【问题标题】:Using C Dynamic allocation using malloc and realloc使用 C 动态分配使用 malloc 和 realloc
【发布时间】:2013-12-26 17:09:52
【问题描述】:

我在使用 C 中的 malloc 和 realloc 函数并使用 2 个单独的函数在其中保存值时遇到了一些麻烦

请注意,我最近才开始使用 c,并且代码中可能存在多个错误,但我的主要关注点是将值保存到结构中

我需要能够将多个值保存到单个数组中。

这些是我的功能

int ArrayCreate() {

  int *pt;

  pt = (ASet *)calloc(1,sizeof(ASet));
  pt == NULL;

  return *pt;
}

//possible 2nd *
void ArrayAdd(ASet **arrayStruct, int x) {

  ASet *pt = NULL;

  *arrayStruct=realloc(*arrayStruct,1*sizeof(ASet));
  pt = arrayStruct;
  *arrayStruct->value = x;

  free(pt);
}

我主要有

ASet *arr_pt = NULL;

创建数组

 printf("a new array is created \n"); 
 arr_pt = ArrayCreate();        

 break;

向数组中添加一些东西

 printf("Enter integer \n");            
 scanf("%d",&x);

 ArrayAdd(arr_pt,x);

 while (getchar() != '\n') {
   continue;
 }

 break;

也为了测试我添加了这个,但我不确定

void ArrayShow(ASet *arrayStruct) {

  ASet *pt = arrayStruct;

  //printf("%d \n", pt[0].value);
  printf("%d \n", pt[1].value);
  printf("%d \n", pt[2].value);
  printf("%d \n", pt[3].value);
  printf("%d \n", pt[4].value);
}

我只需要知道如何使用 realloc 和 calloc 正确保存,但由于某种原因 pt[0] 被忽略并且 p[1] 之后的任何东西都是垃圾

【问题讨论】:

  • there are multiple bugs in the code 是什么意思?
  • 那么精益求精如何使用调试器。那不是我们的工作。
  • 更具体地说:您期望的输出是什么,您得到的结果与此有何不同?
  • 请把整个main函数改写成一个块!并使用一些 cmets!
  • 我只需要知道如何使用 realloc 和 calloc 正确保存但由于某种原因 pt[0] 被忽略并且 p[1] 之后的任何东西都是垃圾

标签: c realloc


【解决方案1】:

简单示例

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

typedef int Item;

#define PRN_Item "%d"

typedef struct da {
    size_t size;
    Item *value;
} ASet;

ASet *ArrayCreate(void){
    return calloc(1, sizeof(ASet));
}

void ArrayAdd(ASet *arrayStruct, Item x){
    ASet *ap = arrayStruct;
    Item *p = ap->value;
    p = realloc(p, (ap->size + 1)*sizeof(Item));
    if(p){
        ap->value = p;
        ap->value[ap->size] = x;
        ap->size += 1;
    } else {
        perror("realloc");
        exit(1);
    }
}

void ArrayShow(ASet *arrayStruct) {
    Item *v = arrayStruct->value;
    size_t n = arrayStruct->size;
    while(n--){
        printf(PRN_Item " \n", *v++);
    }
}

void ArrayDrop(ASet *arrayStruct){
    free(arrayStruct->value);
    free(arrayStruct);
}

int main(){
    ASet *arr_pt = ArrayCreate();

    if(!arr_pt){
        perror("ArrayCreate");
        exit(1);
    }
    printf("a new array is created \n");
    while(1){
        int x;
        printf("Enter integer \n");            
        if(1!=scanf("%d", &x))
            break;
        ArrayAdd(arr_pt, x);
    }
    ArrayShow(arr_pt);
    ArrayDrop(arr_pt);
    return 0;
}

