Mallo c до внезапного завершения без ошибок - PullRequest
0 голосов
/ 10 января 2020

Я пытаюсь создать программу, которая читает целые числа из файла с 103690 парами целых чисел, пропуская строки, начинающиеся с #, и сохраняет их в массиве. Даже если это происходит успешно, оно внезапно останавливается после указанной c строки (строка 5115).

Файл выглядит так:

#I must
#be
#skipped
8050    6737
8050    7238

Код:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct {
    int start;
    int end;   
} path;

int doublesize(path* array,int n){
    path* new_array=malloc(n*2*sizeof(path));
    if(new_array==NULL){
        printf("Error allocating memory\n");
        abort();
    }

    for(int i=0;i<n;i++){
        new_array[i]=array[i];
    }
    free(array);
    array=new_array;
    n*=2;
    return n;

}


int main()
{
    int maxsize=10;
    int test;
    path* array=malloc(maxsize*sizeof(path));
    if(array==NULL) {
        printf("Error allocating memory\n");
        abort();
    }


    FILE* fd=fopen("Wiki-Vote2.txt","r");
    if(fd==NULL) {
        printf("Error opening file\n");
        abort();
    }
    char buff[200];
    int counter=0;

    char c;
    while(fgets(buff,200,fd)) {

        c=buff[0];
        if(c=='#') {
            continue;
        }
        test=sscanf(buff,"%d%d",&array[counter].start,&array[counter].end);
        printf("%d\t%d\n",array[counter].start,array[counter].end);
        printf("Read %d numbers\n", test);
        counter++;
        if(counter==maxsize){
           maxsize=doublesize(array,maxsize); 
        }


    }


    fclose(fd);
    free(array);
    return 0;
}

Я попытался уменьшить количество целых чисел, которое работает, но когда я использовал gdb, я увидел, что он возвращает сигнал sigsegv (я использую windows). Возможно, памяти недостаточно или это что-то еще?

Ответы [ 3 ]

3 голосов
/ 10 января 2020

Аргументы функции передаются по значению. Это включает в себя указатели. Поэтому, когда вы делаете array=new_array; внутри doublesize, вы назначаете копию указателя array указателя из main. Значение array внутри main функции остается неизменным.

Вы можете передать указатель на указатель, чтобы изменить его значение.

int doublesize(path **array,int n){
    ...
        // first dereference array, then access element number i
        new_array[i] = (*array)[i];
    }
    // free the array where array points to, ie array in main
    free(*array);
    // assign new value to array
    *array = new_array;
    n *= 2;
    return n;
}


int main()
{
    ...
           // pass array by pointer to let doublesize modify it
           maxsize = doublesize(&array, maxsize); 
    ...
}

Я думаю, что это может быть понятнее измените функцию doublesize, чтобы она возвращала новый указатель и указывала на переменную int, которая представляет максимальный размер, например:

path *doublesize(path *array, int *maxsize){
    int n = *maxsize;
    ...
    free(array);
    // maxsize here points to the variable maxsize in main
    // let's write n * 2 to it
    *maxsize = n * 2;
    // return the new pointer
    return new_array;
}


int main()
{
    ...
           // array is updated with the new value
           // maxsize is updated with 
           array = doublesize(array, &maxsize); 
    ...
}
1 голос
/ 10 января 2020

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

int doublesize(path** array,int n){
    path* new_array=realloc( *array, n*2*sizeof(path));
    if(new_array==NULL){
        printf("Error allocating memory\n");
        abort();
    }

    *array=new_array;
    return n*2;
}

Вызовите функцию с помощью

maxsize=doublesize(&array,maxsize); 
1 голос
/ 10 января 2020

Проблема в вашей функции изменения размера:

int doublesize(path* array,int n){
     ...
     array=new_array;

Переменная array является локальной для функции, поэтому изменения в ней не отражаются в вызывающей функции. В результате array в main теперь указывает на освобожденную память после возврата этой функции и попытки разыменовать этот указатель вызывает неопределенное поведение .

Вы должны изменить эту функцию, чтобы принимать path **:

int doublesize(path **array,int n){
    path *new_array=malloc(n*2*sizeof(path));
    if(new_array==NULL){
        printf("Error allocating memory\n");
        abort();
    }

    for(int i=0;i<n;i++){
        new_array[i]=(*array)[i];
    }
    free(*array);
    *array=new_array;
    n*=2;
    return n;

}

И передать адрес array в main:

maxsize=doublesize(&array,maxsize); 
...