在C语言中初始化整型指针数组

17
我对在C语言中使用指针有一些困惑和问题。我已经提供下面的示例代码,以便更容易地理解它。请注意这些代码之间的差异。如果您对其理解有问题,请给予反馈。
这不起作用。
#include <stdio.h>
#include <stdlib.h>

void process() {
    int *arr;
    arr=(int*)malloc(5*sizeof(int));
    arr=(int*){3,1,4,5,2};
    for(int z=0;z<5;z++) {
        printf("%d ",arr[z]);
    }
    printf("\n");
}

int main() {
    process();
    return 0;
}

但这样也可以工作。

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

void process() {
    int *arr;
    arr=(int*)malloc(5*sizeof(int));
    arr=(int[]){3,1,4,5,2};
    for(int z=0;z<5;z++) {
        printf("%d ",arr[z]);
    }
    printf("\n");
}

int main() {
    process();
    return 0;
}

这也可以工作。为什么呢?因为我没有在这里分配内存。

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

void process() {
    int *arr;
    arr=(int[]){3,1,4,5,2};
    for(int z=0;z<5;z++) {
        printf("%d ",arr[z]);
    }
    printf("\n");
}

int main() {
    process();
    return 0;
}
为什么它们不一样?
    arr=(int*){3,1,4,5,2};
    arr=(int[]){3,1,4,5,2};

有没有其他方式来初始化指向整数的数组,而不是使用单独分配的方式?

arr[0]=3;
arr[1]=1;
arr[2]=4;
arr[3]=5;
arr[4]=2;

如何获取指针的内存分配大小/数量,以便我可以像静态使用for(int z=0;z<5;z++) {一样使用for(int z=0;z<NUM;z++) {

非常感谢任何回答。

提前致谢。


您正在使用 gcc 吗?arr=(int[]){3,1,4,5,2}; 我认为它不是有效的 C++。 - Jesse Good
是的,我正在使用gcc编译器。这不是有效的C++吗?arr=(int[]){3,1,4,5,2}; - shibly
是的,它们被称为复合字面量,gcc在C++中作为扩展接受它们(尝试使用-pedantic编译,你应该会得到一个警告)。 - Jesse Good
3
你的代码中有stdlib.h和iostream库,还有namespace和malloc函数。这是哪种语言?是C++吗? - ScarletAmaranth
@ScarletAmaranth,我移除了iostream和namespace。这是C语言。谢谢。 - shibly
我们知道以下两种声明是不允许的: int *ptrInt = {23,44,65,555}; char *ptrChar = {'2','3'}; 但是为什么下面这种声明允许: char *str2 = "Hello"; - Mahesha Padyana
4个回答

19

在前几个例子中,malloc 调用分配了一块内存,并将指向该内存的指针赋给 arr。一旦再次对 arr 进行赋值操作,指针值就会被覆盖,你就无法追踪到已分配的内存,也就是泄漏了内存。这就是一个 bug。

换句话说,如果你使用 malloc() 分配了一块内存,那么你可以使用数组语法将数据写入其中(例如):

int* arr = (int *) malloc(sizeof(int) * 5);
for (int i=0; i<5; ++i)
    arr[i] = i;

但是你不能直接为arr分配其他内容,否则你就会失去那块内存的指针。当你使用malloc()分配一个块时,不要忘记在不再需要它时使用free()进行删除。

数组不是指向整数的指针;它是一个数组。当你将数组名作为参数传递给一个接受指针作为参数的函数时,数组名被说成“衰减为指针”,但它们并不是同一件事情。

关于你最后的问题:这实际上是数组和指向类型的指针之间的差异:编译器知道数组的大小,但它不知道由任意类型的指针指向的块的大小。答案很遗憾,是不行的。

但既然你正在编写C++代码,而不是C代码,你不应该使用数组:使用`std::vector'!它们知道自己的长度,而且可以扩展。


理解STL的向量对于初学者来说太难了。 - Stepan Yakovenko
@Ernest Friedman-Hill,我没有理解清楚,我发布的代码有 bug 吗?哪一段有问题? - shibly
@user643540 -- 我希望你是在开玩笑。这比掉木头还容易。 - Ernest Friedman-Hill
@ErnestFriedman-Hill,您是在告诉我不要使用malloc吗?还是应该如何使用malloc,然后分配值? - shibly
@prime -- 你绝对可以使用malloc,只要你使用正确;请看我的编辑。 - Ernest Friedman-Hill
显示剩余3条评论

7
当你执行 ptr = {1,2,3,4,5} 时,你让 ptr 指向数据段中的常量数组 {1,2,3,4,5} 所在的内存,因此会造成内存泄漏。如果你想初始化你的内存,在分配内存后,请写:ptr[0]=1; ptr[1]=2; 以此类推。如果你想要复制数据,请使用 memcpy

我不想像我之前说的那样逐个赋值。 - shibly
你想如何填充已分配的内存?也许你只想从常量数组中读取数据?那么只需要说:ptr = {1,2,3,4,5},而不需要使用alloc()或new[]。但是你将没有机会修改这个数组。 - Stepan Yakovenko
你的回答有点令人困惑。这里的ptr是数组还是指针?你能否请贴上带有ptr的完整C代码? - shibly
1
指针和数组在C语言中是相同的。如果您愿意,请通过Skype联系我(stiv.yakovenko),我将尝试使用MSPaint中的图表进行解释。 - Stepan Yakovenko
4
抱歉反驳你,但在C语言中,数组和指针是两个非常不同的东西。如果你不相信,请尝试运行以下代码:int a[3]; printf("sizeof(a) = %d\n", (int)sizeof(a)); printf("sizeof(a + 0) = %d\n", (int)sizeof(a + 0)); 第一个printf()输出12,第二个输出8。为什么?因为在a + 0中,数组标识符衰变为指针,这与数组非常不同。 - cmaster - reinstate monica
显示剩余2条评论

2
逗号分隔的值列表是初始化数组的一种构造方式。但它不适用于初始化指向数组的指针。这就是为什么你需要使用 (int[]) - 它告诉gcc创建一个未命名的整数数组,并用提供的值进行初始化。
除非你确实想要,否则gcc不会让你失去 arr 是一个数组的信息。这就是为什么你需要一个强制类型转换。最好将 arr 声明为数组,而不是指针。你仍然可以将其传递给接受指针的函数。但是gcc不会让你泄漏内存使用malloc:
error: incompatible types when assigning to type ‘int[5]’ from type ‘void *

如果你需要一个既可以是数组又可以是指向分配内存的指针的变量,那么创建另一个变量来实现这个需求。最好还是创建一个接受指针作为参数的函数,并将其传递给数组或指针。


0
我觉得我可以进一步澄清被接受的答案。
当你用例如初始化一个数组时。
int arr1[]={1,2,3,4,5};

这将在堆栈上保留内存,用值{1,2,3,4,5}填充它,并将arr设置为指向该内存块的指针。
当您使用new初始化数组时:
arr2 = new float[5];

这将在堆上分配内存,并返回指向该内存块的指针。如果您随后调用:
arr2 = arr1;

你会丢失为arr2分配的堆内存的地址。这就是内存泄漏。
正确的做法是使用memcpy将栈中的arr1值复制到堆中。
memcpy(arr2, arr1, sizeof(arr1)); // src, dest, #bytes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接