2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1 ... 3, 4, 5, 6, 7  След.
 
 
Сообщение19.12.2005, 21:19 
Заслуженный участник
Аватара пользователя


12/10/05
478
Казань
Для закрытия файла надо вызывать fclose() (а не close, как у Вас), если для открытия вызываешь fopen(). Хотя как показала практика (на моем компе, по крайней мере, и для небольших файлов) - один черт. Чего я, кстати, не понимаю... :)

 Профиль  
                  
 
 
Сообщение19.12.2005, 21:31 
Заслуженный участник
Аватара пользователя


12/10/05
478
Казань
Более того, когда я совсем убрал (заремил) функцию закрытия файла, все осталось как прежде. Вероятно, при завершении программы все использовавшиеся ей потоки закрываются автоматически - если это так, то спасибо операционной системе! :)

 Профиль  
                  
 
 
Сообщение19.12.2005, 21:32 
Заслуженный участник


28/10/05
1368
Уже поменяла в самой программе, как Вы сказали.
Не знаю, у меня работало..
Такому специалисту как я, Ваши эксперименты надо было пояснить...

 Профиль  
                  
 
 
Сообщение19.12.2005, 21:59 


13/09/05
153
Москва
Вы просили замечания:)
1. Писать для определения структуры
Код:
.......
typedef struct marix_type
{
   char*   Name;
   int      Rows;
   int      Cols;
   float*   Values;
} MATRIX;
.......

ИМХО крайне не правильно. Такая запись обычно используется в купе с
Код:
} MATRIX, FAR *LPMATRIX;// - и здесь можно еще что-нить добавить,

и там она имеет смысл - мы определяем структуру marix_type, и для удобства две новых фичи - это тип и указатель на тип (MATRIX и LPMATRIX), которые на самом деле есть marix_type и marix_type*. Я очень часто так и делаю. Таким образом у нас есть MATRIX, и marix_type. И если не нужно FAR *LPMATRIX и прочей ерунды, то можно написать просто:
Код:
.......
struct MATRIX
{
   char*   Name;
   int      Rows;
   int      Cols;
   float*   Values;
};
.......


2. ИМХО, типичным признаком перехода от языков типа Паскаль к С/С++ является использование предобъявлений. В Паскале, на сколько я знаю, это было вызвано кривостью принципов, заложенных в компилятор. В С/С++ этого делать не обязательно и даже, я бы сказал, ни в коем случае не рекомендуется, так как это ухудшает читаемость кода и прочее. Переменную надо объявлять именно там, где она нужна.
Код:
   MATRIX* matrix;
   matrix = (MATRIX*)malloc(sizeof(MATRIX)); //   Зачем так сложно?
...............
//   Когда можно проще и нагляднее -
   MATRIX* matrix = (MATRIX*)malloc(sizeof(MATRIX));
//   При этом в первом случае выполняется инцилизация переменной, а затем ее использование, а во втором - только инициализация (см. описание С/С++).
...............
//   А вот это
void show_matrix(MATRIX_LIST* matrix_list)
{
   char name[10];
   MATRIX* matrix;
   int i, j;
   printf("indicate the name of variable:\n> ");
   gets(name);
   matrix = search_matrix(matrix_list, name);
   if (!matrix)
   {
      puts("Variable not found!");
      return;
   }
   printf("%s:\n", matrix->Name);
   printf("%d x %d\n", matrix->Rows, matrix->Cols);
   for(i=0; i<matrix->Rows; i++)
   {
      for(j=0; j<matrix->Cols; j++)
         printf("   %.4f", matrix->Values[i * matrix->Cols + j]);
      putchar('\n');
   }
}
............
//   можно свести к следующему
void show_matrix(MATRIX_LIST* matrix_list)
{
   printf("indicate the name of variable:\n> ");
   char name[10];
   gets(name);
   MATRIX* matrix = search_matrix(matrix_list, name);
   if (!matrix)
   {
      puts("Variable not found!");
      return;
   }
   printf("%s:\n", matrix->Name);
   printf("%d x %d\n", matrix->Rows, matrix->Cols);
   for(int i=0; i<matrix->Rows; i++)
   {
      for(int j=0; j<matrix->Cols; j++)
         printf("   %.4f", matrix->Values[i * matrix->Cols + j]);
      putchar('\n');
   }
}

