我在这里连续两次使用realloc函数,它似乎不工作,我用了一次,它完全工作正常,有人能告诉我为什么吗?

pdtvr36n  于 2023-01-08  发布在  其他
关注(0)|答案(2)|浏览(170)
#include <stdio.h>
#include <stdlib.h>

char *ptr;
int n;

int main()
{
    ptr = (char *)calloc(n, sizeof(char));
    // First ID
    printf("Enter the length of your employ ID\n");
    scanf("%d", &n);

    for (int i = 0; i <= n; i++)
    {
        scanf("%c", &ptr[i]);
    }
    for (int i = 0; i <= n; i++)
    {
        printf("%c", ptr[i]);
    }
    // Second ID
    printf("Enter the size of new ID\n");
    scanf("%d", &n);

    ptr = (char *)realloc(ptr, n * sizeof(char));

    for (int i = 0; i <= n; i++)
    {
        scanf("%c", &ptr[i]);
    }

    for (int i = 0; i <= n; i++)
    {
        printf("%c", ptr[i]);
    }

    // Third ID

    printf("Enter the size of new ID\n");
    scanf("%d", &n);

ptr =(字符 *)重新分配(ptr,n *(字符)的大小);

for (int i =0; i <=n; i++)
{
    scanf("%c", &ptr[i]);
}

for (int i = 0; i <= n; i++)
{
    printf("%c", ptr[i]);
}

return 0;

}
我试图获得三个人的身份证,但程序不工作,并采取输入后,一旦它刚刚退出:(。当我使用realloc一次而不是两次时,它工作得很好,有人能解释为什么吗?it takes the input and then exits

sauutmhj

sauutmhj1#

声明:

int n;

在文件作用域声明n。在文件作用域声明的对象具有静态存储持续时间,并且总是被初始化。在没有显式初始化的情况下,它们被隐式初始化为零。
来自C标准C11 6.7.9/10:
..."如果没有显式初始化具有静态或线程存储持续时间的对象,则:

  • 如果是指针类型,则初始化为空指针;
  • 如果是算术类型,则初始化为(正或无符号)零; "

访问超出界限的内存:

然后:

ptr = (char *)calloc(n, sizeof(char));

为0个对象分配内存。
calloc()函数的作用是:为一个由nmemb元素组成的数组分配内存,并返回一个指向所分配内存的指针。内存被设置为零。如果nmemb或size为0,则calloc()返回NULL,或者返回一个唯一的指针值,该指针值可以在以后成功传递给free()。
如果出错,这些函数返回NULL。NULL也可以通过成功调用大小为零的malloc()或成功调用nmemb或size等于零的calloc()返回。
但是您没有检查calloc的返回值。
然后,这句话:

scanf("%c", &ptr[i]);

尝试访问未分配的内存,从而调用未定义的行为。

因一个错误而关闭:

您已经为n元素分配了空间,但条件是:

i <= n

尝试访问n + 1元素,这是内存越界,您尚未分配内存,不属于您的内存,因此是未定义的行为(但这无关紧要,因为您一开始就没有分配任何内存)。
关于realloc
realloc()函数返回一个指向新分配的内存的指针,该指针与任何类型的变量对齐,并且可以不同于ptr,如果请求失败,则返回NULL。如果size等于0,则返回NULL或一个适合传递给free()的指针。如果realloc()失败,则原始块保持不变;它不被释放或移动。
这意味着如果它失败并返回NULL,那么ptr将被初始化为NULL,并且您将失去对原始内存的所有访问权限。
一种解决方案是使用另一个指针:

char *new = realloc(ptr, size);
if (!new) { /* if realloc failed */
   /* deal with it however you wish */
}

/* If we got here, it means that we weren't bounded */
ptr = new;. /* Now ptr points to the new memory, if it didn't already */
new = 0;    /* This avoids a dangling pointer */ 

/* some code relevant to ptr here */
free(ptr);  /* For every allocation, there must be a call to free */
  • 旁注:* 您不应该强制转换malloc和family的结果。这是多余的,可能会隐藏一个bug。这些函数返回的void *会自动提升为正确的类型。

结尾换行符:

scanf("%d", &n);

在输入缓冲区中保留一个换行符,它会被scanf的后续调用自动读取,并且可能永远不会提示您输入。
取代:

scanf("%c");

使用带有前导空格的" %c"可跳过可选的空格:

scanf(" %c");
6jjcrrmo

6jjcrrmo2#

首先,请注意您使用的是:

ptr = (char *)calloc(n, sizeof(char));

n没有在文件作用域中显式初始化时,它会自动初始化为0。因此,基本上,您可以在以下位置覆盖大小为0的缓冲区:

for (int i = 0; i <= n; i++)
{
    scanf("%c", &ptr[i]);
}

同时超过了分配给i <= n的大小,该大小应该是i < n,这可能就是原因。
其次,必须在最后使用free释放内存分配,并检查分配是否成功。
第三,在使用字符串时,您可能希望使用%s来使用scanf,除非有特定的原因。
更清楚且不易出错的实施方式可以是:

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

int main()
{
        int size, times, i;
        char *ptr;

        printf("Enter the number of IDs to enter\n");
        scanf("%d", &times);

        for (i = 0; i < times; ++i) {
                printf("Enter the size of new ID\n");
                scanf("%d", &size);
                if (size < 0) {
                        printf("Entered value is negative\n");
                        return size; // or any other error
                }

                // note the '+ 1' so we have a NULL terminating string
                ptr = (char *)calloc(size + 1, sizeof(char));
                if (ptr == NULL) {
                        printf("Error allocating ptr\n");
                        return -1; // or any other error
                }

                printf("Enter your ID\n");
                scanf("%s", ptr);

                printf("Your ID is: %s\n", ptr);
                free(ptr);
        }

        return 0;
}

希望我回答了所有问题,没有遗漏任何内容(:

相关问题