2014 dxdy logo

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

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




Начать новую тему Ответить на тему На страницу Пред.  1 ... 3, 4, 5, 6, 7
 
 
Сообщение20.12.2005, 20:20 


13/09/05
153
Москва
Да, про структуры мои замечания - это из области С++. Но остальное все в силе и для С.
А С++ - он с Си имеет много общего, чего не скажешь про Си шарп, который к Си и отнести трудно:)) И на мой взгляд запись С/С++ уместна, выкидываем из С++ понятие класс и еще пару мелочей и получаем Си, так как базовые концепты одни и теже. Но это опять лирика уже пошла.

Подытожив свои замечания, еще скажу - предобъявления, ИМХО, вредная привычка:).

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


17/10/05
3709
VLarin писал(а):
Да, про структуры мои замечания - это из области С++. Но остальное все в силе и для С.
А С++ - он с Си имеет много общего, чего не скажешь про Си шарп, который к Си и отнести трудно:)) И на мой взгляд запись С/С++ уместна, выкидываем из С++ понятие класс и еще пару мелочей и получаем Си, так как базовые концепты одни и теже.


1) Далеко не все остальное.
Код:
for (int k = 0;;) {}

в C синтаксически неверно. Не скомпилируется.
2) C++, действительно, первоначально разрабатывался как надъязык C, чего не скажешь о C#. Я намеренно утрировал свои примеры. Но то что Вы "выкидываете" из С++, чтобы остался С меняет язык принципиально. Вы выплескиваете вместе с водой ребенка. Я не говорю про библиотеки типа iostream или STL, но область жизни переменных, типизация, перегрузка функций / методов / операций, управление памятью, обработка исключительных ситуаций, template'ы наконец - меняют "что такое хорошо и что такое плохо" кардинальным образом. Вы, по-видимому, очень мало писали на С.

Я (как и было сказано), почти всегда согласен с Вашими замечаниями о C++. Но они не переносимы назад в C. Как и программы - Вы сравнительно легко перенесете С программу в С++. Вы не сделаете этого также легко с переносом С++ программы в C.

VLarin писал(а):
Подытожив свои замечания, еще скажу - предобъявления, ИМХО, вредная привычка:).

Я даже не знаю, соглашаться с Вами, или возражать. В С++ описание переменных по мере надобности, вместе с инициализацией является подчас необходимостью. У объекта может просто не быть соответсвуещего коструктора. Вместе с тем, я редко встречал программы, в которых описание переменных в начале ухудшало бы их читаемость. Это особенно относиться не к временным переменным типа счетчика цикла, а к концептуальным. Заметьте, что счетчику цикла и имени обычно не дают - i, j, k - не имена, а так. Когда же описание переменной скрыто невесть где в тексте, читая с произвольного места очень трудно найти концы. Читать же с произвольного места приходиться, ибо не всегда имеешь дело со своей программой (программирование суть коллективный процесс), и надо быстро найти какие-то места. И запускаешь многофайловый поиск, который выбрасывает в произвольном месте файла...

Что касается длинных текстов то это особ. статья. Длинный текст метода / операции / функции как правило (да, я знаю, существуют исключения) говорит о плохой работе над организацией программы. И приводить особенности плохого программирования в качестве обоснования стиля - мне непонятно.

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


17/10/05
3709
:evil:
И еще одно замечание. Описание переменной по мере надобности провоцирует написание программы в стиле "потока сознания". Поток сознания неплохо смотриться в художественной литературе, но в программировании удобнее работать с хорошо организованной программой.

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


28/10/05
1368
Вы тут выясняйте, но я чисто между прочим замечу, что мне нужна программа, написанная на С. (Потом переделаю на С++.) И совсем тИхонько, советы бы тоже желательно к С, а не другим языкам.

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


12/10/05
478
Казань
Тож выскажу свое ИМХО... :)

C++ - совершенно иной язык, это уже не далеко C. В C++ все типы являются классами - для инициализации переменной типа int можно написать