Но это так, лирика.

3. Если вы делаете динамическое добавление/удаление - то почему бы не сделать связанный список для хранения матриц. Тогда не прийдется постоянно память выделять/удалять, а просто удаляем/добавляем что-то и переписываем связи.
Код:
typedef struct tagMATRIX_LIST_ITEM
{
   tagMATRIX_LIST_ITEM* m_pPrevItem;
   tagMATRIX_LIST_ITEM* m_pNextItem;
   LPMATRIX m_pMatrix;
} MATRIX_LIST_ITEM, FAR *LPMATRIX_LIST_ITEM;

struct MATRIX_LIST
{
   int m_nItemCount;
   LPMATRIX_LIST_ITEM m_pHeadItem;
   LPMATRIX_LIST_ITEM m_pTailItem;
};

и к этому правда нужно добавить функции работы со списком, типа AddTail/AddHead, RemoveTail/RemoveHead, GetAt/SetAt, RemoveAll, GetCount и т.д.
Код:
LPMATRIX_LIST_ITEM AddHead(MATRIX_LIST* list, LPMATRIX matrix)
{
   list->m_nItemCount++;
   LPMATRIX_LIST_ITEM new_item = new MATRIX_LIST;
   new_item->m_pPrevItem = NULL;
   new_item->m_pNextItem = list->m_pHeadItem;
   new_item->m_pMatrix = matrix;
   list->m_pHeadItem->m_pPrevItem = new_item;
   list->m_pHeadItem = new_item;
   return new_item;
}

bool RemoveHead(MATRIX_LIST* list)
{
   if (!list->m_nItemCount)
      return false;
   list->m_nItemCount--;
   LPMATRIX_LIST_ITEM old_item = list->m_pHeadItem;
   list->m_pHeadItem = old_item->m_pNextItem;
   if (list->m_pHeadItem)
      list->m_pHeadItem->m_pPrevItem = NULL;
   delete old_item;
   return true;
}

int GetCount(MATRIX_LIST* list)
{
   return list->m_nItemCount;
}

и т.д.

 Профиль  
                  
 
 
Сообщение19.12.2005, 22:54 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
Уважаемый VLarin, r сожалению, Ваши замечания относятся больше к C++, чем к C.
В С:

1. запись
Код:
struct Т {
  int x;
};

если и законна, то весьма мало распространена - она определяет структуру, которую можно использовать в дальнейшем только как
Код:
struct T x;
void foo(struct T * y)
Поэтому многие предпочитают форму
Код:
typedef struct {
  int x;
} T;

которая определяет тип использование которого идет на общих основаниях. Обратите внимание, что я вообще не задаю тег структуры - это допустимо в стандартном C (но не в K&R С). Ловушкой является текст
Код:
struct Т {
  int x;
} y, *z;

который определяет тег структуры T и две переменных - структуру y и указатель на структуру z, а не два типа, как можно было бы подумать.

2. В блоке сначала идут все определения, потом все операторы. Смешивать порядок нельзя. Это не имеет большого значения, поскольку нет конструкторов / деструкторов, и, таким образом, время жизни все равно весь блок. (Простите, но в данном случае я не поленился проверить стандарт языка C.)

 Профиль  
                  
 
 
Сообщение19.12.2005, 23:02 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
Sanyok писал(а):
Для закрытия файла надо вызывать fclose() (а не close, как у Вас), если для открытия вызываешь fopen(). Хотя как показала практика (на моем компе, по крайней мере, и для небольших файлов) - один черт. Чего я, кстати, не понимаю... :)

Вы просто не проверяете результат close(). Вопреки распространенному мнению, и close(), и fclose() возвращают результат, который следует проверять, хотя бы для обнаружения вышеупомянутых ошибок. Файлы закрываются автоматически при окончании процесса, но:
1) У Вас может наступить исчерпание ресурсов системы.
2) Если Вы пишете в файл (особенно fwrite() - буфферизованная запись) Вы рискуете потерять конец файла. Особенно, если Ваша программа закончилась аварийно.
3) Незакрытый файл может быть (весьма необоснованно) недоступен другим программам.

 Профиль  
                  
 
 
