VS сходит с ума после второго realloc - PullRequest
0 голосов
/ 29 декабря 2018

Итак, у меня есть входной файл, который имеет следующий текст (каждая строка = пользователь):

012345678;danny;cohen;22;M;danny1993;123;1,2,4,8;Nice person
223325222;or;dan;25;M;ordan10;1234;3,5,6,7;Singer and dancer
349950234;nadav;cohen;50;M;nd50;nadav;3,6,7,8;Engineer very smart

Сначала код выделяет место для одного пользователя, а затем перераспределяет пространство для еще 1 (для каждого пользователя).дело в том, что все идет отлично, пока второй раз не перераспределяется, а затем показывает ошибку «Упражнение 6.exe вызвало точку останова».Я также упомяну, что ошибка была сначала: «wntdll.pdb не загружен», но я попытался сделать то, что VS suggeset - что-то с символами. Затем пришла ошибка «Триггерная точка».

Я попытался переключитьстрок в текстовом файле, но это не имело значения, проблема возникает после попытки перераспределения во второй раз.

позвольте мне показать вам соответствующую часть кода:

int main()
{
    //intiallizing variables
    int menArraySize = 0;
    //creating a NULL array pointer (array) for men
    User *head = NULL;
    readInputFile(head, &menArraySize, list);
}

void readInputFile(User *head, int *menArraySize, WomenList *list)
{
    //temporary data types for the the stracture we're creating
    char id[10];
    char *firstName = NULL;
    char *lastName = NULL;
    char age[4] = { 0 };
    char gender = '\0';
    char *userName = NULL;
    char *password = NULL;
    char hobbies = 0;
    char *description = NULL;
    //regular function data types
    int i = 0, j = 0, k = 0, currentDetail = 1, size;
    char currentString[212] = { 0 };
    int currentChar;

    //opening the input file
    FILE *input = fopen("input.txt", "r");
...
//long code for allocating room for each string (firstName, lastName, etc...)- irelevant
...
    head = addMale(head, menArraySize, id, firstName, lastName, age,
        gender, userName, password, hobbies, description);
...
//rest of the function isn't relevant
}

User* addMale(User *head ,int *menArraySize, char id[], char *firstName, 
char *lastName,char age[], char gender, char *userName,


char *password, char hobbies, char *description)
            {
                //if the array is empty, allocate room for one user
                if (*menArraySize == 0)
                {
                    head = (User *)malloc(1 * sizeof(User));
                }
                //if the array isn't empty, reallocate room for one more user
                else
                {
                    **this is the line in which the error occurs (second time reallocating,
                   third dynamic allocation total for this pointer)**
                head = (User *)realloc(head, (*menArraySize + 1) * sizeof(User));
                }
                //if the allocation failed
                if (head == NULL)
                    exit(1);
                //pointing to the new user we created
                head = &head[*menArraySize];
                //apply all details to the user
                strcpy(head->id, id);
                head->firstName = firstName;
                head->lastName = lastName;
                strcpy(head->age, age);
                head->gender = gender;
                head->userName = userName;
                head->password = password;
                head->hobbies = hobbies;
                head->description = description;
                //applying an index number to the user
                head->index = *menArraySize;
                //pointing back to the head of the array
                head = &head[0];
                //updating the variable showing the size of the array
                *menArraySize = *menArraySize + 1;
                return head;
            }

почему это происходит? что я могу сделать, чтобы это исправить? спасибо!

Ответы [ 2 ]

0 голосов
/ 30 декабря 2018

@ Жан-Франсуа уже исправил ошибку .Но многих неприятностей можно избежать, если разбить проблему на более четко определенные части.

То, что делает код, это ...

  1. Откройте файл И прочитайте его из файла вкуча переменных И вызывает другую функцию, чтобы превратить эти переменные в пользователя и добавить его в список.
  2. Создать пользователя из группы переменных и поместить его в массив.

Когда вы описываете функцию «и» - это подсказка, ее можно разбить на более мелкие функции.Проход через переменные (head, menArraySize) указывает, что два отдельных действия были излишне объединены.Наконец, необходимость обойти парные переменные (head и menArraySize) указывает на то, что, возможно, их следует превратить в структуру.

Вместо этого она должна быть отделена следующим образом ...

  1. Откройте файл.
  2. Считайте пользователя из файла.
  3. Выдвиньте пользователя в массив.

Это приводит к двум более простым функциям с более четким определениемфункциональность.

User *UserRead(FILE *fp);
void UsersPush(Users *users, User *user);

И используется так же.

FILE *input = fopen("input.txt", "r");
if( input == NULL ) {
    perror("Could not open input.txt");
    exit(1);
}

Users *users = UsersNew();

User *user = UserRead(input);
if( user == NULL ) {
    fprintf(stderr, "Could not read user.\n");
    exit(1);
}
UsersPush(users, user);

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

typedef struct {
    // How many users?
    size_t num;
    // How much space do we have?
    size_t size;
    User **users;
} Users;

// Allocate and initialize Users.
Users *UsersNew() {
    Users *users = malloc(sizeof(Users));

    // Because we're storing the size separate from the number of users
    // we can preallocate some space. This makes the code simpler, no NULL
    // condition to worry about, and we can be smarter about growing the array.
    users->num = 0;
    users->size = 1;
    users->users = malloc(sizeof(Users*));

    return users;
}

// Isolate the tricky work of growing the array in its own function.
// This makes it reusable, and we can improve the growth algorithm.
void UsersGrowIfNecessary(Users *users) {
    // asserts like these to check for impossible conditions will save you
    // a lot of debugging time. This makes sure there's never more Users than
    // space for them.
    assert(users->size >= users->num );

    // Check if we need more space.
    if( users->size == users->num ) {
        // Double the size to avoid excessive expensive reallocs.
        size_t new_size = users->size * 2;
        users->users = realloc(users->users, sizeof(Users*) * new_size);
        users->size = new_size;
    }
}

// Add the user, growing the array if necessary.
void UsersPush(Users *users, User *user) {
    UsersGrowIfNecessary(users);

    // With all that done, adding the user is simple.
    users->users[users->num] = user;
    users->num++;
}

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

С учетом всего этого работа по распределению и чтению пользователя может бытьвзялись за дело.

typedef struct {
    char id[10];
    char *firstName;
    char *lastName;
    int age;
    char gender;
    // etc...
} User;

User *UserNew() {
    // Use calloc to begin with everything zeroed.
    User *user = calloc(sizeof(User), 1);

    // 0 isn't always NULL.    
    user->firstName = NULL;
    user->lastName = NULL;

    return user;
}

User *UserRead(FILE *input) {
    User *user = UserNew();

    // The rest is left as an exercise.
    if( fscanf(input, "%9s", user->id) != 1 ) {
        fprintf(stderr, "Couldn't read user ID.\n");
        return NULL;
    }

    return user;
}
0 голосов
/ 29 декабря 2018

здесь:

head = &head[*menArraySize];

вы указываете на новое местоположение, но вы также перезаписываете (и теряете) head исходное значение (если не вычитаете).Когда вы делаете:

head = &head[0];

вы думаете вы восстанавливаете исходное значение, но это ничего не дает.Вы просто ссылаетесь / разыменовываете одно и то же значение.

Решение: используйте другое значение User *temp для ссылки на новое местоположение.И оставьте head без изменений после того, как вы использовали realloc.

...