我在一些看起来像这样的不同函数中有一些代码:
void someFunction (int *data) {
data = (int *) malloc (sizeof (data));
}
void useData (int *data) {
printf ("%p", data);
}
int main () {
int *data = NULL;
someFunction (data);
useData (data);
return 0;
}
someFunction ()
和useData ()
在单独的模块(* .c文件)中定义。
问题在于,虽然malloc工作正常,并且分配的内存在someFunction
中可用,但一旦函数返回,相同的内存就不可用。
可以看到程序的示例运行here,输出显示各种内存地址。
有人可以向我解释一下我在这里做错了什么,以及我如何让这段代码发挥作用?
int **data = NULL; //used for 2D array
我是否需要在函数调用中使用三指针?
答案 0 :(得分:57)
您想使用指针指针:
void someFunction (int **data) {
*data = malloc (sizeof (int));
}
void useData (int *data) {
printf ("%p", data);
}
int main () {
int *data = NULL;
someFunction (&data);
useData (data);
return 0;
}
为什么呢?好吧,你想在主函数中更改指针data
。在C中,如果要更改作为参数传入的内容(并且在调用者的版本中显示该更改),则必须传入指向要更改的内容的指针。在这种情况下,“你想要改变的东西”是一个指针 - 所以为了能够改变那个指针,你必须使用一个指向指针......
请注意,除了主要问题之外,代码中还有另一个错误:sizeof(data)
为您提供存储指针所需的字节数(32位操作系统上为4个字节,或者为8个字节) 64位OS),而你真的想要存储指针指向(一个int
所需的字节数,即大多数操作系统上的4个字节)。因为通常sizeof(int *)>=sizeof(int)
,这可能不会引起问题,但需要注意的是。我在上面的代码中已经纠正了这一点。
以下是关于指针指针的一些有用的问题:
答案 1 :(得分:8)
一个常见的陷阱,特别是如果你将Java从C / C ++转移到C / C ++
请记住,当您传递指针时,它会传递值,即复制指针的值。对指针指向的数据进行更改是有好处的,但指针本身的任何更改都只是本地的,因为它是一个副本!!
诀窍是使用通过引用传递指针,因为你想要改变它,即malloc等等。
**指针 - >会吓到一个noobie C程序员;)
答案 2 :(得分:4)
如果要修改指针,则必须将指针传递给指针。
即。 :
void someFunction (int **data) {
*data = malloc (sizeof (int)*ARRAY_SIZE);
}
编辑: 添加了ARRAY_SIZE,在某些时候你必须知道要分配多少个整数。
答案 3 :(得分:2)
这是因为指针数据按值传递给someFunction
。
int *data = NULL;
//data is passed by value here.
someFunction (data);
//the memory allocated inside someFunction is not available.
指向指针或返回已分配的指针将解决问题。
void someFunction (int **data) {
*data = (int *) malloc (sizeof (data));
}
int* someFunction (int *data) {
data = (int *) malloc (sizeof (data));
return data;
}
答案 4 :(得分:2)
someFunction()将其参数作为int *。因此,当您从main()调用它时,您创建的值的副本。无论您在函数内部修改什么,都是此副本,因此更改不会反映在外部。正如其他人建议的那样,您可以使用int **来获取数据中反映的更改。另外,这样做是从someFunction()返回int *。
答案 5 :(得分:2)
除了使用双指针技术外,如果只需要1个返回参数,则重写如下:
int *someFunction () {
return (int *) malloc (sizeof (int *));
}
并使用它:
int *data = someFunction ();
答案 6 :(得分:1)
这是在函数中分配内存并通过参数返回指针的一般模式:
void myAllocator (T **p, size_t count)
{
*p = malloc(sizeof **p * count);
}
...
void foo(void)
{
T *p = NULL;
myAllocator(&p, 100);
...
}
另一种方法是使指针成为函数的返回值(我的首选方法):
T *myAllocator (size_t count)
{
T *p = malloc(sizeof *p * count);
return p;
}
...
void foo(void)
{
T *p = myAllocator(100);
...
}
关于内存管理的一些注意事项:
sizeof *p
而不是sizeof (T)
);如果数据类型必须改变(例如从int到long或float到double),这将为你节省一些心痛。它还使代码读得更好IMO。答案 7 :(得分:0)
这里你试图修改指针,即从“data == Null”到“data == 0xabcd”你分配的其他一些内存。因此,要修改您需要的数据,请传递数据地址,即& data。
void someFunction (int **data) {
*data = (int *) malloc (sizeof (int));
}
答案 8 :(得分:0)
回复您编辑的其他问题:
'*'表示指向某事物的指针。因此'**'将指向指向某事物的指针,'***'指向指向某物的指针的指针等。
'int ** data'的通常解释(如果数据不是函数参数)将是指向int数组列表的指针(例如'int a [100] [100]')。
所以你需要先分配你的int数组(我为了简单起见使用了对malloc()的直接调用):
data = (int**) malloc(arrayCount); //allocate a list of int pointers
for (int i = 0; i < arrayCount; i++) //assign a list of ints to each int pointer
data [i] = (int*) malloc(arrayElemCount);
答案 9 :(得分:0)
我没有使用双指针,只能分配一个新指针并返回它,不需要传递双指针,因为它不会在函数的任何地方使用。
返回void *
,因此可以用于任何类型的分配。
void *someFunction (size_t size) {
return malloc (size);
}
并将其用作:
int *data = someFunction (sizeof(int));
答案 10 :(得分:0)
为简单起见,我将上面的单指针参数称为p 和双指针pp(指向p)。
在一个函数中,p所指向的对象可以更改,并且更改不存在 功能。但是,如果p本身已更改,则更改不会 离开功能。
不幸的是,malloc具有其自身的特性,通常 更改p。这就是为什么原始代码不起作用的原因。 校正(58)使用指向p的指针pp。在纠正 功能,p改变了,但是pp没有改变。这样就行了。