user-0 提问: 为神马这样都可以！！！

回复:
user: user-1
content: 引用 16 楼 u012345348 的回复:[quote=引用 12 楼 lm_whales 的回复:]  这样处理,也许可以正常运行.如果一定要给char 参数传入指针的化。 void pri(char c) {    char **p = (char**)&c;//避免传入的参数，即形参，被截断。    printf("%s",*p); } int main(){ typedef void （*PtrFun）(const char *); PtrFun pf =(PtrFun)pri; pf(a);//避免参数传递的时候，实参被截断后，传入。 return 0; }  不过，没有谁这样写程序。  谢谢你了，虽然作为菜鸟这个东西我现在还看不懂。。[/quote]  不用谢。 大家都是学而知之，不是不学就会的。

user: user-1
content: 分析如下： 1）出错  void pri(char c) {    printf("%s",c);//A） 这个分析在main 内部 } int main(){ char a[]="abc"; pri(a); //这里，如果编译器，能够编译通过        //下面是参数传递过程：        //1)那么数组名 a 作为指针，会转换为int（其实这里，没有任何转换，除了数据类型） ，        //2)然后可能还会转换为char ,因为实参是 char 类型这时，数据被截断        //3)接着，char 会符号位扩展为 int传递到 pri 这个函数中。        //第三次转换的原因，是函数参数传递，由函数调用约定决定。        //几乎所有函数调用约定，在16Bits,32Bits,X86 平台上，char 都是这样处理的。        //接着，是函数调用pri(a) 的展开 //函数原型 void pri ( char c) 的展开 //  ｛ //     这里只有一个语句 //     编译器知道参数（形参）是char类型，于是按照char类型得到c的值， //     注意，实参应该是 char 类型，由于函数调用约定的原因，认为这个char 其实是int  //     所以，实际传递的是实参的拷贝，并且是int 类型数据 //     现在需要用到形参c,类型实际是char类型的，所以就截取一部分数据，得到一个char类型的数据。 //     如果实参确实是char，那么一点问题也没有。 //     而实际上，实参个指针，所以到此为止，指针被截断 //        //     printf("%s",c); //A 这里，又是一个函数调用，参数传递又开始了。 // //     这个参数c,被扩展为一个int传递。 //     printf 这个函数，函数调用约定就是 cdcel, //     只有第一个参数的类型是确定的（char* 是个字符串）， //     第二个参数以后的各个参数，是根据格式来确定，这里是 %s 格式对应类型为 char * //     这样，传递的c,是个char ，然后又转换成 int，他和指针长度一致，于是 //     printf 就认为 char *的值就是，该int的值。 //     这样实际的参数只有一个字节是对的，其他3个字节是由符号扩展(0 扩展)而来的0,或者0xff   //     这样导致地址数据是错误的，所以输出就出错了，地址变成 0x000000??,或者0xffffff??。 //     ?? 表示唯一正确传递的，那一个字节。    //         //   ｝ // //           return 0; }   2）企图不出错，采用的非常举措；   太麻烦了，没有人这么干,   而且会导致，别的错误。   比如传入真正的char 参数。     void pri(char c) {    char **p = (char**)&c;//避免传入的参数，即形参，被截断。    printf("%s",*p); } int main(){ char a[]="abc"; typedef void （*PtrFun）(const char *); //指向void fun(const char*)这种函数的指针 //参数传递不会出错              PtrFun pf =(PtrFun)pri;//强制类型转换。 pf(a);//避免参数传递的时候，实参被截断后，传入。  //pf(a)实际执行的是pri(a);但是转换后，参数类型正确，所以没有被截断。 //void pri(char c) //{ //   形参还是char c，要想，取数正确，只有直接从形参地址中获取 //   把它的地址，代表的那块内存中的数据，当作指针处理，下面把c的地址强制转换为char*的指针。 //   char **p = (char**)&c;//避免传入的参数，即形参，被截断。 //   printf("%s",*p);//类型匹配，所以输出正确。 //}  return 0; }  3)这是这个函数的正确写法，和调用方式。   void pri(const char* s)//因为函数不修改数据，所以指针类型前，加const。 {    printf("%s",s);//%s 和 const char*匹配，所以输出正确。 } int main(){    char a[]="abc";    pri(a);//类型匹配正确，所以结果正确。    return 0; }  4) 似是而非的，不出错的程序。   这种写法，其实是错误的。  void pri(int c) {    printf("%s",c);//%s 和 char*匹配，char * 和int 类型，长度相同                   //在参数传递时，都是作为 int 传递的,                   //所以,虽然参数是不匹配的，但是长度却是合适的，                   //所以，恰巧输出正确了。 } int main(){    char a[]="abc";    pri(a);//char * 和int 类型 不严格匹配，但是长度相同,           //编译没有报错--可能是编译器，错误处理的比较宽松。           //在参数传递时，都是作为 int 传递的,           //所以,虽然参数是不匹配的，但是长度却是合适的，转换也不需要，做任何处理。           //所以，恰巧传递过去的数据，是对的。    return 0; }

user: user-0
content: 引用 12 楼 lm_whales 的回复:这样处理,也许可以正常运行.如果一定要给char 参数传入指针的化。 void pri(char c) {    char **p = (char**)&c;//避免传入的参数，即形参，被截断。    printf("%s",*p); } int main(){ typedef void （*PtrFun）(const char *); PtrFun pf =(PtrFun)pri; pf(a);//避免参数传递的时候，实参被截断后，传入。 return 0; }  不过，没有谁这样写程序。  谢谢你了，虽然作为菜鸟这个东西我现在还看不懂。。

user: user-2
content: 不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  计算机组成原理→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对应的汇编并单步执行观察相应内存和寄存器变化。）

user: user-3
content: #include<stdio.h> void pri(char *a); int main() {  	char a[5]={'a','b','c','d','\0'}; 	pri(a); 	return 0; } void pri(char *a) { 	printf("%s",a); } 你的形参是char型，而你传入的是指针，一个一个字节，一个是四个字节，截断了，将char改成char *,编译通过

user: user-4
content: 指针大小和int一样 碰巧吧？ 不过感觉至少应该会有警告 不知道是不是所有的编译器都编译的过

user: user-5
content: 对char4你分别赋ch类型的，和char[]="abc"一样，结果这样没问题啊

user: user-1
content: 这样处理,也许可以正常运行.如果一定要给char 参数传入指针的化。 void pri(char c) {    char **p = (char**)&c;//避免传入的参数，即形参，被截断。    printf("%s",*p); } int main(){ typedef void （*PtrFun）(const char *); PtrFun pf =(PtrFun)pri; pf(a);//避免参数传递的时候，实参被截断后，传入。 return 0; }  不过，没有谁这样写程序。

user: user-1
content: 引用 9 楼 sinservice 的回复:因为用char做形参类型，而实际要传一个指针，而编译器对char做了扩展，是用0扩展的。 ++  实际是指针转换成char 被截断 然后，char 转换成 int 传入函数（0扩展，或者符号位扩展）  很多编译器 char 缺省是 signed char . 只能符号扩展。 但是不是绝对的，至少可以设置为 unsigned char .此时0扩展 不管如何扩展，结果都面目全非了。  而函数内部，又把参数看作char 了，此时，刚刚扩展的参数又被截断。 然后此char 又一次扩展传入printf 函数 printf根据 %s判断，格式化串后的第一个参数是个指针，  对于32Bits系统，指针可能是4字节的。  于是所有4字节，组合起来看作指针，除了低字节。 其他3个字节，都是错误的（其他字节，非零即FF）。

user: user-6
content: 因为用char做形参类型，而实际要传一个指针，而编译器对char做了扩展，是用0扩展的。

user: user-7
content: 奇怪,應該不行呀,就算是INT 剛剛4個位也不能這樣做,因為類型不一樣!! 編譯器問題吧?  反正違法了標準!就算能偷雞也不要做

user: user-8
content: 1 传参进来的是首地址而已！通过地址输出 2 char的有效范围也就是 -256 ～255而已！

user: user-9
content: 引用 1 楼 user-14 的回复:当然了，int占用4个字节，指针也占用四个字节，这样刚好，但是应该有警告的，换成char就不行了，因为char只有一个字节，跟指针大小不一样，所以就出错了。+1

user: user-10
content: How amazing 答案在这本书里 http://download.csdn.net/detail/zhou19891113/3032586

user: user-11
content: pri(a)是数组a的首地址，占四个字节，char a一个字节，你这样掉用a，指针会被截断，取a前面一个字节。

user: user-12
content: 同意 引用 1 楼 user-14 的回复:当然了，int占用4个字节，指针也占用四个字节，这样刚好，但是应该有警告的，换成char就不行了，因为char只有一个字节，跟指针大小不一样，所以就出错了。

user: user-13
content: 编译器的缘故吧

user: user-14
content: 当然了，int占用4个字节，指针也占用四个字节，这样刚好，但是应该有警告的，换成char就不行了，因为char只有一个字节，跟指针大小不一样，所以就出错了。