何时返回指针,将指针作为参数传递或者根本不使用它们?

时间:2011-09-27 05:52:54

标签: c pointers

我目前正在尝试C,我很难理解如何在函数中使用指针。我理解当我初始化指针然后取消引用它时发生了什么,但是,当我必须在函数中使用它们时,我有点困惑,如下所示:

我这里有三个功能,但我不确切知道何时使用哪个功能。我对C来说还是比较新的。

int returnSomething(int a, int b)
int returnSomething(int *ptrA, int *ptrB)
int* returnSomething(int *ptrA, int *ptrB);

编辑:

三者之间是否存在重大差异?

5 个答案:

答案 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 - 一个数字,例如1242,{{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 - 一个数字,例如foo12,{{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时,传递它并将其作为指针返回,除非无法这样做。