第二次重新分配后 VS 发疯了

VS goes nuts after second realloc

所以我有一个输入文件,其中包含以下文本(每行 = 用户):

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 个用户(每个用户)重新分配空间。问题是,在第二次重新分配之前一切都很顺利,然后它向我显示错误 "Exercise 6.exe has triggered a breakpoint." 我还会提到错误首先是: ““wntdll.pdb 未加载”但我尝试执行 VS 建议的操作 - 带有符号的操作。然后出现 "triggered a breakpoint" 错误。

我试过在文本文件中切换行,但没关系,第二次尝试重新分配后出现问题。

让我向您展示代码的相关部分:

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 = '[=11=]';
    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;
            }

为什么会这样?我该怎么做才能解决它?谢谢!

此处:

head = &head[*menArraySize];

您指向的是新位置,但您也覆盖(并丢失)了 head 原始值(除非您减去)。当你这样做时:

head = &head[0];

认为你正在恢复原始值,但这没有任何作用。你只是 reference/dereference 相同的值。

解决方案:使用另一个 User *temp 值来引用新位置。使用 realloc.

后保持 head 不变

。但是通过将问题分解成更明确的部分可以避免很多麻烦。

代码的作用是...

  1. 打开一个文件并从一个文件中读入一堆变量并调用另一个函数将这些变量转换为用户并将其添加到列表中。
  2. 从一堆变量构造一个 User 并将其推送到一个数组。

当你描述一个函数时,"and" 是一个提示,它可以分解成更小的函数。通过变量 (head, menArraySize) 表示两个单独的动作不必要地一起使用。最后需要传递成对的变量(headmenArraySize)表明也许它们应该变成一个结构。

相反,它应该像这样分开...

  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;
}