Код:
int i(5);


То же со структурами - в C++ единственное отличие их от классов в том, что у них "по умолчанию" все члены открыты. При желании их можно закрыть.

В обычном C структуры не могут содержать функций-членов!

По-моему это отличие кардинально меняет идеологию программирования. Утешает одно - разница между C и С++ такая же, как м/у английским и китайским - настолько же первый проще второго!

 Профиль  
                  
 
 
Сообщение20.12.2005, 21:26 


13/09/05
153
Москва
To незванный гость:
Да, я действительно мало работал в СИ и могу ошибаться. Но про область жизни переменных - идеалогия С++ таже, что и в Си.

To Sanyok:
В С++ struct == class, а в СИ - это всего лишь структура с полями и ничего более.
Я тут кстати читал книжку Ахо-Сети-Ульмана "Компиляторы: принципы, технологии, инструменты", там в приложении к ней в русском издании есть спецификации С++ и С#.
По ним узнал много нового о языке С++:)).
Запись int i(5) это тоже самое, что int k = 5;
Разбор строки такой - "type id Initializer",
а Initializer - это или "= Expression", или "( Expression )" ;
и для int - это неявный конструктор.

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


17/10/05
3709
:evil:
VLarin писал(а):
Но про область жизни переменных - идеалогия С++ таже, что и в Си.

Это утверждение просто неверно. Смотрите стандарт языка C, 3.6.2
$compound$-$statement: \
\ \ \ \ \ \  \{ declaration$-$list_{opt} \ \ statement$-$list_{opt}\}$

VLarin писал(а):
Я тут кстати читал книжку Ахо-Сети-Ульмана "Компиляторы: принципы, технологии, инструменты", там в приложении к ней в русском издании есть спецификации С++ и С#.
По ним узнал много нового о языке С++:)).

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

 Профиль  
                  
 
 
Сообщение20.12.2005, 22:11 


13/09/05
153
Москва
а вот стандарт 1999 года http://anatolix.naumen.ru/files/books/iso9899.zip. Но суть там таже. И это граматика, области жизни из нее не следует. Она руками делается.

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


17/10/05
3709
:evil:
VLarin писал(а):
а вот стандарт 1999 года

Большое спасибо! Этого стандарта у меня не было. Исключительно интересное чтиво!

VLarin писал(а):
Но суть там таже. И это граматика, области жизни из нее не следует.

Как раз эти места поменялись. Теперь, в С-99, можно смешивать декларации и предложения (6.8.2). Кроме того, они разрешили описание в for (6.8.5). Вопрос только теперь, какой C у компилятора? Раньше были K&R и ANSI С (ANSI X3.159-1989). Теперича добавляется C-99 (ISO:IEC 9899:1999). Дела :!:

 Профиль  
                  
 
 
Сообщение21.12.2005, 12:10 


13/09/05
153
Москва
Тут выяснил для себя, что Вы правы и действительно в старых стандартах нельзя смешивать код и объявления, но в последних это можно, и в for писать объявления тоже можно (6.8.5 - for (declaration expression; .....) ). Так что, я опять за старое - не надо использовать предобъявления:))
Думаю, что эта тема о стандартах Си себя исчерпала:)

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


17/10/05
3709
:evil:
ОК - эта программа реорганизована больше. Выделены три большие секции - матрица (с именем), набор матриц, и пользователский интрефейс. Более или менее ограничен доступ к внутренней структуре. Наверное, правильнее было бы вынуть имя из матрицы, но уж совсем кромсать программу не хотелось. Как рыбе воды, не хватаеат exceptions для обработки ошибок. Тяжко, господа, на C писати. Из-за этого в matrix_read() и размер, и goto. И еще одна хитрость - float Values[0]; в описании матрицы. Во первых, матрица отводиться прямо в структуре. Во вторых, Values[0]; позволяют обращаться к массиву в конце, не отводя памяти. Коли не будет компилироваться, надо ноль на единичку поменять.

