无法到达 realloc 分配的内存

Can't reach memory allocated by realloc

我有一个全局动态指针数组 (iterator) 指向结构 (person_t)。首先,我为 iterator 分配了 10*sizeof(person_t*) 内存,在内部我为每个 iterator[i] i = 0..9.

分配了 sizeof(person_t) 内存
typedef struct Person
{
    char name[30];
    unsigned age;
    char job[30];
} person_t;

person_t **iterator;
int size = 10;
int count = 0;

int main()
{
    int i;
    iterator = malloc(size * sizeof(person_t *));
    if (iterator == NULL)
    {
        /*fprintf(stderr, "Memory allocation did not succeed\n");*/
        exit(1);
    }
    for (i = 0; i < size; ++i)
    {
        iterator[i] = malloc(sizeof(person_t));
        if (iterator[i] == NULL)
        {
            /*fprintf(stderr, "Memory allocation did not succeed\n");*/
            exit(1);
        }
    }
}

在我达到最大容量之前一切正常。发生这种情况时,我尝试重新分配 iterator 以获得更多内存,但它似乎不起作用,尽管我没有收到任何类型的警告或编译错误(我使用 gcc -ansi -pedantic -W -Wall -Wextra 编译),并且 realloc 不会 return NULL。这就是一切发生的地方:

void grow()
{
    int i;
    size += 5;
    iterator = realloc(iterator, size);
    if (iterator == NULL)
    {
        /*fprintf(stderr, "Memory allocation did not succeed\n");*/
        exit(1);
    }
    printf("realloced to bigger\n");
    for (i = size - 5; i < size; ++i)
    {
        iterator[i] = malloc(sizeof(person_t));
        if (iterator[i] == NULL)
        {
            /*fprintf(stderr, "Memory allocation did not succeed\n");*/
            exit(1);
        }
    }
}

当我尝试在调用 grow() 之前列出我的数据时,一切都很好。在 grow() 之后,可能会打印前 3 个结构(第一个被搞砸了),然后我得到 Segmentation fault.

如果有帮助,这里是完整代码:

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

typedef struct Person
{
    char name[30];
    unsigned age;
    char job[30];
} person_t;

person_t **iterator;
int size = 10;
int count = 0;

void newPerson();
void grow();
void list();
void del();

int main()
{
    int i;
    iterator = malloc(size * sizeof(person_t *));
    if (iterator == NULL)
    {
        /*fprintf(stderr, "Memory allocation did not succeed\n");*/
        exit(1);
    }
    for (i = 0; i < size; ++i)
    {
        iterator[i] = malloc(sizeof(person_t));
        if (iterator[i] == NULL)
        {
            /*fprintf(stderr, "Memory allocation did not succeed\n");*/
            exit(1);
        }
    }
    while (1)
    {
        char menuChoice = ' ';
        scanf("%c", &menuChoice);

        switch (menuChoice)
        {
        case 'a':
            newPerson();
            break;
        case 'l':
            list();
            break;
        case 'x':
            for (i = 0; i < size; ++i)
            {
                free(iterator[i]);
            }
            free(iterator);
            exit(0);
        case 'd':
            del();
            break;
        case '\n':
            break;
        default:
            fprintf(stderr, "\'a\' -add, \'l\' -list, \'d\' -delete,  \'x\' -exit\nOnly these inputs are allowed\n");
            break;
        }
    }

    return 0;
}

void newPerson()
{
    unsigned a = 0;
    char strN[30];
    char strJ[30];
    int err;

    if (count == size)
        grow();

    /*printf("Name: ");*/
    scanf("%s", strN);
    if ((strlen(strN) + 1) > 30)
    {
        do
        {
            fprintf(stderr, "Maximum 30 characters are allowed\n");
            scanf("%s", strN);
        } while ((strlen(strN) + 1) > 30);
    }
    /*printf("Age: ");*/
    err = scanf("%u", &a);
    if (err != 1)
    {
        do
        {
            printf("Only numbers are allowed\n");
            fgetc(stdin);
            err = scanf("%u", &a);
        } while (err != 1);
    }
    /*printf("Job: ");*/
    scanf("%s", strJ);
    if ((strlen(strJ) + 1) > 30)
    {
        do
        {
            fprintf(stderr, "Maximum 30 characters are allowed\n");
            scanf("%s", strJ);
        } while ((strlen(strJ) + 1) > 30);
    }

    iterator[count]->age = a;
    strcpy(iterator[count]->name, strN);
    strcpy(iterator[count]->job, strJ);
    count++;
}

void list()
{
    int i;
    for (i = 0; i < count; ++i)
    {
        printf("%d. person:\tname: %s, age: %d, job: %s\n", i + 1, iterator[i]->name, iterator[i]->age, iterator[i]->job);
    }
}

void grow()
{
    int i;
    size += 5;
    iterator = realloc(iterator, size);
    if (iterator == NULL)
    {
        /*fprintf(stderr, "Memory allocation did not succeed\n");*/
        exit(1);
    }
    printf("realloced to bigger\n");
    for (i = size - 5; i < size; ++i)
    {
        iterator[i] = malloc(sizeof(person_t));
        if (iterator[i] == NULL)
        {
            /*fprintf(stderr, "Memory allocation did not succeed\n");*/
            exit(1);
        }
    }
}

void del()
{
    char toDelete[30];
    int i;
    int toDeleteIndex;
    scanf("%s", toDelete);
    if ((strlen(toDelete) + 1) > 30)
    {
        do
        {
            fprintf(stderr, "Maximum 30 characters are allowed\n");
            scanf("%s", toDelete);
        } while ((strlen(toDelete) + 1) > 30);
    }
    for (i = 0; i < count; ++i)
    {
        if (strcmp(iterator[i]->name, toDelete) == 0)
        {
            toDeleteIndex = i;
        }
    }
    if (i == count)
    {
        fprintf(stderr, "No match\nBack to menu\n");
    }
    else
    {
        free(iterator[toDeleteIndex]);
        for (i = toDeleteIndex; i < count - 1; ++i)
        {
            iterator[i] = iterator[i + 1];
        }
        free(iterator[count]);
        count--;

        if (count == size - 6)
        {
            size -= 5;
            iterator = realloc(iterator, size);
            if (iterator == NULL)
            {
                /*fprintf(stderr, "Memory allocation did not succeed\n");*/
                exit(1);
            }
            printf("realloced to smaller\n");
        }
    }
}

正如在malloc中一样,您需要以字节为单位指定大小。例如:

v = realloc(iterator, size * sizeof *iterator);
if( v != NULL ){
    iterator = v;
}

这是一个常见错误,可能是选择“尺寸”以外名称的一个很好的理由。 (也许称之为“能力”)。 请注意,尽管在您的代码中执行 iterator = realloc(iterator, size * sizeof *iterator) 是可以的,因为如果 realloc returns NULL,您会立即中止程序,但我修改了代码以使用不同的变量,只是为了向未来的读者强调该代码模式。