我目前正在尝试C,我很难理解如何在函数中使用指针。我理解当我初始化指针然后取消引用它时发生了什么,但是,当我必须在函数中使用它们时,我有点困惑,如下所示:
我这里有三个功能,但我不确切知道何时使用哪个功能。我对C来说还是比较新的。
int returnSomething(int a, int b)
int returnSomething(int *ptrA, int *ptrB)
int* returnSomething(int *ptrA, int *ptrB);
编辑:
三者之间是否存在重大差异?
答案 0 :(得分:6)
您需要根据具体情况调整使用方式。
第一种情况,你将两个int作为参数并返回一个int。因为您的参数是按值的,所以应用于它们的任何更改都只有函数范围。
例如:
int returnSomething(int a, int b)
{
a = 0;
b = 0;
return 0;
}
//....
int x = 3;
int y = 4;
returnSomething(a,b);
// x will still be 3, y will still be 4
在第二种情况下,因为您将参数作为指针传递,所以您将能够更改这些值。
int returnSomething(int* a, int* b)
{
*a = 0;
*b = 0;
return 0;
}
//....
int x = 3;
int y = 4;
returnSomething(&a,&b);
// x and y will be 0 here
第三种情况,除了通过指针传递参数外,还返回指向int的指针。这意味着在函数内部,您必须分配内存并在完成后释放它。我不建议使用它,通常有解决方法。
int* returnSomething(int* a, int* b)
{
int* x = malloc(sizeof(int));
*x = 1;
return x;
}
//....
int x = 3;
int y = 4;
int* z = returnSomething(&a,&b);
free(z);
答案是,这取决于你想做什么。如果需要更改方法中的参数值,请按引用或通过指针进行传递。我不建议使用最后一种方法。
此外,这适用于您正在处理POD类型。如果你有自己的结构,通过指针或返回指针传递它会更有效率,因为不需要创建新的副本。
答案 1 :(得分:0)
让我们首先向您解释通过引用;处理它的难度要小得多。
说你有:
int increment(int &a)
{
a = a + 1;
return a;
}
increment(foo); // foo = foo + 1;
(注意:为了更容易理解,我牺牲了一些'正确性'。)
这有两件事:
a
递增1
。但请注意 - 我们将&a
放在函数声明中。这意味着通过引用传递给increment()
“的值也会增加1
。换句话说,foo
增加1
,就像a
一样。a
的值 - 一个数字,例如1
,2
,42
,{{1}等等。还有一件事:通过引用传递 C ++ ;你不能在C中使用它,但在你开始搞乱指针之前,这是一个很好的概念。
传递指针基本上只是传递值 ...除了你在内存中传递位置(-21
),而不是实际的0x12345678
。
foo
这与我们的第一个程序完全相同 - 它增加int pincrement(int *p)
{
*p = *p + 1;
return *p;
}
pincrement(&foo); // foo = foo + 1;
的值。
foo
会告诉您内存中&foo
的地址。此信息将传递给foo
。所以:
p
在第三行,p = &foo;
指向的值会递增。换句话说,*p
会增加foo
。
1
的值 - 一个数字,例如foo
,1
,2
,{{1}等等。对于返回指针,您可以使用它们返回42
s:
-21
答案 2 :(得分:0)
你的问题的答案更多地与内存考虑和良好的代码设计有关,即你是否想要节省资源,以及你是否知道你的代码在任何一个实例中发生了什么。
1)当你传递值( int returnSomething(int a, int b) )
时,每个参数都是一个副本,对它们所做的任何更改都不会影响函数外的原始变量(参数有函数作用域),并且函数返回一个值,你然后可以用来初始化变量。
2)当您通过指针传递时,您将地址传递到内存中的某个位置,所以请记住,作为良好代码设计的问题,您必须将该位置与其他外部位置进行隔离(锁语义)过程。这尤其适用于您提供的示例:
int returnSomething(int *ptrA, int *ptrB)
int* returnSomething(int *ptrA, int *ptrB);
其中,在函数退出后,函数中对 *ptrA and *ptrB
所做的更改仍然存在。两者之间的唯一区别是其中一个函数返回一个值,然后您可以使用该值初始化变量( int returnSomething(int *ptrA, int *ptrB) )
,另一个函数返回另一个地址到内存中可能会发生变化和/或垃圾头痛的位置根据您的程序设计(您在函数内为返回类型创建内存并将该地址分配给指针变量,指针变量本身可以任意更改为指向内存中的另一个位置等)。我将通过添加以下内容扩展Luchian的最后一个示例:想象一下你的代码中的其他地方你将 * z 变量传递给另一个函数然后尝试使用该地址指向的内存,你现在有了指向您之后尝试使用的任何内容的指针变量。
这一切都归结为良好的代码设计。如果您了解指针的优缺点并适当地使用它们,那么您将没有任何问题。
答案 3 :(得分:0)
Luchian Grigore上面写了一些很好的描述。我想给你一个小小的想法,以进一步简化你的想法。
当您将参数传递给C中的函数时,请尝试考虑堆栈的确切位置(在第1种情况下,实际的整数变量会被压入堆栈,如果这些整数变量的2&3;推动),现在结合这一事实,一旦控制从funciton和堆栈unwindes返回,对堆栈上的变量所做的更改就会消失。
因此,简单来说,如果您计划更改在函数内部传递的varibales并希望稍后使用这些更改,那么请考虑传递这些变量的地址,否则只需传递变量。
答案 4 :(得分:-2)
对于int
,除非无法执行此操作,否则始终按值传递。
即int returnSomething(int a, int b)
。
当您传递一些自定义大struct
时,传递它并将其作为指针返回,除非无法这样做。