Код:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#define FILENAME  "matrizes.dat"

#define MAXNAMESZ  80
#define MAXDIMSZ   40
#define MAXLINESZ 256

#define MAXDIM   100

#define MATRIXLISTSTEP 100

#define MXELEMENT(mx, r, c) ((mx)->Values[(mx)->Cols * (r) + (c)])

#define E_FFORMAT  -16384
#define E_FEOF     -16383


typedef struct marix_type
{
   char*    Name;
   int      Rows;
   int      Cols;
   float    Values[0];
} MATRIX;

typedef struct matrix_list_type
{
   int       Num_matrixes;
   int       Matrixes_size;
   MATRIX**   Matrixes;
} MATRIX_LIST;

/******************************************************************************************
** miscelaneous utilities
******************************************************************************************/

// allocate memory for string and copy it
char* mkstr(const char* s)
{
   char* p;

   p = (char*)malloc(strlen(s)+1);
   if (p == NULL) {
      return "*** error *** not enough memory";
   } else {
      strcpy(p, s);
      return p;
   }
}

// read string form file
int getstr(FILE* f, char* buffer, int buffersz) {
  char dummy[80];
  char* p;

  p = fgets(buffer, buffersz, f);
  if (p == NULL) {
     buffer[0] = 0;
     return -1;
   } else {
     int failed = 0;

     if (buffer[strlen(buffer)-1] == '\n') {
       // delete end-of-line symbol
       buffer[strlen(buffer)-1] = 0;
     } else {
       // flush rest of the line
       while ((p != NULL) && (p[strlen(p)-1] != '\n')) {
         p = fgets(dummy, sizeof(dummy), f);
         failed = 1;
       }
     }
     return (failed? -1: (int)strlen(buffer));
  }
}


/******************************************************************************************
** matrix management
******************************************************************************************/

MATRIX* matrix_create(const char* name, int rows, int cols) {
   MATRIX* matrix;
   size_t mxsize;

   mxsize = sizeof(MATRIX) + sizeof(matrix->Values[0])*(rows*cols);
   matrix = (MATRIX*)malloc(mxsize);
   memset(matrix, 0, mxsize);

   matrix->Name = mkstr(name);
   matrix->Rows = rows;
   matrix->Cols = cols;
   return matrix;
}

void matrix_delete(MATRIX* matrix) {
  free(matrix->Name);
  free(matrix);
}

void matrix_fill_random(MATRIX* matrix) {
   int i, j;

   srand((int)time(NULL));
   for (i=0; i < matrix->Rows; i++) {
      for (j=0; j < matrix->Cols; j++) {
        MXELEMENT(matrix, i, j) = (float)rand() / RAND_MAX;
      }
   }
}

MATRIX* matrix_transpose(MATRIX* matrix, const char* name) {
   MATRIX* trans_matrix;
   int i, j;

   trans_matrix = matrix_create(name, matrix->Cols, matrix->Rows);

   for (i=0; i<trans_matrix->Rows; i++) {
      for(j=0; j<trans_matrix->Cols; j++) {
         MXELEMENT(trans_matrix, i, j) = MXELEMENT(matrix, j, i);
      }
   }
   return trans_matrix;
}

MATRIX* matrix_sum(MATRIX* matrix1, MATRIX* matrix2, const char* name) {
   MATRIX *res_matrix;
   int i, j;

   res_matrix = matrix_create(name, matrix1->Rows, matrix1->Cols);
   for (i=0; i < res_matrix->Rows; i++) {
      for (j=0; j < res_matrix->Cols; j++) {
        MXELEMENT(res_matrix, i, j) = MXELEMENT(matrix1, i, j) + MXELEMENT(matrix2, i, j);
      }
   }
   return res_matrix;
}

void matrix_show(MATRIX* matrix) {
  int i, j;

  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", MXELEMENT(matrix, i, j));
      }
      putchar('\n');
   }
   putchar('\n');
}

