2014-11-02 3 views
0

Я смотрел на другие ответы подобной природы, но все же сталкивался с проблемами.Как изменить размер массива целых чисел?

Я новичок в C и вам нужен совет.

Соответствующие части кода:

int readNumbers(int **array, char* fname, int hexFlag) { 

    int numberRead = 0; 
    FILE* fp; 
    int counter = 0; 
    char arr[100]; 
    char* ptr; 

    array = malloc(0 * sizeof(*array)); //Problematic area. Should I initially give it space? 



    fp = fopen(fname, "r"); 

    if (fp == NULL) { 
      printf("Error opening file\n"); 
      return -1; 
    } 

    while (fgets(arr, sizeof(arr), fp)) { 
      ptr = strtok(arr, " \n"); 
      while(ptr) { 
       if (hexFlag == 0) { 
         array = realloc(array, (counter + 1) * sizeof(int*)); 
         array[counter++] = strtol(ptr , NULL , 10); //Seg Faulting 
       } else { 
         array = realloc(array, (counter + 1) * sizeof(int*)); 
         array[counter++] = strtol(ptr, NULL, 16); 
       } 
       ++numberRead; 
       ptr = strtok(NULL , " \n"); 
    } 

} 

Я отлажена это и кажется, что массив никогда не получает память, выделенную для него. Кроме того, сбой программы seg сразу после попытки доступа к массиву array[counter++];

Я также обнаружил, что это плохая практика повторного использования после каждого приращения, но я не знаю, что еще делать.

+0

Здравствуйте, я остановился C несколько лет назад, но эта строка: массив = таНос (0 * SizeOf (* массив)); всегда будет выделять байты PointerSize. Ваш массив на самом деле указывает на указатели, поэтому * array - это просто указатель. Edit, btw: 0 * XX = 0, поэтому вы не выделяете какую-либо память – Jurion

+0

Прочтите этот вопрос http://stackoverflow.com/questions/2937409/resizing-an-array-with-c! – Blackhat002

+0

@ Blackhat002 Привет, я довольно подробно рассмотрел этот вопрос. Однако я, вероятно, пропустил важную деталь. Я пробовал всевозможные способы, но они либо имеют неверный указатель, либо ошибку сегментации. – Ansdai

ответ

1

Неправильная практика: realloc каждый раз через петлю. Лучше расти в больших блоках по мере необходимости.

Кроме того, вы неправильно распределяете массив. array - это указатель на целочисленный массив, вам нужно косвенным путем установить указатель вызывающего.

*array = malloc(size * sizeof(**array)); 

Так что ваша функция должна выглядеть так:

int readNumbers(int **array, char* fname, int hexFlag) { 

    int numberRead = 0; 
    FILE* fp; 
    int counter = 0; 
    char arr[100]; 
    char* ptr; 
    size_t curSize = 16; 
    int radix = hexFlag ? 16 : 10; 

    *array = malloc(curSize * sizeof(**array)); 

    fp = fopen(fname, "r"); 

    if (fp == NULL) { 
     printf("Error opening file\n"); 
     return -1; 
    } 

    while (fgets(arr, sizeof(arr), fp)) { 
     ptr = strtok(arr, " \n"); 
     while(ptr) { 
      if (counter >= curSize) { 
       curSize += 16; 
       *array = realloc(*array, curSize * sizeof(**array)); 
      } 
      (*array)[counter++] = strtol(ptr , NULL , radix); 
      ++numberRead; 
      ptr = strtok(NULL , " \n"); 
     } 

    } 
} 
+0

Здравствуйте, спасибо и Джонатан, я понимаю это лучше сейчас. Однако это одна из проблем с реализацией выше, когда входные данные заканчиваются в конце файла, произойдет ошибка сегментации для по какой-то причине. – Ansdai

+0

Я не уверен, почему. Когда он доходит до конца файла, 'fgets()' должен возвращать 'NULL', а цикл' while' заканчивается. Думаю, вам нужно запустить его в отладчике, чтобы увидеть где он попадает на линию, которая вызывает segfault. – Barmar

+0

Я понял это. Это произошло потому, что вместо curSize в malloc я случайно поставил 0. Но я не понимаю, почему это приведет к сбою fgets. – Ansdai

1

Правило большого пальца состоит в том, чтобы выделить небольшое начальное распределение и удвоить выделенный размер, когда требуется больше места. Вы должны отслеживать два размера - размер и размер. Вы можете сделать все это с realloc(), хотя, пожалуй, более обычным является использование malloc(), а затем realloc().

size_t n_alloc = 1; 
size_t n_used = 0; 
int *data = malloc(n_alloc * sizeof(*arr)); 

if (arr == 0) 
    …report out of memory and return… 
int base = (hexFlag == 0) ? 10 : 16; 

while (fgets(arr, sizeof(arr), fp)) 
{ 
    ptr = strtok(arr, " \n"); 
    while (ptr) 
    { 
     if (n_used == n_alloc) 
     { 
      size_t new_size = n_alloc * 2; 
      int *new_data = realloc(data, new_size); 
      if (new_data == 0) 
      { 
       free(data); 
       …report error and return… 
      } 
      data = new_data 
      n_alloc = new_size; 
     } 
     data[n_used++] = strtol(ptr, NULL, base); 
     ptr = strtok(NULL, " \n"); 
    } 
} 

/* Optionally resize array */ 
*array = realloc(data, n_used * sizeof(*data)); 
/* Or, instead of realloc(), just write: *array = data; */ 
return n_used; 

В качестве альтернативы, инициализация может быть:

size_t n_alloc = 0; 
size_t n_used = 0; 
int *data = 0; 

Это также будет работать нормально; он даже сокращает количество мест, где требуется отчет об ошибках.

Обратите внимание, что код тщательно избегает утечки памяти в случае ошибки realloc(). Ошибочно написать:

ptr = realloc(ptr, size); 

Если realloc() не удается, ptr присваиваются NULL, что означает, что вы не можете освободить память, которая была выделена перед вызовом realloc(), который является архетипической утечкой памяти.

отметить также, что этот код относится к array (int **) и data (int *) правильно. Исходный код в вопросе обрабатывал array, как если бы он был int *, а не int **.

+0

этот код: data [n_used ++] не будет правильно переходить к следующей записи в памяти, на которую указывают данные, если это не произойдет что int и long int имеют одинаковую длину.Это может быть правдой, но является плохим предположением, гораздо лучше изменить данные int * на длинные int * данные. – user3629249

+0

@ user3629249: Можете ли вы объяснить, почему 'long' имеет значение, когда код в вопросе не используется 'long'? –

Смежные вопросы