【问题标题】:realloc an array of pointers is doing nothingrealloc 一个指针数组什么都不做
【发布时间】:2015-03-19 05:11:24
【问题描述】:

我有一个字符串数组,我想在它不再有 NULL 指针时扩展它(意味着数组已满)。 我尝试了 realloc 但没有成功,我认为我没有正确地考虑指针。

这是我的代码:

int storage; //global, outside of main
int i, key;
char **people;
char **phones;

printf("Please enter a storage cacpity:\n");
scanf("%d",&storage);
printf("\n");

people=malloc(storage*sizeof(char *));
phones=malloc(storage*sizeof(char *));

for (i=0; i<storage; i++) {
    people[i] = NULL;
    phones[i] = NULL;
}

void AddNewContact(char * people[], char * phones[]) {
    char name[100];
    char phone[12];
    int i, listfull = 0;

    printf("Enter a contact name:\n");
    scanf("%s",&name);
    printf("Enter a phone number:\n");
    scanf("%s",&phone);

    for (i=0; i<storage; i++) {
        if (people[i]==NULL) {
            people[i] = (char *)malloc(strlen(name));
            phones[i] = (char *)malloc(strlen(phone));
            strcpy(people[i],name);
            strcpy(phones[i],phone);
            break;
        }
        listfull = 1;
    }

    if (listfull == 1) {
        storage++;
        people = realloc(&people,(storage)*sizeof(char *));
        phones = realloc(&phones,(storage)*sizeof(char *));
        people[storage-1] = NULL;
        phones[storage-1] = NULL;
        strcpy(people[storage-1],name);
        printf("\nData Base extanded to %d",storage);
    }
    printf("\n");
    return;
}

void PrintAll(char * people[], char * phones[]) {
    int i;
    for (i=0; i<storage; i++) {
        if (NULL != people[i]) {
            printf("Name: %s, ",people[i]);
            printf("Number: %s\n",phones[i]);
        }
    }
    printf("\n");
    return;
}

任何帮助将不胜感激,我坚持了几个小时,没有运气解决这个问题。

【问题讨论】:

  • @NirTzezana:您遇到的具体问题是什么?
  • people&amp;people 不一样。
  • 作为一个建议,您应该将strcpy(people[i], name);strcpy(phones[i], phone); 更改为strncpy(people[i], name);strncpy(phones[i], phone);。这不会解决你的问题,但它会 NULL 终止字符串。
  • @NirTzezana:你怎么知道?
  • 哦,作为第二个建议,请切勿这样做:people = realloc(&amp;people,(storage)*sizeof(char *));。如果重新分配失败,则返回 NULL,这意味着 people 变为 NULL 指针。因此,您丢失了指向该内存块的指针。您应该将 realloc 的返回值分配给一个单独的变量和if ( NULL != returnedReallocAddress ) people = returnedReallocAddress;

标签: c arrays string pointers realloc


【解决方案1】:

你有4个重要错误,首先你将数组的地址传递给scanf()这是错误的,你应该改变

scanf("%s", &name);

scanf("%s", name);

除了scanf("%s",&amp;phone);,我还应该建议使用scanf 的长度说明符来防止缓冲区溢出,例如

scanf("%99s", name);

name 数组的长度 -1,用于 '\0' 终止符。

其次,你的realloc调用也是错误的,你应该传递指针而不是它的地址,而不是这个

people = realloc(&people,(storage)*sizeof(char *));

你应该这样做

people = realloc(people, storage * sizeof(char *));

但即使这样也不是 100% 正确,因为万一realloc 失败,您将覆盖指针,然后您将没有机会清理内存,所以您实际上应该这样做

void *pointer;
pointer = realloc(people, storage * sizeof(char *));
if (pointer == NULL)
    free_people_andCleanUpOtherResourcesAndExitFromThisFunction();
people = pointer;

phones 也是如此。

第三你应该总是为一个额外的字符分配空间,终止'\0',这个

people[i] = (char *)malloc(strlen(name));

应该阅读

people[i] = malloc(1 + strlen(name));

请注意,我删除了不必要的演员表。

第四次你在第一次迭代中退出循环,离开listfull == 1,即使列表尚未满。

for (i=0; i<storage; i++) {
    if (people[i]==NULL) {
        people[i] = malloc(1 + strlen(name));
        phones[i] = malloc(1 + strlen(phone));
        strcpy(people[i],name);
        strcpy(phones[i],phone);
        break;
    }
    listfull = 1;
}

我会在循环之外推荐这个

listfull = (i == storage);

注意:不管一个函数失败的可能性有多大,如果理论上它会失败,你应该经常检查它是否失败,这样可以节省你几个小时的调试时间来找到一个非常愚蠢的错误,您没有检查可能的故障。

【讨论】:

  • 谢谢,程序在尝试使用 realloc 扩展数组时仍然崩溃。
  • 还有第三个重要错误:在 C 中,字符串是由 NUL 字符 '\0' 终止的字符数组。 strlen 返回的长度 not 包含 NUL 字符。所以 OP 使用的所有缓冲区都太小了 1 个字符。
  • @user3386109 谢谢,我已将其更新为 strlen(name)+1)
  • @user3386109 完全正确,我没有注意到。
  • @NirTzezana 如果你愿意,可以联系我 iharob@gmail.com
【解决方案2】:

你有

listfull = 1;

在你的 (for i ...) 循环内,它应该在循环外,像这样

if (i == storage)           // if loop completed
    listfull = 1;

接下来,您的部分程序会发现一些变量是全局声明的,但它们后面是可执行代码语句,这些语句必须在函数内,那么“全局”变量实际上是局部变量吗?

【讨论】:

  • 天气,我相信 OP 粘贴了一些实际代码,而不是包含所有实际代码。我猜想被注释为“全局”的变量可能是全局定义的,并且它们后面的代码可能在他没有包含声明的某个函数中。也就是说,因此代码有点令人困惑。
  • 你说的是存储,它需要是全局的,因为它被用于许多功能。你可以在这里看到完整的代码:pastebin.com/45grLUrs
  • @SpencerDoak 我认为粘贴部分代码而不是整个代码会更好,因为它更短,更专注于不起作用的部分。
  • @NirTzezana 如果peoplephones 是全局的,为什么需要将它们传递给AddNewContact()
  • @NirTzezana,是的,在 SO 上通常首选只显示相关的代码片段,但我可能会建议您在未来的问题中包含函数声明(例如 returnType functName(params) { ... })。这使读者可以注意到函数和全局变量之间的分离。就是说,感谢您保守,没有将所有代码都扔到问题中。帮助发布项目每一行的人可能会让人不知所措。
猜你喜欢
  • 2016-08-23
  • 1970-01-01
  • 1970-01-01
  • 2021-09-02
  • 2019-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-12
相关资源
最近更新 更多