int matrix_write(MATRIX* matrix, FILE* f) {
  int i, j;
  int res;

  res = fprintf(f, "%s;%d;%d\n", matrix->Name, matrix->Rows, matrix->Cols);
  if (res < 0) return res;

  for(i=0; i < matrix->Rows; i++) {
      for(j=0; j < matrix->Cols; j++) {
        res = fprintf(f, "%d,%d,%.4f\n", i, j, MXELEMENT(matrix, i, j));
        if (res < 0) return res;
      }
  }
  res = fprintf(f, "\n");
  return res;
}

int matrix_read(MATRIX** pmatrix, FILE*f) {
  MATRIX* matrix = NULL;
  int i, j, ii, jj;
  int rows, cols;
  char line[MAXLINESZ], *ptr, ch1, ch2, ch3;
  float x;
  int res;

  *pmatrix = NULL;
  res = getstr(f, line, sizeof(line));
  if (res == -1) return E_FEOF;
  if (res < 0) goto error;
  ptr = strchr(line, ';');
  if (ptr == NULL) goto format_error;
  *ptr = 0;
  res = sscanf(ptr+1, "%d%c%d%c", &rows, &ch1, &cols, &ch2);
  if ((res != 3) || (ch1 != ';') || (rows < 1) || (rows > MAXDIM) || (cols < 1) || (cols > MAXDIM)) {
    goto format_error;
  }
  matrix = matrix_create(line, rows, cols);
  for(i=0; i < matrix->Rows; i++) {
      for(j=0; j < matrix->Cols; j++) {
        res = getstr(f, line, sizeof(line));
        if (res < 0) goto error;
        res = sscanf(line, "%d%c%d%c%f%c", &ii, &ch1, &jj, &ch2, &x, &ch3);
        if ((res != 5) || (ch1 != ',') || (ch2 != ',') || (ii != i) || (jj != j)) {
          goto format_error;
        }
        MXELEMENT(matrix, i, j) = x;
      }
  }
  res = getstr(f, line, sizeof(line));
  if (res != 0) goto format_error;
  *pmatrix = matrix;
  return 0;

// error processing

format_error:
  res = E_FFORMAT;
  // intentional fall-through

error:
  if (matrix) {
    matrix_delete(matrix);
  }
  return res;
}


/******************************************************************************************
** matrix list management
******************************************************************************************/

void ml_init(MATRIX_LIST* matrix_list) {
   matrix_list->Num_matrixes = 0;
   matrix_list->Matrixes_size = 0;
   matrix_list->Matrixes = NULL;
}

void ml_free(MATRIX_LIST* matrix_list) {
  int ix;

  for (ix = 0; ix < matrix_list->Num_matrixes; ++ix) {
    matrix_delete(matrix_list->Matrixes[ix]);
  }
  free(matrix_list->Matrixes);
}

void ml_check_spot(MATRIX_LIST* matrix_list) {
  if (matrix_list->Num_matrixes >= matrix_list->Matrixes_size) {
      matrix_list->Matrixes_size += MATRIXLISTSTEP;
      matrix_list->Matrixes =
         (MATRIX**)realloc(matrix_list->Matrixes, (matrix_list->Matrixes_size) * sizeof(matrix_list->Matrixes[0]));
  }
}

void ml_add(MATRIX_LIST* matrix_list, MATRIX* matrix) {
   ml_check_spot(matrix_list);
   matrix_list->Matrixes[matrix_list->Num_matrixes] = matrix;
   ++matrix_list->Num_matrixes;
}

void ml_del(MATRIX_LIST* matrix_list, MATRIX* matrix) {
  int ix;

  for (ix = 0; ix < matrix_list->Num_matrixes; ++ix) {
    if (matrix_list->Matrixes[ix] == matrix) break;
  }
  if (ix >= matrix_list->Num_matrixes) {
    printf("something wrong in program - matrix to remove not found\n");
  } else {
    for ( ; ix < matrix_list->Num_matrixes - 1; ++ix) {
      matrix_list->Matrixes[ix] = matrix_list->Matrixes[ix+1];
    };
    --matrix_list->Num_matrixes;
  }
}

