user-0 提问: 函数传值的问题

回复:
user: user-0
content: 引用 7 楼 AnYidan 的回复:林锐 高质量c/c++编成指南 有时间一定读，正在努力中。

user: user-0
content: 引用 8 楼 zhao4zhong1 的回复:从汇编角度弄清楚__cdecl,__stdcall,__fastcall,thiscall的区别再说。  计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495 长知识了，以后一定记得前辈给的经验。

user: user-0
content: 引用 5 楼 user-4 的回复:不是结果得不到吧！是代码编译都不过吧！ 错误已经帮你改好了，参考下修改后的代码！ 思路是没错的！  #include<stdio.h> #include<string.h> #include<stdlib.h> #define MAXE 10 typedef struct name {     char build[MAXE][21];     int top; }luxian;  luxian * create(void); int push(luxian *lu2); char * pop(luxian *lu3); int sempty(luxian *lu4);  int main() {     int i;//判断入栈是否成功     char *zu[21];//用来存储出栈时的所有元素     char *p;//用来接收出栈元素的那个元素     luxian *lu=NULL;     lu=create();     i=push(lu);     printf("%d\n",lu->top);     printf("%d\n",i); //  strcpy((zu[1]), pop(lu));     printf("%d\n",i);  } luxian* create(void) {     luxian *luxian1;     luxian1=(luxian *)malloc(sizeof(luxian));     luxian1->build[MAXE][21]=0;     luxian1->top=-1;     return(luxian1); }  int push(luxian *lu2) {     char name[21];     if(lu2->top==MAXE-1)     {            return(0);     }        printf("请输入地址\n");     scanf("%s",name);     lu2->top++;     printf("%d\n",lu2->top);     strcpy(lu2->build[lu2->top],name);     return(1); } char * pop(luxian *lu3) {     char *p;     printf("%s\n",lu3->build[lu3->top]);      if(sempty(lu3))     {         printf("栈为空了\n");         return NULL;     }     else     {         p=(char *)malloc(21*sizeof(char));         printf("%s\n",lu3->build[lu3->top]);         strcpy(p,lu3->build[lu3->top]);         printf("dazhele1\n");         lu3->top--;         return(p);       } } int sempty(luxian *lu4) {     if(lu4->top==-1)     {         return 0;     }     else     {         return 1;     } }   啊！！！！！！知道了，我去，搞混了。唉！  谢谢了！

user: user-1
content: mk:@MSITStore:C:\MSDN98\98VS\2052\vccore.chm::/html/_core_argument_passing_and_naming_conventions.htm Argument Passing and Naming Conventions Home |  Overview |  How Do I  All arguments are widened to 32 bits when they are passed. Return values are also widened to 32 bits and returned in the EAX register, except for 8-byte structures, which are returned in the EDX:EAX register pair. Larger structures are returned in the EAX register as pointers to hidden return structures. Parameters are pushed onto the stack from right to left.  The compiler generates prolog and epilog code to save and restore the ESI, EDI, EBX, and EBP registers, if they are used in the function.  Note   For information on how to define your own function prolog and epilog code, see Naked Function Calls.  The following calling conventions are supported by the Visual C/C++ compiler.  Keyword Stack cleanup Parameter passing  __cdecl Caller Pushes parameters on the stack, in reverse order (right to left)  __stdcall Callee Pushes parameters on the stack, in reverse order (right to left)  __fastcall Callee Stored in registers, then pushed on stack  thiscall  (not a keyword) Callee Pushed on stack; this pointer stored in ECX    For related information, see Obsolete Calling Conventions.

user: user-1
content: 从汇编角度弄清楚__cdecl,__stdcall,__fastcall,thiscall的区别再说。  计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495

user: user-2
content: 林锐 高质量c/c++编成指南

user: user-3
content: 引用 4 楼 u012510962 的回复:[quote=引用 1 楼 u011779875 的回复:] 我没有看你程序的逻辑  第一点 我严重怀疑你的程序是会有很多警告的吧 对于警告  这个东西 最好全不干掉 要不然 你终有一天会吃大亏的  你主函数是这样调用的吗 luxian p; push(p);   第二点 你要记住 函数传参 永远是值的一份拷贝  就算是地址也是一份拷贝 只不过你可以对该地址指向的地方 进行修改值 嗯！确实有好多警告，以后一定注意。顺便问一下结构体指针中存在int变量，当这个指针为实参传值时在被调函数中改变int变量的值时，当函数结束后，其int改变的值会不会在主函数中有所保存。[/quote]  看你怎么传了 如果只是 luxian p;  push(p);   不会有任何改变  luxian p;  push(&p); 这样在处理函数中改变int型a的值 那就会改变 主函数会随着改变

user: user-4
content: 不是结果得不到吧！是代码编译都不过吧！ 错误已经帮你改好了，参考下修改后的代码！ 思路是没错的！  #include<stdio.h> #include<string.h> #include<stdlib.h> #define MAXE 10 typedef struct name {     char build[MAXE][21];     int top; }luxian;  luxian * create(void); int push(luxian *lu2); char * pop(luxian *lu3); int sempty(luxian *lu4);  int main() {     int i;//判断入栈是否成功     char *zu[21];//用来存储出栈时的所有元素     char *p;//用来接收出栈元素的那个元素     luxian *lu=NULL;     lu=create();     i=push(lu);     printf("%d\n",lu->top);     printf("%d\n",i); //  strcpy((zu[1]), pop(lu));     printf("%d\n",i);  } luxian* create(void) {     luxian *luxian1;     luxian1=(luxian *)malloc(sizeof(luxian));     luxian1->build[MAXE][21]=0;     luxian1->top=-1;     return(luxian1); }  int push(luxian *lu2) {     char name[21];     if(lu2->top==MAXE-1)     {            return(0);     }        printf("请输入地址\n");     scanf("%s",name);     lu2->top++;     printf("%d\n",lu2->top);     strcpy(lu2->build[lu2->top],name);     return(1); } char * pop(luxian *lu3) {     char *p;     printf("%s\n",lu3->build[lu3->top]);      if(sempty(lu3))     {         printf("栈为空了\n");         return NULL;     }     else     {         p=(char *)malloc(21*sizeof(char));         printf("%s\n",lu3->build[lu3->top]);         strcpy(p,lu3->build[lu3->top]);         printf("dazhele1\n");         lu3->top--;         return(p);       } } int sempty(luxian *lu4) {     if(lu4->top==-1)     {         return 0;     }     else     {         return 1;     } }

