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 = *实参
===========
形参只是实参的一个拷贝,
所以修改 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;
}
其实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也许可以节省你很多时间。
换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的一份拷贝,
总之,不好说懂. :(
我觉得有的时候你可以这样看待形参与实参的关系,那就是相当于一个赋值过程:形参=实参.
好,那下面的问题:
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 = *实参
===========
形参只是实参的一个拷贝,
所以修改 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;
}
其实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也许可以节省你很多时间。
换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的一份拷贝,
总之,不好说懂. :(
我觉得有的时候你可以这样看待形参与实参的关系,那就是相当于一个赋值过程:形参=实参.
好,那下面的问题:
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++交流群