【讨论】:

    【解决方案2】:

    编辑:

    下面这行是注释,所以没有被执行:

    //printf("%d \n", pt[0].value);
    

    而你的 pt 类型错误,这就是你得到垃圾的原因

    /* 将 Aset 替换为 int 并且 SIZE 必须是定义的大小 */ pt= calloc(SIZE, sizeof(int));

    pt == NULL 是一个比较表达式而不是一个判断语句:

    pt = NULL // assining NULL to pt
    

    ArrayCreate 必须返回指向数组第一个元素的指针,而不是指向的地址的值:

    int *ArrayCreate() {
    
    int *pt;
    
    pt = calloc(SIZE,sizeof(int));
    pt == NULL;
    
    return pt;
    }
    

    【讨论】:

    • 不要投malloc():它不是必需的,有潜在危险,而且最重要的是:它会使 OP 感到困惑。
    • 感谢您的帮助,我更改了 calloc 函数并删除了 pt==NULL(我现在才意识到该行是多余的)
    • 但还是一样
    • @user3137308 将您的完整代码粘贴到 pastebin.com 并提供链接
    • 不,在C 中,void 指针可以分配给 任何 指针类型(函数指针除外),而无需强制转换。
    【解决方案3】:

    您的代码有一些问题:

    • 而不是pt == NULL; 你应该做pt = NULL 因为使用ptNULL 之间的第一个比较并且不会将NULL 分配给pt
    • 这个pt = arrayStruct 是非法的,因为ptASet 类型,而arrayStruct**ASet 类型你应该用pt = *arrayStruct 替换它
    • 这里*arrayStruct-&gt;value = x;就像你要求将成员value的地址更改为x你应该改为*(arrayStruct)-&gt;value = x;

    【讨论】:

      【解决方案4】:

      问题:

      1. 没有关于数组大小的可见记录,因此您无法确定要重新分配的大小。

      2. 您的ArrayCreate() 函数应该返回一个指向该结构的指针。 pt == NULL; 语句什么也不做;您的编译器应该警告您一条无效的语句。因为您返回的是 int 而不是指针,所以您正在泄漏内存。

      3. 您的 ArrayAdd() 函数不知道要分配多少空间(再次点 1)。代码不应使用free(pt)realloc() 可能返回了指向同一位置或不同位置的指针,但无论哪种方式,它都处理了旧内存。


      我没看懂1、2;所以你说pt 应该是*pt?这将产生什么影响以及 3 关于多少空间的部分?

      考虑ArrayCreate() 函数——就像目前写的那样:

      int ArrayCreate() {
      
        int *pt;
      
        pt = (ASet *)calloc(1,sizeof(ASet));
        pt == NULL;
      
        return *pt;
      }
      

      首先,代码混淆了它是在处理int 还是ASet 类型。它似乎正在分配一个具有 1 个(归零)ASet 元素的数组,但将其分配给 int *。下一行应该是if 语句。代码应该是这样的:

      ASet *ArrayCreate(void)
      {
          ASet *pt = (ASet *)calloc(1, sizeof(ASet));
          if (pt == NULL)
          {
              fprintf(stderr, "Memory allocation failed!\n");
              exit(1);
          }
          return pt;
      }
      

      我不反对从calloc() 返回的演员表,只要您向我保证您始终使用选项进行编译,这样如果您忘记包含&lt;stdlib.h&gt;,您的代码将无法编译。例如,我主要使用 GCC,并且总是使用以下选项进行编译:

      gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror ...
      

      如果你不那样编译,那么你最好省略演员表。正如您会注意到的,还有其他人对从malloc() 等人的回报问题不灵活。 (我什至在其他人的 SO 代码上使用这些选项;有时让他们的代码编译干净是很痛苦的。)

      错误处理或内存分配是最简单的可用选项——报告错误(在标准错误上,请注意)并退出。对于如何处理错误,您可以随心所欲地发挥创意,但快速失败在许多情况下都有很多优点。

      现在,我显示的代码或多或少是连贯的,但您知道ASet 值数组中有一个元素的唯一方法是......因为它只是用一个元素创建的。

      当你第一次调用ArrayAdd()时,你可以假设数组中有一个元素,但是当你再次调用它时,你不知道数组中有多少行,所以你仍然会为数组分配 2 个元素,即使这是一个空操作。您需要以某种方式知道数组中有多少元素。

      如目前所写:

      void ArrayAdd(ASet **arrayStruct, int x) {
      
        ASet *pt = NULL;
      
        *arrayStruct=realloc(*arrayStruct,1*sizeof(ASet));
        pt = arrayStruct;
        *arrayStruct->value = x;
      
        free(pt);
      }
      

      您获取传递给您的(指向该)数组的(指针),并将该数组的大小调整为一个元素。 pt = arrayStruct; 行应该生成编译警告;您将ASet ** 分配给ASet *;它们是非常不同的类型。 free(pt) 是完全错误的——不可救药的错误。你需要这样的代码:

      void ArrayAdd(ASet **arrayStruct, size_t new_size, int x)
      {
          ASet *pt = realloc(*arrayStruct, new_size * sizeof(ASet));
          if (pt == 0)
          {
              fprintf(stderr, "Memory allocation failed!\n");
              exit(1);
          }
          pt[new_size-1].value = x;
          *arrayStruct = pt;
      }
      

      代码再次因内存分配失败而快速失败。在知道这样做是安全的之前,请注意不要破坏*arrayStruct。它将x 分配给数组最后一个元素的value 成员。请注意,realloc() 不会将它提供的额外内存归零。代码也不知道之前的数组有多大;它无法判断数组是在增长还是在缩小——只有调用代码才知道该信息。

      所以,这不是一段很好的代码,但它比以前的代码要好。

      【讨论】:

      • 我没看懂 1, 2 所以你说的 pt 应该是 *pt?这将产生什么影响以及 3 关于我不了解多少空间的部分
      • 感谢这有很大帮助,但问题是我不能使用可变长度数组,所以我不能使用 size
      • @user3137308 他没有谈到 VLA。当您尝试扩展内存时需要新的大小,因为由 realloc 确保。
      猜你喜欢
      • 2018-07-13
      • 1970-01-01
      • 1970-01-01
      • 2020-04-13
      • 2016-01-10
      • 2018-10-16
      • 1970-01-01
      • 2011-05-09
      • 2023-03-16
      相关资源
      最近更新 更多