MATRIX* ml_find(MATRIX_LIST* matrix_list, const char* name) {
  int ix;

  for (ix = 0; ix < matrix_list->Num_matrixes; ++ix) {
    if (strcmp(matrix_list->Matrixes[ix]->Name, name) == 0) {
      return matrix_list->Matrixes[ix];
    }
  }
  return NULL;
}

int ml_is_empty(MATRIX_LIST* matrix_list) {
   return (matrix_list->Num_matrixes == 0);
}

void ml_show(MATRIX_LIST* matrix_list) {
  int i;

  if (ml_is_empty(matrix_list)) {
      puts("List of matrixes is empty!");
  } else {
    for(i=0; i<matrix_list->Num_matrixes; i++) {
      printf("%s (%d x %d)\n", matrix_list->Matrixes[i]->Name,
         matrix_list->Matrixes[i]->Rows, matrix_list->Matrixes[i]->Cols);
    }
  }
}

int ml_write(MATRIX_LIST* matrix_list, FILE* f) {
   int k;
   int res = 0;

   for(k=0; k<matrix_list->Num_matrixes; k++)
   {
      res = matrix_write(matrix_list->Matrixes[k], f);
      if (res < 0) break;
   }
   return res;
}

int ml_read(MATRIX_LIST* matrix_list, FILE* f) {
   int res = 0;
   MATRIX* matrix;

   while (!feof(f)) {
     res = matrix_read(&matrix, f);
     if (res < 0) break;
     ml_add(matrix_list, matrix);
   }
   return res;
}

/******************************************************************************************
** user interface
******************************************************************************************/

int getname(char* prompt, char* buffer, int buffsize) {
   int res;

   printf("enter the %s:\n> ", prompt);
   res = getstr(stdin, buffer, buffsize);
   if (res < 0) {
      printf("name is too long...\n");
   }
   return res;
}

int ui_check_empty(MATRIX_LIST* matrix_list) {
  if (ml_is_empty(matrix_list)) {
    printf("no variables defined\n");
    return 1;
  } else {
    return 0;
  }
}

void ui_new_matrix(MATRIX_LIST* matrix_list)
{
   char name[MAXNAMESZ], dimensions[MAXDIMSZ];
   int res;
   MATRIX* matrix;

   char ch1 = 0, ch2 = 0;
   int rows = -1, cols = -1;

   printf("What are the dimensions of the matrix?\n(number of lines and columns separated by space, in range 1..%d)\n> ", MAXDIM);
   res = getstr(stdin, dimensions, sizeof(dimensions));
   if (res < 0) {
      printf("dimensions are too long...\n");
      return;
   }
   res = sscanf(dimensions, "%d%c%d%c", &rows, &ch1, &cols, &ch2);
   if ((res != 3) || (ch1 != ' ') || (rows < 1) || (rows > MAXDIM) || (cols < 1) || (cols > MAXDIM)) {
      puts("Wrong dimensions!");
      return;
   }

   if (getname("variable name", name, sizeof(name)) < 0) return;
   if (ml_find(matrix_list, name))
   {
      puts("This name is already in used!");
      return;
   }

   matrix = matrix_create(name, rows, cols);
   matrix_fill_random(matrix);
   ml_add(matrix_list, matrix);
}


void ui_delete_matrix(MATRIX_LIST* matrix_list)
{
   char name[MAXNAMESZ];
   MATRIX* matrix;

   if (ui_check_empty(matrix_list)) return;

   if (getname("variable name", name, sizeof(name)) < 0) return;

   matrix = ml_find(matrix_list, name);
   if (!matrix) {
      puts("Variable not found!");
      return;
   }

   printf("remove var: %s(%dx%d)\n", matrix->Name, matrix->Rows, matrix->Cols);

   ml_del(matrix_list, matrix);
   matrix_delete(matrix);
}


