Как перераспределить массив внутри функции без потери данных?(в С) - PullRequest
0 голосов
/ 26 декабря 2010

У меня есть динамический массив структур, поэтому я подумал, что могу хранить информацию о массиве в первой структуре.

Таким образом, один атрибут будет представлять объем памяти, выделенный для массива, а другой - количество структур, фактически сохраненных в массиве.

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

Может кто-нибудь объяснить, почему это так и как это преодолеть?Вот мой код

#define INIT 3

typedef struct point{
    int x;
    int y;
    int c;
    int d;
}Point;
Point empty(){
    Point p;
    p.x=1;
    p.y=10;
    p.c=100;
    p.d=1000; //if you put different values it will act differently - weird
    return p;
}
void printArray(Point * r){
    int i;
    int total = r[0].y+1;
    for(i=0;i<total;i++){
          printf("%2d | P [%2d,%2d][%4d,%4d]\n",i,r[i].x,r[i].y,r[i].c,r[i].d);
    }
}

void reallocFunction(Point * r){
    r=(Point *) realloc(r,r[0].x*2*sizeof(Point));
    r[0].x*=2;
}
void enter(Point* r,int c){
    int i;
    for(i=1;i<c;i++){
        r[r[0].y+1]=empty();
        r[0].y++;
        if( (r[0].y+2) >= r[0].x ){ /*when the amount of Points is near
                                     *the end of allocated memory.
                                      reallocate the array*/
            reallocFunction(r);
        }
    }
}

int main(int argc, char** argv) {
    Point * r=(Point *) malloc ( sizeof ( Point ) * INIT );
    r[0]=empty();
    r[0].x=INIT;    /*so here I store for how many "Points" is there memory
                    //in r[0].y theres how many Points there are.*/
    enter(r,5);
    printArray(r);
    return (0);
}

Ответы [ 2 ]

2 голосов
/ 26 декабря 2010

Ваш код не выглядит мне чистым по другим причинам, но ...

void reallocFunction(Point * r){
    r=(Point *) realloc(r,r[0].x*2*sizeof(Point));
    r[0].x*=2;
    r[0].y++;
}

Проблема здесь в том, что r в этой функции является параметром, поэтому любые изменения в ней будут потеряныкогда функция возвращается.Вам нужен какой-то способ изменить версию вызывающего абонента на r.Я предлагаю:

Point *   // Note new return type...
reallocFunction(Point * r){
    r=(Point *) realloc(r,r[0].x*2*sizeof(Point));
    r[0].x*=2;
    r[0].y++;

    return r; // Note: now we return r back to the caller..
}

Затем позже:

r = reallocFunction(r);

Теперь ... Еще одна вещь, которую следует учитывать, это то, что realloc может потерпеть неудачу.Общий шаблон для realloc, который объясняет это:

Point *reallocFunction(Point * r){
    void *new_buffer = realloc(r, r[0].x*2*sizeof(Point));

    if (!new_buffer)
    {
       // realloc failed, pass the error up to the caller..
       return NULL;
    }

    r = new_buffer;
    r[0].x*=2;
    r[0].y++;

    return r;
}

Это гарантирует, что вы не пропустите r при сбое выделения памяти, и тогда вызывающая сторона должна решить, что произойдет, когда вашфункция возвращает NULL ...

Но некоторые другие вещи, на которые я хотел бы обратить внимание в этом коде (я не хочу сказать, что я придираюсь к вещам и пытаюсь их разлучить;подразумевается как конструктивная обратная связь при проектировании):

  • Имена переменных и членов не дают четкого представления о том, что вы делаете.
  • У вас много магииконстанты.Нет никакого объяснения тому, что они имеют в виду или почему они существуют.
  • reallocFunction, кажется, не имеет никакого смысла.Возможно, имя и интерфейс могут быть более понятными.Когда вам нужно realloc?Почему вы удваиваете член X?Почему вы увеличиваете Y?Может ли звонящий принять эти решения вместо этого?Я хотел бы прояснить это.
  • Точно так же не ясно, что должен делать enter().Возможно, имена могли бы быть более четкими.
  • Это хорошая вещь, чтобы распределять и управлять переменными-членами в согласованном месте, поэтому легко определить (и позже, возможно, изменить), как вы должны создать, уничтожить и манипулировать одним из этих объектов.Здесь, в частности, кажется, что main() хорошо знает внутренности вашей структуры.Это кажется плохим.
  • Использование оператора умножения в параметрах до realloc в способе, который вы делаете, иногда является красным флагом ... Это угловой случай, но умножение может переполниться, и вы можете в конечном итогесокращение буфера вместо его роста.Это может привести к сбою, и при написании производственного кода важно избегать этого по соображениям безопасности.
0 голосов
/ 26 декабря 2010

Вы, похоже, тоже не инициализируете r[0].y. Насколько я понял, у вас должно быть где-то r[0].y=0.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...