在C语言中调用函数时,什么情况下应该添加"&",什么情况下不需要?

3

程序 A

void create(struct Stack *st) 
{
    printf("Enter Size");
    scanf("%d",&st->size);
    st->top=-1;
    st->S=(int *)malloc(st->size*sizeof(int));
}

int main()
{
struct stack st;
create(&st);
return 0;
}

程序B - 假设已经创建了一个链表,first(声明为全局变量)指向链表中的第一个节点。

struct Node 
{ 
 int data;
 struct Node *next;
}*first=NULL;

void display(struct Node *p) 
{
while(p!=NULL)
{
 printf("%d ",p->data);
 p=p->next;
}
} 

int main()
{
display(first);
return 0;
}

我的疑问是,在程序A中调用 create 函数时为什么需要&运算符,而在程序B中调用 display 函数时却不需要。两个函数都将指针作为参数。您能否通过示例解释在调用函数时& * 运算符之间的关系。谢谢。


当您拥有一个变量并需要将该类型的变量的指针传递给函数时,您使用 &。如果您已经拥有正确类型的指针,则不使用 & - Jonathan Leffler
&x allows to get the address of x whatever its usage, if you need to get the value of x use x if you need to get its address use &x - bruno
在第二个程序中,传递的变量已经是一个指针。它被定义为*first - Weather Vane
当您将一些&作为参数发送到任何函数的参数时,应该有一个*来保存那个&。这是纯粹的关系。 - Shubham
3个回答

2

无论x的类型是什么,&x都可以获取x的地址。如果需要获取x的值,请使用x;如果需要获取其地址,请使用&x

在第一个程序中,提供st的地址允许create修改它,因此在从create返回到main时,变量st被修改。

但是有:

void create(struct Stack st) 
{
    printf("Enter Size");
    scanf("%d",&st.size);
    st.top=-1;
    st.S=(int *)malloc(st.size*sizeof(int));
}

int main()
{
  struct stack st;
  create(st);
  return 0;
}

在这种情况下,create 在从 main 复制的 st 上工作,并且在返回到 main 时,st 没有发生任何变化。
当执行时,
scanf("%d",&st->size);
目标是读取一个整数并将其存储在字段“size”中,为此需要给出该字段的地址,因此使用&st->size而不是st->size,后者只会返回其值。
在第二个程序中,first已经是一个指针,这就是为什么在main中调用display(first);而不是display(&first);,无论如何请注意first的值为NULL,因为(p!=NULL)立即为false,display什么也不做。
当然,您也可以使用&first获取first的地址,但在这种情况下,您会得到一个struct Node **,所以假设display(&first);,则display必须更改为void display(struct Node ** p),并且其主体必须相应地进行调整。

2
当您将一些&作为参数发送给任何函数的参数时,应该有*来保存&,或者如果函数的参数中有任何*,您可以发送参数,如&*。这是纯粹的关系。
程序A:中:
void create(struct Stack *st) 
{
    printf("Enter Size");
    scanf("%d",&st->size);
    st->top=-1;
    st->S=(int *)malloc(st->size*sizeof(int));
}

int main()
{
struct stack st;
create(&st);
return 0;

您需要发送&st,因为向create()发送&st将使您访问存储st的内存。如果您将st作为参数发送--这只是存储st数据的内存位置的名称--到create()中,那么这只会将st复制到struct Stack *st中,并导致错误。您不能像使用其副本一样修改原始值,例如scanf("%d", &st->size);,这就是为什么在第一个程序中您需要发送st的地址。
程序B中:
struct Node 
{ 
 int data;
 struct Node *next;
}*first=NULL;

void display(struct Node *p) 
{
while(p!=NULL)
{
 printf("%d ",p->data);
 p=p->next;
}
} 

int main()
{
display(first);
return 0;
}

你已经拥有了struct Node类型的data存储的内存地址,即first的值。 因此,在这种情况下,你不需要执行display(&first),只需复制first并在display()函数中使用它即可。

你能通过例子解释在调用函数时 & 和 * 操作符之间的关系吗?

但是在B程序中,你也可以像这样执行display(&first)

struct Node 
{ 
 int data;
 struct Node *next;
}*first=NULL;

void display(struct Node **p) 
{
while(*p!=NULL)
{
 printf("%d ",(*p)->data);
 *p=(*p)->next;
}
} 

int main()
{
display(&first);
return 0;
}

我希望上面给出的示例可以清楚地说明在调用任何函数时,根据其参数使用 *&。请注意,使用 &first 显示数据将修改 *p=(*p)->next;first 的地址,你的指向链表头部的指针 head 将被丢失,因此,此示例仅用于演示目的。

1
如果您想在函数中更改原始对象而不是其副本,则必须通过引用传递它。在C中通过引用传递意味着通过指向对象的指针间接传递对象。
例如,如果在第一个程序中写入:
void create(struct Stack st) 
{
    printf("Enter Size");
    scanf("%d",&st.size);
    st.top=-1;
    st.S=(int *)malloc(st.size*sizeof(int));
}

int main()
{
struct stack st;
create(st);
return 0;
}

那么该函数将处理传递给函数的对象 st 的副本。更改副本不会影响原始对象。

在第二个程序中

struct Node 
{ 
 int data;
 struct Node *next;
}*first=NULL;

void display(struct Node *p) 
{
while(p!=NULL)
{
 printf("%d ",p->data);
 p=p->next;
}
} 

int main()
{
display(first);
return 0;
}

函数display处理指针first的副本。指针本身在函数中没有被改变,因此没有必要通过引用传递它。另一方面,指针指向的节点是通过引用传递的。因此,编译器不会创建一个struct Node类型的对象的副本。如果需要,您可以在函数中更改指向的节点。


是的,我明白了。 - Shubham

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