void ui_transpose_matrix(MATRIX_LIST* matrix_list)
{
   char name[MAXNAMESZ];
   MATRIX *matrix, *trans_matrix;

   if (ui_check_empty(matrix_list)) return;

   if (getname("variable name", name, sizeof(name)) < 0) return;

   matrix = ml_find(matrix_list, name);
   if (!matrix)
   {
      puts("Variable not found!");
      return;
   }


   if (getname("variable name for transposed matrix", name, sizeof(name)) < 0) return;
   if (ml_find(matrix_list, name))
   {
      puts("This name is already in use!");
      return;
   }

   trans_matrix = matrix_transpose(matrix, name);
   ml_add(matrix_list, trans_matrix);
}


void ui_sum_matrixes(MATRIX_LIST* matrix_list)
{
   char name[MAXNAMESZ];
   MATRIX *matrix1, *matrix2, *res_matrix;

   if (ui_check_empty(matrix_list)) return;

   if (getname("variable name (1st operand)", name, sizeof(name)) < 0) return;
   matrix1 = ml_find(matrix_list, name);
   if (!matrix1)
   {
      puts("Variable not found!");
      return;
   }

   if (getname("variable name (2nd operand)", name, sizeof(name)) < 0) return;
   matrix2 = ml_find(matrix_list, name);
   if (!matrix2)
   {
      puts("Variable not found!");
      return;
   }

   if ((matrix1->Rows != matrix2->Rows) || (matrix1->Cols != matrix2->Cols))
   {
      puts("Matrixes have different dimensions!");
      return;
   }


   if (getname("variable name for sum", name, sizeof(name)) < 0) return;
   if (ml_find(matrix_list, name))
   {
      puts("This name is already in use!");
      return;
   }

   res_matrix = matrix_sum(matrix1, matrix2, name);
   ml_add(matrix_list, res_matrix);
}

void ui_show_matrix(MATRIX_LIST* matrix_list)
{
   char name[MAXNAMESZ];
   MATRIX* matrix;

   if (ui_check_empty(matrix_list)) return;

   if (getname("variable name", name, sizeof(name)) < 0) return;

   matrix = ml_find(matrix_list, name);
   if (!matrix) {
      puts("Variable not found!");
      return;
   }
   matrix_show(matrix);
}

void ui_write_to_file(char* filename, MATRIX_LIST* matrix_list)
{
   FILE* f;
   int res;

   f = fopen(filename, "w");
   res = ml_write(matrix_list, f);
   if (res < 0) {
     printf("io errors detected writing to the file.\nSome information may be lost\n");
   }
   fclose(f);
}

void ui_read_from_file(char* filename, MATRIX_LIST* matrix_list)
{
   FILE* f;
   int res;

   f = fopen(filename, "r");
   if (!f) {
      printf("file <%s> not found\n", filename);
      return;
   }
   res = ml_read(matrix_list, f);
   if (res == E_FFORMAT) {
     printf("file format errors detected reading from the file.\nSome information may be lost\n");
   } else if (res != E_FEOF) {
     printf("io errors detected reading from the file.\nSome information may be lost\n");
   }
   fclose(f);
}

