关于指针作为函数参数的问题

时间:2022-10-01 18:49:43
include <iostream>
using namespace std;

struct Student
{
long number;
float score;
Student *next;
};

Student* head;

Student* Create(void)
{
Student* PS;
Student* PEnd;

head = NULL;

while (1)
{
PS = new Student;
cin >> PS->number >> PS->score;
if (0 == PS->number)
break;

if (NULL == head)
head = PS;
else
PEnd->next = PS;

PEnd = PS;
}
         PEnd->next = NULL;
delete PS;

return head;
}

void Delete(Student* head, int number)
{
Student* p;

if (NULL == head)
{
cout << "The list is empty!" << endl;
return;
}

if (head->number == number)
{
p = head;
head = head->next;
delete p;
p = NULL;

cout << "The head is deleted" << endl;
return;
}

for (Student* pGuard=head; pGuard->next; pGuard=pGuard->next)
{
if (pGuard->next->number == number)
{
p = pGuard->next;
pGuard->next = p->next;

delete p;
p = NULL;

cout << "The number " << number << " is deleted!" << endl;

    return;
}
}

cout << "Can not find " << number << "from list" << endl;
return;
}

void ShowList(Student* head)
{
cout << "The list is: " << endl;

while (head)
{
cout << head->number << "  " << head->score << endl;
head = head->next;
}
}

void main(void)
{
Create();

ShowList(head);

Delete(head,3); 
         ShowList(head);

}
问题:
1.为什么void ShowList(Student* head)不会修改实参head而只修改形参head的地址?也就是说形参只是实参的一个拷贝?
2.为什么void Delete(Student* head, int number)里面修改了形参head所指向的地址实参head也跟着变化呢?
3.也就是说当指针做为函数的形参时,在什么情况下修改形参的地址或者所指向的地址实参也会变化?是不是修改*head的值,实参也会同步修改,但修改head的值,实参就不会同步变化?
谢谢!

9 个解决方案

#1


1.为什么void ShowList(Student* head)不会修改实参head而只修改形参head的地址?也就是说形参只是实参的一个拷贝?
===========
形参只是实参的一个拷贝,
所以修改 head 不能修改实参,
但是修改 *head 可以实现 修改 *实参, 因为拷贝的内容是完全一样的,
即 *head = *实参

#2


后面的问题也是一个意思。

对于指针,
如果修改指针本身,那么无法反馈到实参,
如果对指针解引用操作,可以实现反馈。

即在函数中需要 使用 * 操作

#3


其实我之前的想法也和楼主是一样的,但看完下面的这段之后感觉到有点模糊了,毕竟下面这段代码是谭浩强的《c++程序设计教程》,不敢怀疑专家的权威,其实这本书里面还有很它其它的错误!真晕,大家对这本书的评价还这么高!?
其实void Delete(Student* head, int number)应该定义为void Delete(Student* &head, int number),要不形参head的地址发生变化了,但实参head的地址不会发生变化,实际上这块内存已经被delete了.


void Delete(Student* head, int number)//应修改为void Delete(Student* &head, int number)
{
Student* p;

if (NULL == head)
{
cout << "The list is empty!" << endl;
return;
}

if (head->number == number)
{
p = head;
head = head->next;//形参head的变化不会改变实参head,删除它之后再调用ShowList(head)就会提示读内存错误
delete p;
p = NULL;

cout << "The head is deleted" << endl;
return;
}

for (Student* pGuard=head; pGuard->next; pGuard=pGuard->next)
{
if (pGuard->next->number == number)
{
p = pGuard->next;
pGuard->next = p->next;

delete p;
p = NULL;

cout << "The number " << number << " is deleted!" << endl;

    return;
}
}

cout << "Can not find " << number << "from list" << endl;
return;
}

#4


建议你如果学C++而不想走弯路的话,最好别用国产书。
换C++ Primer也许可以节省你很多时间。

#5


其实我觉得指针做参数,修改与不修改实参这个问题真的对初学者来说很难懂,我也是这么过来的,刚开始看各种书,怎么都觉得有问题,不知所云,可现在虽不能说透彻了,但感觉也算比较清楚,总的来说还是要多看书,多练,多实践,自已总结.那些什么"实参的拷贝,不修改"之类的话的确太难懂,太苍白了,而几乎所有的书都这么说,难道他们不知道这话说出来有多恶心?

从这里我也感觉"天下文章一大抄",真的是害人不浅.

#6


好了,回答楼主的问题吧.

我觉得有的时候你可以这样看待形参与实参的关系,那就是相当于一个赋值过程:形参=实参.

好,那下面的问题:

void f(char *s)       
{
}
这个函数,会不会修改实参? 其实要看实参是什么东西.如果是:

char q[]="hello";
char *p=q;
f(p);

现在在f函数里相当于: char *s=p;  那么也就是s指针指向了p,p又指向数组q,  现在在f里面如

果*s='y'也就相当于*p='y',即q[0]='y'了,修改了!

修改的是谁? 是数组的内容.

实参是谁? 实参是指向数组的指针.

再来:  在f里面这样做: s++;*s='n'; s指向的是数组首地址,s++后s指向了下一个地

址,*s='n'也就相当于q[1]='n'了, 但是注意, p并没有移动,所以实参p并没有改变.


