【问题标题】:C : buffer and pointersC:缓冲区和指针
【发布时间】:2018-12-20 09:36:37
【问题描述】:

我正在编写一个必须的小程序:

  1. 询问用户他将输入多少个数字(动态存储在 2 个选项卡中)
  2. 逐步输入数字,如果他是正数则进入缓冲区P,如果负数则进入缓冲区N
  3. 如果缓冲区中没有更多位置,则将其大小加倍
  4. 最后 printf 两个缓冲区

这是我的代码:

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

int main(){
    int length = 0;
    printf("Number of data: \n");
    scanf("%d", &length);
    int *bufferP = (int*)malloc(2*sizeof(int));
    int *bufferN = (int*)malloc(2*sizeof(int));
    int number = 0;
    for (int i = 0 ; i <= length ; i++){
        scanf("%d", &number);
        if(number < 0){
            if(*bufferN == NULL){
                printf("No more place");
                exit(0);
            }
            *bufferN= number;
            *bufferN++;
        }

        if(number >= 0){
            if(*bufferP == NULL){
                printf("No more place");

            }
            *bufferP = number;
            *bufferP++;
        }

    }

    int res =0;
    printf("tab negative : ");
    for (int i = 0; bufferN[i] != NULL; i++)
    {
        res = bufferN[i]; 
        printf("%d\n", res );
    }
    printf("tab positive : ");
    for (int i = 0; bufferP[i] != NULL; i++)
    {
        res = bufferP[i]; 
        printf("%d\n", res );
    }
}

我遇到了这些错误:

 In function ‘main’:
rev_S3_ptr.c:14:16: error: comparison between pointer and integer [-Werror]
    if(*bufferN == NULL){
                ^~
rev_S3_ptr.c:19:4: error: value computed is not used [-Werror=unused-value]
    *bufferN++;
    ^~~~~~~~~~
rev_S3_ptr.c:23:16: error: comparison between pointer and integer [-Werror]
    if(*bufferP == NULL){
                ^~
rev_S3_ptr.c:28:4: error: value computed is not used [-Werror=unused-value]
    *bufferP++;
    ^~~~~~~~~~
rev_S3_ptr.c:35:29: error: comparison between pointer and integer [-Werror]
  for (int i = 0; bufferN[i] != NULL; i++)
                             ^~
rev_S3_ptr.c:41:29: error: comparison between pointer and integer [-Werror]
  for (int i = 0; bufferP[i] != NULL; i++)

所以我的问题是:

  1. 缓冲区像标签一样工作,对吗?那么为什么我不能说如果指针为空它是满的并执行 *buffer ++ 呢?
  2. 在“No more place”处,我必须将缓冲区大小加倍,但我不知道该怎么做。

【问题讨论】:

  • 你熟悉 struct 吗?
  • 关于您的第一个问题,如果您看到C operator preference table,则代码*bufferN++ 与您编写bufferN++; *bufferN 几乎相同。这就是为什么编译器说你 error: value computed is not used 因为值 *bufferN 未被使用。

标签: c


【解决方案1】:

这个版本怎么样:

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

int main(){
    int length = 0;
    printf("Number of data: \n");
    scanf("%d", &length);
    int bufferP_size = 2, bufferP_loc = 0;
    int *bufferP = (int*)malloc(bufferP_size*sizeof(int));
    int bufferN_size = 2, bufferN_loc = 0;
    int *bufferN = (int*)malloc(bufferN_size*sizeof(int));
    int number = 0;
    for (int i = 0 ; i <= length ; i++) {
        scanf("%d", &number);
        if(number < 0) {
            if(bufferN_loc == (bufferN_size - 1)) {
                int *temp_buffer;
                printf("No more room in negative buffer, extending\n");
                bufferN_size *= 2; 
                temp_buffer = (int*)realloc(bufferN,bufferN_size*sizeof(int));
                if (temp_buffer == NULL) {
                    printf("Memory allocation failed, aborting\n");
                    free(bufferP);
                    free(bufferN);
                    exit(EXIT_FAILURE);
                }
                bufferN = temp_buffer;
            }
            bufferN[bufferN_loc++] = number;
        }

        if(number >= 0) {
            if(bufferP_loc == (bufferP_size - 1)) {
                int *temp_buffer;
                printf("No more room in positive buffer, extending\n");
                bufferP_size *= 2; 
                temp_buffer = (int*)realloc(bufferP,bufferP_size*sizeof(int));
                if (temp_buffer == NULL) {
                    printf("Memory allocation failed, aborting\n");
                    free(bufferP);
                    free(bufferN);
                    exit(EXIT_FAILURE);
                }
                bufferP = temp_buffer;
            }
            bufferP[bufferP_loc++] = number;
        }
    }

    int res =0;
    printf("tab negative : ");
    for (int i = 0; i < bufferN_loc; i++)
    {
        res = bufferN[i]; 
        printf("%d\n", res );
    }
    printf("tab positive : ");
    for (int i = 0; i < bufferP_loc; i++)
    {
        res = bufferP[i]; 
        printf("%d\n", res );
    }
    free(bufferP);
    free(bufferN);
    exit(EXIT_SUCCESS);
}

重大变化是:

  • 读入缓冲区时不要丢弃缓冲区指针的开头
  • realloc 是你扩展缓冲区的朋友
  • 当你到达缓冲区的末尾时,你不能使用指向缓冲区的指针来计算,你必须自己跟踪它有多大
  • 存储当前位置以及缓冲区大小,以便跟踪从何处读取和写入

【讨论】:

  • 对于健壮的代码,应该检查 (!=NULL) 调用 malloc()realloc() 的返回值并使用 realloc() 将返回值分配给“temp”变量和在分配给目标变量之前,在那里执行有效性检查。否则当realloc()失败时,原来分配的堆内存的指针会丢失,导致内存泄漏
  • 我已经在检查来自realloc 的返回值,并按照您的建议分配给一个临时变量。对malloc 的调用未修改原版 - 我同意他们应该检查 NULL 返回
【解决方案2】:

代码中存在以下问题:

  1. malloc 不会在分配的内存末尾插入 NULL。所以检查if(*bufferN == NULL) 将不起作用。指针会取消对内存的引用,并且可能会得到一个垃圾值。
  2. 出现错误rev_S3_ptr.c:14:16: error: comparison between pointer and integer [-Werror] if(*bufferN == NULL){ 是因为您将值 (*bufferN) 地址与 NULL(用于 nil 地址)进行比较。
  3. 代码rev_S3_ptr.c:19:4: error: value computed is not used [-Werror=unused-value] *bufferN++; 引发错误,因为只需要增加地址。尊重没有帮助。
  4. 语句bufferP[i] 表示*(bufferP+i),因此与NULL 比较时会出错。

【讨论】:

    【解决方案3】:

    考虑以下更改:

    #include <stdlib.h>
    #include <stdio.h>
    
    int main(){
        int length = 0;
        printf("Number of data: \n");
        scanf("%d", &length);
    
        int bufferP_cap = 2, bufferN_cap = 2;
        int bufferP_size = 0, bufferN_size = 0;
        int* bufferP = (int*)malloc(bufferP_cap * sizeof(int));
        int* bufferN = (int*)malloc(bufferN_cap * sizeof(int));
    
        int number = 0;
        for (int i = 0 ; i < length ; i++){  // '<' instead of '<='
            scanf("%d", &number);
            if(number < 0){
                if ( bufferN_size == bufferN_cap){
                    bufferN_cap *= 2;
                    bufferN = (int*)realloc(bufferN, sizeof(int)*bufferN_cap);
                }
                bufferN[bufferN_size++] = number;
            }
            else {
                if ( bufferP_size == bufferP_cap){
                    bufferP_cap *= 2;
                    bufferP = (int*)realloc(bufferP, sizeof(int)*bufferP_cap);
                }
                bufferP[bufferP_size++] = number;
            }
        }
    
        printf("tab negative : ");
        for (int i = 0; i < bufferN_size; i++)
            printf("%d\n", bufferN[i]);
    
        printf("tab positive : ");
        for (int i = 0; i < bufferP_size; i++)
            printf("%d\n", bufferP[i]);
    
        free(bufferN);
        free(bufferP);
    }
    

    【讨论】:

    • 您可能会再次阅读这部分问题:'在“没有更多的地方”,我必须将缓冲区的大小加倍,但我不知道该怎么做。' 如果没有动态内存分配,这可能不会真正实现。
    • 感谢这大大改进了代码,但是当我执行时出现“分段错误(核心转储)”
    • @Gerhardh,谢谢,我真的错过了这一点。更新了代码以支持 realloc
    • @grapes 请检查 malloc / realloc 失败,不要强制返回并使用“sizeof(*bufferN)”而不是“sizeof(int)”,因为 bufferN 的类型更改会导致无声的错误。
    • @Tom's,谢谢。修复了故障。关于强制转换返回类型 - 我知道不强制转换的原因,但我在 VS 上测试了这个示例,这需要我这样做。 sizeof(*p) 无疑是个不错的选择,但在这个例子中,我不想将点声明和初始化跨越到 2 行(紧凑的例子很重要),而使用像 t* a = malloc (100*sizeof(*a)) 这样的构造看起来是恶意的。
    【解决方案4】:

    让我们从头开始:

    int *bufferP = (int*)malloc(2*sizeof(int));
    int *bufferN = (int*)malloc(2*sizeof(int));
    

    这是正确的,但你不应该强制转换(不要使用(int*))malloc() 的结果。搜索“投射 malloc 结果”。另外,如果您打算让它按需增长,为什么还要分配 2 个插槽呢?为什么不是 10 或 100?为什么不只有一个?

    让我们继续吧:

    if(*bufferN == NULL){
      printf("No more place");
      exit(0);
    }
    

    在这里,您应该考虑 bufferN,而不是它所指向的内容。 NULL 用于检查指针本身,而不是指针所指向的值;这就是编译器抱怨的原因。无论如何请注意,bufferN 永远不会自动更改值,因此不要尝试比较它以了解缓冲区是否已满。唯一的办法就是数一数你放了多少东西。

    最后:

            *bufferN= number;
            *bufferN++;
    

    您正确地将数字存储在指针指向的位置。也许OK。但是在下一行你想增加指针,但你也取消引用它。这没有错,但不寻常——事实上编译器再次抱怨。

    缓冲区就像标签一样工作,对吧?

    错了。缓冲区是一个内存区域,由您操作,可能使用指针,而指针又由您操作。您必须跟踪发生的情况。

    在“没有更多的地方”,我必须将缓冲区的大小加倍,但我不知道该怎么做。

    您为此使用 realloc()。

    我不想为你完成整个工作,但我可以解释你需要什么。我讲一个buffer,其他的也一样。

    首先,像现在一样分配一个缓冲区,但只分配一个插槽。并引入一个计数器(一个 int)来计算缓冲区中有多少个数字。计数器最初为 0。

    当用户输入一个数字时,你可以这样存储它:

    bufferN[counterN] = number;
    counterN++;
    

    此时,您知道缓冲区已满。我们从只有一个(和空闲)插槽的缓冲区开始,现在我们没有......为什么不调整缓冲区的大小以再次添加一个空闲插槽?我们知道缓冲区中有counterN 项,缓冲区已满,所以我们想要一个带有counterN+1 个槽的新缓冲区; realloc() 可以做我们需要的。

    请注意,要在缓冲区中读取和写入,语法 bufferN[...] 既简单又安全,因为您现在总是(通过 counterN)缓冲区有多大,它包含多少项目。而且您不会触摸指针本身。

    还有其他方法可以做到这一点,但这是一种 - 不是最干净但合理的。我希望这会有所帮助。

    编辑:在看到另一个回复后,我意识到要求是将缓冲区大小加倍。我上面的建议不符合这个要求。对不起...为您做更多工作...我们(您)不仅要计算添加到缓冲区的项目,还要计算缓冲区的大小。简单地说,另一个要管理的整数变量。好吧,有一个技巧可以避免这种情况,但还是别管它了 :-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 2021-01-11
      • 2017-10-13
      • 2021-01-13
      • 1970-01-01
      相关资源
      最近更新 更多