user: user-0
content: 引用 1 楼 u011779875 的回复:我没有看你程序的逻辑  第一点 我严重怀疑你的程序是会有很多警告的吧 对于警告  这个东西 最好全不干掉 要不然 你终有一天会吃大亏的  你主函数是这样调用的吗 luxian p; push(p);   第二点 你要记住 函数传参 永远是值的一份拷贝  就算是地址也是一份拷贝 只不过你可以对该地址指向的地方 进行修改值 嗯！确实有好多警告，以后一定注意。顺便问一下结构体指针中存在int变量，当这个指针为实参传值时在被调函数中改变int变量的值时，当函数结束后，其int改变的值会不会在主函数中有所保存。

user: user-0
content: 引用 2 楼 user-4 的回复:没错阿！刚测试了阿！值反生改变了阿！ 传地址进去，修改地址上的内容啊！没错的。。楼主再试试！  #include <stdlib.h> #include <stdio.h> #include <string.h>  #define MAXE 10 typedef struct name {     char build[MAXE][21];     int top; }luxian;  int push(luxian *lu2) {     char name[21];     if(lu2->top==MAXE-1)     {            return(0);     }        printf("iput address\n");     scanf("%s",name);     lu2->top++;     printf("%d\n",lu2->top);     strcpy(lu2->build[lu2->top],name);     return(1); }   int main(void) {     luxian a = {0};      a.top = 2;     printf(" %d \n", a.top);     push( &a);      printf(" %s \n", a.build[a.top]);     printf(" %d \n", a.top); }  结果：  2  iput address zhongguo 3  zhongguo   3    这上面上面和我的有所出入，我写的程序的一部分是下面的麻烦大师看下  #include<stdio.h> #include<string.h> #include<stdlib.h> #define MAXE 10 typedef struct name { 	char build[MAXE][21]; 	int top; }luxian; luxian * create(void); int push(luxian *lu2); char * pop(luxian *lu3); int sempty(luxian *lu4); int main() { 	int i;//判断入栈是否成功 	char *zu[21];//用来存储出栈时的所有元素 	char *p;//用来接收出栈元素的那个元素 	luxian *lu=NULL; 	lu=create(); 	i=push(lu); 	printf("%d\n",lu->top); 	printf("%d\n",i); 	strcpy(*(zu[1]),pop(lu)); 	printf("%d\n",i);  } luxian* create(void) { 	luxian *luxian1; 	luxian1=(luxian *)malloc(sizeof(luxian)); 	luxian1->build[MAXE][21]=0; 	luxian1->top=-1; 	return(luxian1); }  int push(luxian *lu2) { 	char name[21]; 	if(lu2->top==MAXE-1) 	{ 		return(0); 	} 	printf("请输入地址\n"); 	scanf("%s",name); 	lu2->top++; 	printf("%d\n",lu2->top); 	strcpy(lu2->build[lu2->top],name); 	return(1); } char * pop(luxian *lu3) { 	char *p; 	printf("%s\n",lu3->build[lu3->top]);  	if(sempty(lu3)) 	{ 		printf("栈为空了\n"); 		return; 	} 	else 	{ 		p=(char *)malloc(21*sizeof(char)); 		printf("%s\n",lu3->build[lu3->top]); 		strcpy(*p,lu3->build[lu3->top]); 		printf("dazhele1\n"); 		lu3->top--; 		return(*p);   	} }  int sempty(luxian *lu4) { 	if(lu4->top==-1) 	{ 		return 0; 	} 	else 	{ 		return 1; 	} }   主要差别是我的传的是指针，而不是数组的名字。定义路线变量的时候用的是指针。

user: user-4
content: 没错阿！刚测试了阿！值反生改变了阿！ 传地址进去，修改地址上的内容啊！没错的。。楼主再试试！  #include <stdlib.h> #include <stdio.h> #include <string.h>  #define MAXE 10 typedef struct name {     char build[MAXE][21];     int top; }luxian;  int push(luxian *lu2) {     char name[21];     if(lu2->top==MAXE-1)     {            return(0);     }        printf("iput address\n");     scanf("%s",name);     lu2->top++;     printf("%d\n",lu2->top);     strcpy(lu2->build[lu2->top],name);     return(1); }   int main(void) {     luxian a = {0};      a.top = 2;     printf(" %d \n", a.top);     push( &a);      printf(" %s \n", a.build[a.top]);     printf(" %d \n", a.top); }  结果：  2  iput address zhongguo 3  zhongguo   3

user: user-3
content: 我没有看你程序的逻辑  第一点 我严重怀疑你的程序是会有很多警告的吧 对于警告  这个东西 最好全不干掉 要不然 你终有一天会吃大亏的  你主函数是这样调用的吗 luxian p; push(p);   第二点 你要记住 函数传参 永远是值的一份拷贝  就算是地址也是一份拷贝 只不过你可以对该地址指向的地方 进行修改值