【问题标题】:How to reassign pointer to smaller array in C?如何在C中重新分配指向较小数组的指针?
【发布时间】:2019-10-08 09:18:06
【问题描述】:

有没有办法在 C 中重新分配指向数组的指针,使其指向更小的数组?例如,如果我有一个指针 ptr 最初指向一个大小为 3 的数组 s,并且还存在一个大小为 2 的数组 s1,我是否可以重新分配 ptr 使其指向 @987654325 @ 并因此指向一个较小的数组?

我尝试了以下代码:

void changePtr(double* ptr);

int main()
{
    double *ptr;
    ptr = (double*)malloc(sizeof(double)*3);
    double s[3]={1,2,3};
    ptr=s;
    changePtr(ptr);

    return 0;
}

void changePtr(double* ptr) {

    double s1[2]={4,5};
    free(ptr);
    ptr = (double*)malloc(sizeof(double)*2);
    ptr=s1;
}

但是当我在 VIsual Studio 中运行它时,我在 free(ptr) 收到一个错误,上面写着 Debug Assertion failed! Expression: _CrtIsValidHeapPointer(block)

这是为什么?

编辑

新代码是:

void changePtr(double* ptr);

int main()
{
    double *ptr;
    ptr = (double*)malloc(sizeof(double)*3);
    double *s;
    s = (double*)malloc(sizeof(double)*3);
    s[0]=1; s[1]=2; s[0]=3; 
    for (int i=0; i<3; i++){
        ptr[i]=s[i];
    }

    changePtr(ptr);

    for (int i=0; i<2; i++){
        printf("%f\t", ptr[i]);
    }


    free(ptr);
    free(s);

    return 0;
}

void changePtr(double* ptr) {
    free(ptr);
    double *s1;
    s1 = (double*)malloc(sizeof(double)*2);
    s1[0]=11; s1[1]=12;

    ptr = (double*)malloc(sizeof(double)*2);

    for (int i=0; i<2; i++){
        ptr[i]=s1[i];
    }
}

但是当我在调用changePtr 后打印出ptr 的值时,我得到了像-1456815990147....1 这样的垃圾值。这是为什么呢?

【问题讨论】:

  • changePtr() 中的最后一行看起来很可疑。您正在分配一个指向本地创建的数组的指针。当函数返回时,数组将超出范围,因此您指向的内存位置不属于您的程序。最好的办法是附加一个调试器并逐步运行程序。
  • 我将新代码粘贴到 OP 中。我现在在ptr 中得到垃圾值。这是为什么呢?
  • 在 printf 中使用 %f 修饰符,尝试使用 %lf 修饰符并再次检查结果(%f 用于浮点数,双打需要 %lf)。
  • 我仍然用%lf得到垃圾值
  • 您是否尝试过在函数返回之前在函数内使用 printf?你还会得到垃圾值吗?

标签: c arrays pointers dynamic heap-memory


【解决方案1】:

好吧,当你这样做时

double s[3]={1,2,3};

那块内存不是你管理的,所以你不能释放它。只有在使用 malloc 或 calloc(即动态分配的内存)分配内存时才能使用 free。此外,您还有内存泄漏,因为

ptr=(double*)malloc(sizeof(double)*3); // here you allocate memory 
...
ptr = s; // here you change the pointer address but allocated memory is never freed

一种解决方案是使用 for 循环将值从 s 复制到 ptr,并在 changePtr 中执行相同操作以将值从 s1 复制到 ptr。

【讨论】:

  • 我将新代码粘贴到 OP 中。我现在在ptr 中得到垃圾值。这是为什么呢?
  • 在函数 changePtr(double* ptr) 中释放内存,然后在不同的位置分配内存。但是,在 main 函数中 ptr 仍然指向旧地址。我认为一个解决方案是在 changePtr(double &ptr) 中使用 & 运算符。因此 ptr 是 main 中 ptr 的引用,通过在 Changeptr 函数中更改它也将在 main 函数中修改它
【解决方案2】:

编辑 1

你原来的问题:

简短回答:是的,您可以在 C 中重新分配指向较小数组的指针。

长答案:简短的答案具有误导性。数组也是 C 中的简单指针。为了更好地理解这个概念,您可能需要阅读 this thread,尤其是查看 this answer


