【问题标题】:How can I change what a pointer points to within a function in C?如何更改 C 函数中指针指向的内容?
【发布时间】:2021-11-19 01:33:22
【问题描述】:

我正在尝试编写一个可调整大小的数组,它会在满时展开。所有功能都在工作,但调整大小的功能却不行。

int main(void)
{
   int arr[4];
   int *ptr = arr;
   initializeEmptyArray(ptr);
   insertAtIndex(ptr, 0, 4);
   insertAtIndex(ptr, 0, 3);
   insertAtIndex(ptr, 0, 2);
   insertAtIndex(ptr, 0, 1);
   resizeArray(&ptr);
   for (int i = 0; i < capacity; i++)
   {
       printf("%i", arr[i]);
   }
}

这会启动我的数组 [1,2,3,4],然后调用调整大小的数组来测试它。

void resizeArray(int **arr)
{
    int *newArr = (int *)malloc(capacity * 2 * sizeof(int));
    for (int i = 0; i < capacity; i++)
    {
        newArr[i] = (*arr)[i];
    }
    for (int i = capacity; i < capacity * 2; i++)
    {
        newArr[i] = EMPTY;
    }
    free(*arr);
    *arr = newArr;
}

问题是arr 的值在我打印时不会更改为 [1,2,3,4,-1,-1,-1,-1] (-1 代表空)。如何更改指针以指向这个新数组?

Capacity 表示数组支持的元素数量,初始为 4 EMPTY 定义为 -1,表示数组中的一个空槽。

【问题讨论】:

  • 请更新问题,使其成为minimal reproducible example。什么是容量,EMPTY,insertAtIndex,Missing 包括。
  • 这是未定义的行为。您的初始数组在堆栈上,并且最初没有使用 malloc 分配。因此,当您的 resize 函数尝试在其上调用 free 时,未定义的行为。我很惊讶它没有崩溃。
  • 这是我的第一个问题,感谢您的提示。我调整了你的要求。谢谢
  • 有道理,但即使没有free(),结果也是一样的。修复它是一个悲伤的尝试。
  • 您正在更新 ptr 以指向一个新数组,然后打印 arr(旧的局部变量数组)。

标签: arrays c pointers memory


【解决方案1】:

代码的两个主要问题是arr 分配在main() 的堆栈上,然后您将free() 分配在resizerArray() 中。这是一个缺陷,我修复了在main() 中分配arr 的堆。在您的循环中,您打印arr[i],但将ptr 传递给已更新的resizeArray(),但arr 仍指向现在已释放的内存。我通过消除ptr 变量解决了这个问题:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define EMPTY 0

void resizeArray(int **arr, size_t capacity) {
    int *newArr = malloc(2 * capacity * sizeof(int));
    // for (int i = 0; i < 2 * capacity; i++) {
    //  newArr[i] = i < capacity ? (*arr)[i] : EMPTY;
    // }
    memcpy(newArr, *arr, capacity * sizeof(int));
    memset(newArr + capacity, EMPTY, capacity * sizeof(int));
    free(*arr);
    *arr = newArr;
}

int main(void) {
    size_t capacity = 4;
    int *arr = malloc(capacity * sizeof(int));
    arr[0] = 1;
    arr[1] = 2;
    arr[2] = 3;
    arr[3] = 4;
    for (int i = 0; i < capacity; i++) {
        printf("before: %d\n", arr[i]);
    }
    resizeArray(&arr, capacity);
    capacity *= 2;
    for (int i = 0; i < capacity; i++) {
        printf("after: %d\n", arr[i]);
    }
}

我注释掉 resizeArray 中的循环,以便您了解如何执行此操作。代码打印:

before: 1
before: 2
before: 3
before: 4
after: 1
after: 2
after: 3
after: 4
after: 0
after: 0
after: 0
after: 0

resizeArray() 和调用代码都必须知道因子 2。这不是一个伟大的设计。也许通过新旧容量?或者传入size_t *capacity,如果你想硬编码resizeArray()中的因子,可以更新它?记得检查malloc()的返回值,确保没有失败。

