【问题标题】:VS goes nuts after second reallocVS 在第二次重新分配后发疯
【发布时间】:2018-12-29 20:33:27
【问题描述】:

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

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 建议的操作——使用符号。然后出现“触发断点”错误。

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

让我给你看一下代码的相关部分:

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

为什么会这样?我能做些什么来解决它?谢谢!

【问题讨论】:

  • head = &head[0]; 什么都不做。当你做head = &head[*menArraySize];时,你已经失去了head。使用另一个变量
  • 尽管存在技术问题——很好地解决了问题标题...在进行了建议的更改之后,您将永远不会看到 main() 中的 head 的分配,因为 readInputFile 收到了一份副本head 和在 main() 之外进行的任何分配都将丢失(以及内存泄漏)。相反,您需要传递head地址(例如&head),并且您的参数需要为User **head
  • 作为关于addMale 的一般说明——如果你传递的参数超过 4 个——你应该考虑重构你的代码。
  • 即使在修复之后,您也没有正确使用realloc - 您需要将指针保存到临时地址,然后检查,然后才将临时地址中的值分配给您的head。如果没有分配数组,则可以通过将指针设置为 NULL 来删除 if - realloc 将正确处理它。

标签: c dynamic-memory-allocation realloc


【解决方案1】:

这里:

head = &head[*menArraySize];

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

head = &head[0];

认为您正在恢复原始值,但这无济于事。您只需引用/取消引用相同的值。

解决方案:使用另一个User *temp 值来引用新位置。并在使用realloc 后保持head 不变。

【讨论】:

  • 那是完美的答案。我真的很感激,谢谢! (问题解决了)
  • 我很高兴,因为可能还有其他问题:)
  • 请问有什么问题?只是出于好奇
  • main() 之后readInputFile(head, &menArraySize, list); -- 你还期待head == NULL 吗? (更好地检查)在原始问题下方查看我的 cmets。
【解决方案2】:

@Jean-François has covered the immediate bug。但是,通过将问题分解成更明确的部分,可以避免很多麻烦。

代码正在做的是......

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

当你描述一个函数时,“and”是一个提示,它可以分解成更小的函数。传递变量(headmenArraySize)表示两个单独的操作不必要地一起使用。最后需要传递成对变量(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 结构来封装数组、它的大小以及其中有多少用户。这让我们只传递一个东西,一个用户结构,我们可以只做处理数组的工作。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-05
    • 2015-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-25
    • 2016-11-22
    相关资源
    最近更新 更多