问题是您尝试取消分配stack 上的内存。

每当你创建一个局部变量,à la int a = 5,它被压入堆栈,也就是说,这个变量在堆栈上分配内存,在函数调用 (main()) 结束后,内存被释放 -这一切都是自动发生的!

你的情况是这样的:

// memory is allocated automatically on stack for the local variable "s"
double s[3]={1,2,3};

// assign the stack address of "s" to "ptr"
ptr = s;

// de-allocate the managed stack address of "s", which is NOT allowed!
free(ptr);

创建动态内存,例如通过malloc,另一方面发生在heap内存中,需要由程序员管理,即分配(malloc())和取消分配(free())内存是允许的并且必须完成非常小心。

因此,在您的程序中,当它到达free(ptr); 这一行时,断言失败,因为目标内存地址不符合要求 -> IsValidHeapPointer: No ptr 不是有效的堆指针,因为它在该点保存s 变量的堆栈地址。 :)


编辑 2

当我在调用 changePtr 后打印出 ptr 的值时,我得到了像 -1456815990147....1 这样的垃圾值。这是为什么呢?

因为,你先在changePtr(ptr)中释放了ptr的内存,也就是说ptr的内容被写入了一些“垃圾”值。

然后在这里分配新内存并将其分配给ptr

ptr = (double *) malloc(sizeof(double) * 2); 

在此之后,您通过ptr(即ptr[i] = 12)所做的更改对ptr 持有的先前地址没有影响。因此,只需删除 free(ptr) 和上面的行,就不需要它们了。


编辑 3

那么ptr 现在只包含 2 个值,对吗?在我删除你提到的那一行,然后打印出 ptr 中的值之后,它显示 ptr[0] 和 ptr[1] 的正确值,然后是 ptr[2] 的垃圾值。

正确。 ptr[2] 之前已被释放,因此除非您为该地址分配新值,否则它将仍然是垃圾。释放堆内存后也要小心。您不应使用指针访问内存或为其分配新值。在你调用free 之后考虑你的指针“void”。

当我尝试用 printf("%d", sizeof(ptr)) 打印它的大小时,它显示 8 并且 printf("%d", sizeof(ptr)/sizeof(ptr[0]) 显示1.

ptr 是一个指针。 sizeof(ptr) 返回8 字节,这是系统中指针所保存的地址大小。所以,这不是数组的大小......此外,在运行时确定指针的大小(指向数组并作为引用传递给函数 - 就像你所做的changePtr(ptr))是programmatically not possible,你如果要执行一些循环操作,则必须将数组大小显式传递给函数。

【讨论】:

  • 我将新代码粘贴到 OP 中。我现在在ptr 中得到垃圾值。这是为什么呢?
  • @user5739619 更新了我的答案。请访问我在编辑 1 中提供的链接。此外,您可以在这里找到关于 pointers 的精彩文章,位于 C:beginnersbook.com/2014/01/c-pointers
  • 感谢您的链接。那么ptr 现在只包含 2 个值,对吗?在我删除你提到的那一行,然后打印出ptr 中的值后,它会显示ptr[0]ptr[1] 的正确值,然后是ptr[2] 的垃圾值。当我尝试用printf("%d", sizeof(ptr)) 打印它的大小时,它显示为8 而printf("%d", sizeof(ptr)/sizeof(ptr[0]) 显示为1。
  • 因此,如果我先执行free(ptr),然后执行ptr[i]=s1[i],则会重新分配ptr 指向的地址,对吗?如果是这样,为什么要在不删除ptr = (double *) malloc(sizeof(double) * 2)的情况下这样做“对ptr持有的先前地址没有影响”?
  • @user5739619 更新了我的答案。您应该重新阅读我的 Edit 2Edit 3。我强烈建议您彻底阅读指针。然后,您将能够自己回答所有问题,相信我。 :)
猜你喜欢
  • 2019-05-13
  • 2014-02-18
  • 1970-01-01
  • 1970-01-01
  • 2010-09-25
  • 1970-01-01
  • 2011-12-04
  • 2022-01-15
  • 2013-03-02
相关资源
最近更新 更多