有关调整堆分配内存大小的标准方法,请参阅realloc(),有关如何获取预初始化内存的信息,请参阅calloc()

【讨论】:

  • 你能解释一下这些台词吗? for (int i = 0; i
  • 我遇到了另一个问题。如何在另一个接收 *arr 作为参数的函数中调用 resize 函数?当我这样做时,它会正确调整大小,但添加的插槽会变成垃圾值,而不是之前设置的 EMPTY。 void appendInTheEnd(int *arr, int value) { if (size == capacity) { resizeArray(&amp;arr, capacity); } }
  • @LorenzoBattistela 在您的原始代码中,您有两个循环首先从 0 到容量,然后从容量到 2 * 容量。我将它们组合成一个循环,从 0 到 2 * 容量。前半部分从 arr 复制,后半部分将其初始化为 EMPTY。它使用三级运算符condition ? expression when true : expression when false,所以整个事情都返回一个表达式。如果 appendInTheEnd() 需要改变 *arr,那么就像 resikzeArray() 你需要传入 int **arr。
  • @LorenzoBattistela 请为有用的答案投票并接受他的最佳答案,这样我们就知道你们都准备好了。如果需要,请打开一个新问题。
  • 是的,您的回答对我帮助很大,但据我所知,我没有支持的声誉。现在我可以在 append 内部调用 resizeArray 来调整数组的大小,但是函数的另一部分(那个 assings:arr[size] = value; 不起作用。如:预期结果:1、2、3、4、5、-1、- 1, -1 结果:1, 2, 3, 4, -1, -1, -1, -1 感谢您的帮助
【解决方案2】:

您无法调整数组的大小。它的大小是固定的。

所以如果你想要一些可以调整大小的东西:

int arr[4]; --> int* arr = malloc(4 * sizeof *arr);

顺便说一句:

你好像漏掉了这样一行:

capacity = 2 * capacity ;

【讨论】:

  • 没错,我无法调整数组的大小。但是您可以创建一种方法,当数组已满时,您创建一个大小加倍的副本,这将转换为一个可调整大小的数组。
  • @LorenzoBattistela 不,您不能为 arr 分配新值。就这么简单。 *arr = newArr; 是非法的
  • 哦,现在我明白了。
【解决方案3】:

看看"realloc",你的问题听起来很完美

【讨论】:

  • 不 - arr 是一个数组 - 不能更改
  • @4386427:resizeArray() 实现使用了 malloc,所以我暗示在实现时不要首先使用数组
【解决方案4】:

您不能使用自动存储持续时间调整数组的大小。您可以对已分配存储持续时间的数组执行此操作。

所以你应该删除 main 中的数组声明并写入

int *ptr = malloc( 4 * sizeof( int ) );

int *ptr = malloc( capacity * sizeof( int ) );

另外,您忘记更改变量capacity 的值。我想它没有被声明为常量变量。

在这种情况下,函数resizeArray 可以如下所示

int resizeArray( int **arr )
{
    int *newArr = realloc( *arr, capacity * 2 * sizeof(int));

    int success = newArr != NULL;

    if ( success ) 
    {
        *arr = newArr;

        for (int i = capacity; i < capacity * 2; i++)
        {
            newArr[i] = EMPTY;
        }

        capacity *= 2;
    }

    return success;
}

请注意,数组的重新分配可能会失败。因此,该函数应该向调用者发出重新分配是否成功的信号。

另外,将变量 capacity 用作全局变量也不是一个好主意。

你可以写main

int capacity = 4;
int *ptr = malloc( capacity * sizeof( int ) );

// ...

然后像这样调用函数

resizeArray( &ptr, &capacity );

在这种情况下,函数将如下所示

int resizeArray( int **arr, int *capacity )
{
    int *newArr = realloc( *arr, *capacity * 2 * sizeof(int));

    int success = newArr != NULL;

    if ( success ) 
    {
        *arr = newArr;

        for (int i = *capacity; i < *capacity * 2; i++)
        {
            newArr[i] = EMPTY;
        }

        *capacity *= 2;
    }

    return success;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-31
    • 2012-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多