c - 在c中为数组动态分配内存时的停止条件

标签 c

我从输入中获取一个数组,当没有更多内存时,我分配更多内存(我不能使用 realloc)。我的问题是我不知道该将什么作为循环的停止条件。我希望它在我按 Enter 时停止接受输入,但它只是等待更多。(我应该使用 scanf)

我的代码:

#include<stdio.h>
#include<stdlib.h>
#define CHUNK 5
int main()
{
    int *arr, allocate_size=0, i, j, k, temp=0, *p, len=0;
    printf("Enter array: ");
    for(i=0,j=0;temp!='\n';i++){
        if(i>=allocate_size){
            allocate_size+= ((++j)*CHUNK);
            p = (int*)malloc(sizeof(int)*allocate_size);
            if(p==NULL){
                printf("Error");
                return 1;
            }
            for(k=0;k<i && i!=0;k++){ /*copying array*/
                p[k]=arr[k];
            }
            free(arr);
            arr = p;
        }
        if(!scanf(" %d", &temp)){
            printf("Invalid input");
            return 1;
        }
        if(temp!='\n'){
            arr[i] = temp;
            len++;
        }
    }
    printf("length is %d\n", len);
    for(i=0;i<len;i++){
        printf("%d",arr[i]);
    }
    return 0;
} 

最佳答案

获取用户输入的首选方法是使用 fgets() 或 POSIX getline() 一次读取整行输入。原因是每次读取都会消耗一整行输入,而 stdin 中保留的内容并不取决于所使用的 scanf 转换说明符 。它还无需记住哪些转换说明符消耗前导空格,哪些不消耗前导空格,并消除在匹配失败时留在stdin中的字符。

它还可以方便地检查用于保存输入的缓冲区中的第一个字符是否是 '\n' 告诉您 Enter 单独是在没有任何其他输入的情况下按下。

要在代码中使用 fgets()sscanf(),只需声明一个缓冲区来保存一行用户输入,足以满足用户的任何需求输入(或者如果猫踩在键盘上会产生什么结果)——不要吝惜缓冲区大小。然后使用 fgets() 将输入读入缓冲区,并检查第一个字符是否为 '\n' 以确定是否单独按下了 Enter .

您可以按如下方式执行此操作:

int main()
{
    char buf[256];
    ...
        if (!fgets (buf, sizeof buf, stdin)) {  /* read line of input/validate */
            fputs ("(user canceled input)\n", stderr);
            return 1;
        }
        if (buf[0] == '\n')     /* break loop on [Enter] alone */
            break;
        if (sscanf (buf, "%d", &temp) != 1) {
            fputs ("error: invalid integer input.\n", stderr);
            return 1;
        }
    ...

(注意:检查 sscanf (buf, "%d", &temp) != 1 将捕获手动生成的 EOF如果用户按 Ctrl+d(或在 Windows 上按 Ctrl+z),则 !sscanf(buf, "%d", &temp) 获胜't)

仔细检查一下,如果您还有其他问题,请告诉我。

<小时/>

编辑每条评论

因为在您的问题中,您表明必须为每个读取的整数动态分配,但您不能使用 realloc 来调整数组大小,这是双指针 arr 的唯一逻辑假设code> 和 p 是,您应该通过每次使用 p 分配存储来手动实现 realloc,通过以下方式保存指向分配 block 的指针在每次迭代结束时从 arr = p; 进行赋值,以便您可以从 arr 复制到您在下一次迭代中分配的新 p 并然后在再次分配 arr = p; 之前释放 arr 以防止内存泄漏

将上述解决方案与您发布的代码放在一起,您可以执行类似于以下操作的操作:

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

#define CHUNK  5
#define MAXC 256

int main (void)
{
    char buf[MAXC] = "";        /* buffer to hold each line */
    int *arr = NULL,            /* pointer to block holding final array */
        *p = NULL,              /* temp pointer to allocate for each number */
        allocate_size = 0,      /* tracks length of array */
        temp = 0;               /* temp value for integer conversion */

    printf ("Enter %d elements of array:\n\n  arr[%d]: ", CHUNK, allocate_size);

    while (fgets (buf, MAXC, stdin)) {  /* read user input into buf */
        int rtn;                        /* variable to hold sscanf return */

        if (*buf == '\n')               /* check if ENTER alone */
            break;                      /* break loop if so */

        /* use sscanf to convert to int, saving return */
        if ((rtn = sscanf (buf, "%d", &temp)) == 1) {
            /* allocate new storage for allocate_size + 1 integers */
            if (!(p = malloc ((allocate_size + 1) * sizeof *p))) {
                perror ("malloc-p");
                break;
            }
            for (int i = 0; i < allocate_size; i++) /* copy arr to p */
                p[i] = arr[i];
            p[allocate_size++] = temp;  /* add new element at end */

            free (arr);                 /* free old block of memory */
            arr = p;                    /* assign new block to arr */
        }
        else if (rtn == EOF) {  /* manual EOF generated */
            fputs ("(user canceled input)\n", stderr);
            break;
        }
        else {  /* not an integer value */
            fputs ("error: invalid integer input.\n", stderr);
        }

        if (allocate_size < CHUNK)  /* if arr not full, prompt for next */
            printf ("  arr[%d]: ", allocate_size);
        else
            break;                  /* done */
    }

    /* output results */
    printf ("\nlength is %d\n", allocate_size);
    for (int i = 0; i < allocate_size; i++)
        printf (" %d", arr[i]);
    putchar ('\n');

    free (arr);     /* don't forget to free what you allocate */
}

示例使用/输出

没有停止或错误:

$ ./bin/arrnorealloc
Enter 5 elements of array:

  arr[0]: 10
  arr[1]: 20
  arr[2]: 30
  arr[3]: 40
  arr[4]: 50

length is 5
 10 20 30 40 50

提早停止:

$ ./bin/arrnorealloc
Enter 5 elements of array:

  arr[0]: 10
  arr[1]: 20
  arr[2]:

length is 2
 10 20

处理用户错误:

$ ./bin/arrnorealloc
Enter 5 elements of array:

  arr[0]: 10
  arr[1]: 20
  arr[2]: dogs
error: invalid integer input.
  arr[2]: 30
  arr[3]: fish
error: invalid integer input.
  arr[3]: 40
  arr[4]: 50

length is 5
 10 20 30 40 50

内存使用/错误检查

最重要的是动态分配内存时,错误检查:

$ valgrind ./bin/arrnorealloc
==5555== Memcheck, a memory error detector
==5555== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5555== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5555== Command: ./bin/arrnorealloc
==5555==
Enter 5 elements of array:

  arr[0]: 10
  arr[1]: 20
  arr[2]: 30
  arr[3]: 40
  arr[4]: 50

length is 5
 10 20 30 40 50
==5555==
==5555== HEAP SUMMARY:
==5555==     in use at exit: 0 bytes in 0 blocks
==5555==   total heap usage: 7 allocs, 7 frees, 2,108 bytes allocated
==5555==
==5555== All heap blocks were freed -- no leaks are possible
==5555==
==5555== For counts of detected and suppressed errors, rerun with: -v
==5555== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放分配的所有内存并且不存在内存错误。

关于c - 在c中为数组动态分配内存时的停止条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59701788/

相关文章:

c - 使用C从txt文件中获取具体数据

c# - 我可以使用 Xcode 编写 Excel 插件吗?

c - 使用 shmget 和 shmat 时页面获取(删除)

python - 将文件转换为静态 C 字符串声明

c - 文件内容不会读入结构

c - 消除字符串中以空格结尾的特殊字符

c - Gcc 编译器优化函数内联

c - 指向 3d 数组的指针

c - 指向共享变量的指针互斥

objective-c - 为什么我不能将 nil 对象添加到 NSMutableArrays?