Сообщение19.12.2005, 23:03 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
Sanyok писал(а):
если это так, то спасибо операционной системе! :)

Больше run-time библиотеке. Хотя OS тоже лепту вносит.

 Профиль  
                  
 
 
Сообщение19.12.2005, 23:15 
Заслуженный участник
Аватара пользователя


12/10/05
478
Казань
Еще я бы посоветовал LynxGAV использовать для ввода строки ту же процедуру, что и в первой программе, или сделать хотя бы буфер побольше. 10 символов для имени матрицы - маловато как-то.

 Профиль  
                  
 
 
Сообщение20.12.2005, 00:07 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
Sanyok писал(а):
Еще я бы посоветовал LynxGAV использовать для ввода строки ту же процедуру, что и в первой программе, или сделать хотя бы буфер побольше. 10 символов для имени матрицы - маловато как-то.

Присоединяюсь. Не говоря уж об экономии усилий - чего второй-то раз писать написанное.

Задача: вкипятиnm чайник. Физик, математик и программист решают одинаково - наливают воду в чайник и ставят его на огонь. Следующая задача - вскипятить полный чайник. Физик - ставит на огонь. Математик - выливает воду из чайника и возращается к ранее рассмотренной задаче. Программист - выделяет постановку на огонь в отдельную функцию, которую он будет теперь везде вызывать.

 Профиль  
                  
 
 
Сообщение20.12.2005, 00:16 
Заслуженный участник


28/10/05
1368
"Программируя", я не думаю о том, что мне где-то это сможет пригодиться еще. Я не пишу заготовок. Поэтому: :oops:.

 Профиль  
                  
 
 
Сообщение20.12.2005, 00:50 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
LynxGAV писал(а):
"Программируя", я не думаю о том, что мне где-то это сможет пригодиться еще. Я не пишу заготовок.

Никто не пишет. "Программист - выделяет постановку на огонь в отдельную функцию, которую он будет теперь везде вызывать."

 Профиль  
                  
 
 
Сообщение20.12.2005, 00:57 
Заслуженный участник


28/10/05
1368
Да, понятно.

 Профиль  
                  
 
 
Сообщение20.12.2005, 00:59 


27/11/05
183
Северодонецк
------LynxGAV

choice = atoi(str);

switch (choice)

-------bekas

Спрашивается, зачем использовать посредник 'choice', когда
далее он не используется (даже для печати по default о том,
что ввели неправильное число)?

switch (atoi(str))

Если же необходима печать об ошибке 'choice', опять же можно

switch (choice = atoi(str))
{
...

default:
printf("Wrong choice %d!\n", choice);
}

А такая печать необходима, если вы попадали в ситуацию, когда, например,
чужая программа печатает сообщение "Файл не найден" и не сообщает,
какой именно, тем более, если программа работает с несколькими файлами.

------LynxGAV
printf("%s:\n", matrix->Name);
printf("%d x %d\n", matrix->Rows, matrix->Cols);

-------bekas (оптимизация)
printf("%s:\n%d x %d\n", matrix->Name, matrix->Rows, matrix->Cols);

------LynxGAV
for(i=0; i<matrix->Rows; i++)
{
for(j=0; j<matrix->Cols; j++)
printf(" %.4f", matrix->Values[i * matrix->Cols + j]);
putchar('\n');
}

-------bekas (оптимизация)
for(i=0; i<matrix->Rows; i++)
{
work = i * matrix->Cols;
for(j=0; j<matrix->Cols; j++)
printf(" %.4f", matrix->Values[work + j]);
putchar('\n');
}

------LynxGAV
gets(dimensions);
ptr = strchr(dimensions, ' ');
if (!ptr)
{
puts("Wrong dimensions!");
return;
}
ptr++;
rows = atoi(dimensions);
cols = atoi(ptr);
if ((rows < 1) || (cols < 1))
{
puts("Wrong dimensions!");
return;
}