int main()
{
   MATRIX_LIST matrix_list;
   int choice;
   char str[5];

   ml_init(&matrix_list);

   puts("$ matprog");

   ui_read_from_file(FILENAME, &matrix_list);
   ml_show(&matrix_list);

   for (;;)
   {
      puts("\nShow matixes..................1");
      puts("Show matrix...................2");
      puts("Remove matrix.................3");
      puts("New arbitrary matrix..........4");
      puts("Transponse....................5");
      puts("Sum...........................6");
      puts("Exit..........................x");
      putchar('>');
      getstr(stdin, str, sizeof(str));

      if ((str[0] == 'x') || (str[0] == 'X'))
         break;

      choice = atoi(str);

      switch (choice)
      {
         case 1: {
              ml_show(&matrix_list);
            } break;
         case 2: {
              ui_show_matrix(&matrix_list);
            } break;
         case 3: {
              ui_delete_matrix(&matrix_list);
            } break;
         case 4: {
              ui_new_matrix(&matrix_list);
            } break;
         case 5: {
              ui_transpose_matrix(&matrix_list);
            } break;
         case 6: {
              ui_sum_matrixes(&matrix_list);
            } break;
         default: {
              puts("Wrong choice!");
            } break;
      }
   }
   ui_write_to_file(FILENAME, &matrix_list);

   ml_free(&matrix_list);

   return 0;
}



 Профиль  
                  
 
 
Сообщение22.12.2005, 13:53 