这也就是所谓的,s是p的一份拷贝,

总之,不好说懂.  :(


#7



所谓一份拷贝,就是在函数调用时,将参数入栈,我们对形参的任何修改都是修改到
栈上的个拷贝,并不影响我们的实际参数.

任何编程语言的参数传递实际上都是在做传值调用.
所谓的传指针,就是把指针指向者的地址(一个值)传进函数.
也就是那个地址被压栈.
然后我们再通过这个地址进行操作,因为实参和形参同样都是一个地址的值.
所以改变形参指向者的状态时,实参指针也能看到这种变化.

#8



最好学会调试

vc里面有个望远镜的,哈哈,可以看到你想看到的东西

有写东西真的需要自己做调试才会有体会的

否则印象不深的


比如,我做了下面这测试以后我就基本弄懂了构造函数,析构函数,继承

http://www.dj9158.com/ReadCode/436.html

可以看看

总结也很重要

#9


30122002  c++交流群

#1


1.为什么void ShowList(Student* head)不会修改实参head而只修改形参head的地址?也就是说形参只是实参的一个拷贝?
===========
形参只是实参的一个拷贝,
所以修改 head 不能修改实参,
但是修改 *head 可以实现 修改 *实参, 因为拷贝的内容是完全一样的,
即 *head = *实参

#2


后面的问题也是一个意思。

对于指针,
如果修改指针本身,那么无法反馈到实参,
如果对指针解引用操作,可以实现反馈。

即在函数中需要 使用 * 操作

#3


其实我之前的想法也和楼主是一样的,但看完下面的这段之后感觉到有点模糊了,毕竟下面这段代码是谭浩强的《c++程序设计教程》,不敢怀疑专家的权威,其实这本书里面还有很它其它的错误!真晕,大家对这本书的评价还这么高!?
其实void Delete(Student* head, int number)应该定义为void Delete(Student* &head, int number),要不形参head的地址发生变化了,但实参head的地址不会发生变化,实际上这块内存已经被delete了.


void Delete(Student* head, int number)//应修改为void Delete(Student* &head, int number)
{
Student* p;

if (NULL == head)
{
cout << "The list is empty!" << endl;
return;
}

if (head->number == number)
{
p = head;
head = head->next;//形参head的变化不会改变实参head,删除它之后再调用ShowList(head)就会提示读内存错误
delete p;
p = NULL;

cout << "The head is deleted" << endl;
return;
}

for (Student* pGuard=head; pGuard->next; pGuard=pGuard->next)
{
if (pGuard->next->number == number)
{
p = pGuard->next;
pGuard->next = p->next;

delete p;
p = NULL;

cout << "The number " << number << " is deleted!" << endl;

    return;
}
}

cout << "Can not find " << number << "from list" << endl;
return;
}

#4


建议你如果学C++而不想走弯路的话,最好别用国产书。
换C++ Primer也许可以节省你很多时间。

#5


其实我觉得指针做参数,修改与不修改实参这个问题真的对初学者来说很难懂,我也是这么过来的,刚开始看各种书,怎么都觉得有问题,不知所云,可现在虽不能说透彻了,但感觉也算比较清楚,总的来说还是要多看书,多练,多实践,自已总结.那些什么"实参的拷贝,不修改"之类的话的确太难懂,太苍白了,而几乎所有的书都这么说,难道他们不知道这话说出来有多恶心?

从这里我也感觉"天下文章一大抄",真的是害人不浅.

#6


好了,回答楼主的问题吧.

我觉得有的时候你可以这样看待形参与实参的关系,那就是相当于一个赋值过程:形参=实参.

好,那下面的问题:

void f(char *s)       
{
}
这个函数,会不会修改实参? 其实要看实参是什么东西.如果是:

char q[]="hello";
char *p=q;
f(p);

现在在f函数里相当于: char *s=p;  那么也就是s指针指向了p,p又指向数组q,  现在在f里面如

果*s='y'也就相当于*p='y',即q[0]='y'了,修改了!

修改的是谁? 是数组的内容.

实参是谁? 实参是指向数组的指针.

再来:  在f里面这样做: s++;*s='n'; s指向的是数组首地址,s++后s指向了下一个地

址,*s='n'也就相当于q[1]='n'了, 但是注意, p并没有移动,所以实参p并没有改变.


这也就是所谓的,s是p的一份拷贝,

总之,不好说懂.  :(


#7



所谓一份拷贝,就是在函数调用时,将参数入栈,我们对形参的任何修改都是修改到
栈上的个拷贝,并不影响我们的实际参数.

任何编程语言的参数传递实际上都是在做传值调用.
所谓的传指针,就是把指针指向者的地址(一个值)传进函数.
也就是那个地址被压栈.
然后我们再通过这个地址进行操作,因为实参和形参同样都是一个地址的值.
所以改变形参指向者的状态时,实参指针也能看到这种变化.

#8



最好学会调试

vc里面有个望远镜的,哈哈,可以看到你想看到的东西

有写东西真的需要自己做调试才会有体会的

否则印象不深的


比如,我做了下面这测试以后我就基本弄懂了构造函数,析构函数,继承

http://www.dj9158.com/ReadCode/436.html

可以看看

总结也很重要

#9


30122002  c++交流群