-------bekas (упрощение)

gets(dimensions);
if(sscanf(dimensions, "%d %d", &rows, &cols) != 2 || rows < 1 || cols < 1)
{
puts("Wrong dimensions!");
return;
}

------LynxGAV

for(i=0; i<rows; i++)
for(j=0; j<cols; j++)
{
ptr = strchr(ptr1, ';');
if (!ptr)
continue;
matrix->Values[i * cols + j] = atof(ptr1);
ptr1 = ptr + 1;
}

-------bekas

Достаточно здесь иметь ситуацию, когда нет ни одного символа ';'
(или их менее rows * cols), и мы будем иметь ситуацию с мусорными
данными в matrix->Values[]. Это связано с тем, что new_matrix()
выделяет память под массив, но не инициализирует его начальными
значениями, поэтому в new_matrix() необходимо выполнить хотя бы

matrix->Values = (float*)malloc(rows * cols * sizeof(float));
memset(matrix->Values, 0, rows * cols * sizeof(float));

И вообще, если преподаватель потребует контроль ввода данных,
то программу придется переделать

 Профиль  
                  
 
 
Сообщение20.12.2005, 19:54 


13/09/05
153
Москва
To незванный гость:
Да, замечания больше относятся к С++, в котором struct == class и можно приписать структуре member-функции. Поэтому запись
Код:
struct Т {
  int x;
};

вполне законна и правильна. И поэтому можно писать
Код:
struct T x;
void foo(struct T * y)

а можно и просто
Код:
T x;
void foo(T* y)


Текст
Код:
typedef struct Т {
  int x;
} y, *z;

на самом деле эквивалентен
Код:
struct Т {
  int x;
};
typedef struct Т y, *z;

Т.е. мы сначала определяем структуру, а затем два собственных типа - это y (== T) и z (== T*). Разбор строки такой получачается. И тоже самое для
Код:
typedef struct {
  int x;
} T;

- где мы сначала определяем безымянную TEMP-структуру, а потом говорим, что T - это она самая. Кроме того, попробуйте с помошью последней записи сделать список с перекрестными ссылками - ничего не выйдет, так как имя структуры T не определено в момент разбора структуры компилятором и нужен тег.
Код:
typedef struct {
  int x;
  T* p;
} T;

Это я по поводу записи без тега.

А по поводу предобъявлений - если код большой, и/или переменная нужна только во вложенном блоке, то ее нужно объявлять там, где она нужна. Переменная живет только в блоке и возможно ее повторное использование в другом блоке. А самое главное - это исключает ошибки с инициализацией. Если мы используем одну глобальную по отношению к нескольким блокам переменную, а в каждом блоке нужны свои значения, то пропуск инициализации перед некоторым блоком может привести к ошибке и это является одним из часто встречающихся багов.
А так - нужна нам переменная внутри блока - создаем ее именно там, где она впервые понадобилась, что значительно повышает читаемость. Так как в противном случае Вам нужно смотреть в начале функции, какие имена уже были использованы и какой тип.
ИМХО, предобъявление - это беда старых языков и от нее нужно отказываться.

Просто зачем в С/С++ писать
Код:
int i, j, k;
.............
for (i = 0; i < 10; i++)
{
     for (j = 0; j < 10; j++)
     {
          .....
          k = i*j;
          .....
     }
}

Когда можно проще и нагляднее -
Код:
for (int i = 0; i < 10; i++)
{
     for (int j = 0; j < 10; j++)
     {
          .....
          int k = i*j;
          .....
     }
}

Переменная k видна только во вложенном блоке и зачем про нее знать всей функции.

 Профиль  
                  
 
 
Сообщение20.12.2005, 20:08 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
Я (почти всегда) согласен с Вами, коли мы согласимся на C++.

С и С++ - два разных языка. Для меня Ваше обозначение C/C++ почти также режет глаз, как C/C#, Pascal/Oberon, или латинский/португальский. Что-то общее есть, но языки разные и практика программирования весьма различна. Quod licet C++ non licet C.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 105 ]  На страницу Пред.  1 ... 3, 4, 5, 6, 7  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group