13/09/05
153
Москва
To незванный гость:
Два вопроса по программе -
1. Зачем Вы используете goto, когда там на условных переходах можно все сделать?:)
2. И зачем в switch используете фигурные скобки -
Код:
switch (choice)
      {
         case 1: {
              ml_show(&matrix_list);
            } break;
         case 2: {
............

когда можно просто
Код:
switch (choice)
{
case 1:
         ml_show(&matrix_list);
         break;
case 2:
............

Скобки нужны, если нам нужно объявление в теле swicth сделать, а так они только загромаждают код.

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


17/10/05
3709
:evil:
VLarin писал(а):
1. Зачем Вы используете goto, когда там на условных переходах можно все сделать?:)

Можно. Существует конструктивное доказательство того, что любую программу можно переписать без goto. Оно (доказательство) оставляет без ответа вопрос, можно ли прочитать такую переписанную программму.

Более конкретно. goto использовано для весьма специфической цели - обработки исключительной ситуации. В С нет exception. И это очень мешает. Принципиально, можно было бы сделать локальные return в условных операторах. Но тогда нет гарантии правилього восстановления после exception (например, освобождения ресурсов). Его бы пришлось выписывать несколько раз (столько, сколько потенциальных raise), и при модификации легко потерять где-то в программе. Кроме того, теряется логика программы. У меня же всё на виду: - goto == raise, метка == except.

VLarin писал(а):
2. И зачем в switch используете фигурные скобки [...] Скобки нужны, если нам нужно объявление в теле swicth сделать, а так они только загромаждают код.

Я принадлежу к другой школе в программировании, идущей от Алгола-68. Одна из проблем С и иже с ним (C++, Java, C#) состоит в весьма архаичной (c 1958 года по крайней мере - Алгол-60) концепции "операторности" предложений (a la набла). То есть после for, if, switch,... идет ровно одно предложение. Нужно больше - делай из группы предложений блок.

Сей подход, на мой взгляд, доказал свою непродуктивность (в 1976 - по крайней мере, это уже было в Алголе-68. В Паскаль не вошло, но уже 1980 Вирт включил в Модулу-2. Дошло даже до Visual Basic'а) и разумность рамочной структуры предложений. Причин много. Одна состоит в том, что при модификации легко потерять пропущенные скобки, и вместо двух операторов будет выполнен один. Я как-то потерял do в таком коде:
Код:
{
  s1;
}
while (...);
и теперь пишу только так:
Код:
do {
  s1;
} while (...);
Скобки задают визуальные ориентиры границ оператора (чем-то вроде засечек на концах штриха в шрифте) и освобождают мозги читателя для более продуктивной работы. Вы можете заметить, что за весьма редким исключением я ставлю скобки и в if,... там, где они синтаксически не нужны. Исключение составляет короткий if с оператором управления: return, break, continue, goto.

Вторая причина состоит в придании некоторой структуры аморфному switch (не задаваемой языком). В этом смысле
Код:
case ...: {
  s1;
  s2;
} break;
выглядит как, например, оператор цикла выше. Скобки подчеркивают секцию case - break, обращают внимание, что break не есть часть исполняемого кода, а суть часть switch'а. Опять же усиливается видимость программы - в исходной программе, например, break был пропущен в default.

Вы могли заметить также, что я принижаю сами скобки, и не выделяю их. Я последовательно пишу везде
Код:
if (..) {
  ...
} else if (...) {
  ...
} else {
  ...
}
поскольку рассматриваю скобки как синтаксический мусор, при последовательном использовании не несущий семантической нагрузки. То есть они нужны только, чтобы скомпенсировать дефект языка.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Классическим примером худшего в С (и С++, коли не исключено последним стандартом) является Duff's Device:
Код:
void send(volatile short *to, short* from, int count)
{
   register n=(count+7)/8;
   switch(count%8){
   case 0:   do{   *to = *from++;
   case 7:      *to = *from++;
   case 6:      *to = *from++;
   case 5:      *to = *from++;
   case 4:      *to = *from++;
   case 3:      *to = *from++;
   case 2:      *to = *from++;
   case 1:      *to = *from++;
      }while(--n>0);
   }
}
(я слегка осовременил синтаксис) Это - законно, это работает. Но нравится ли?

 Профиль  
                  
 
 
Сообщение22.12.2005, 20:03 


27/11/05
183
Северодонецк
to незванный гость:

Насчет лишних {} в контексте case я полностью согласен с Vlarin. Такие же излишества
просматриваются и в вашем стиле if((a==0) || (b==0)), которое идет от Паскаля. Гораздо
прозрачнее виден оператор if(a==0 || b==0). И такие скобки нельзя оправдать даже
не совсем удачным выбором, например, приоритета операции '==' в языке C, когда
в операторе типа if((a & 3) == 0) действительно скобки нужны, так как без них
оператор if(a & 3 == 0) эквивалентен if(a & (3 == 0)). Но таких тонкостей в языке C
еще раз-два и обчелся. Этот стиль (с лишними символами) написания программы можно
охарактеризовать как "обжегшись на молоке, дует на воду"...

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


17/10/05
3709
:evil:
bekas писал(а):
Насчет лишних {} в контексте case я полностью согласен с Vlarin.

Я же не возвражаю. Я обосновываю мои решения (стиль), а Вы делаете свой выбор. И надеюсь, что Ваш выбор будет еще более ясным и обоснованным после этой дискурсии. Я же обычно просто следую стилю той группы, в которой работаю, или той программы, которую правлю. Единообразие стиля для меня гораздо важнее, чем то или иное предпочтение.

bekas писал(а):
которое идет от Паскаля. Гораздо прозрачнее виден оператор if(a==0 || b==0). И такие скобки нельзя оправдать даже не совсем удачным выбором, например, приоритета операции '==' в языке C, когда в операторе типа if((a & 3) == 0) действительно скобки нужны, так как без них оператор if(a & 3 == 0) эквивалентен if(a & (3 == 0)).

Эк у Вас Паскаль словом бранным выходит :D. Уж не прозелит ли Вы? :D Так в Паскале та же проблема - один оператор после if/for. Давайте уж не начинать священные войны о языках программирования. Дали задание на С - и все, никаких Пасквилей. А скажут на С obtuse - никаких Жаб.

Если честно, я просто не задумывался, и следовал уже написанной программе. Вы правы, скобки здесь излишни, и я обычно их не ставлю. Тем не менее я сознательно ставлю избыточные скобки в двух случаях: смешанное || && (& |) выражение и ?: операция. В первом случае - потому, что несмотря на задание языком явного порядка исполнения операций, в культуре (математической) этого порядка нет, и посему кроме экспертов всяк споткнется на порядке вычисления выражений типа a || b && c || d && e || f. Во втором - потому что хочу подчеркнуть замкнутость тринарной формы, весьма неочевидную (не случайно эту полезную конструкцию многие избегают).

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

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



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

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


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

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