《《C专家编程》总结.docx》由会员分享,可在线阅读,更多相关《《C专家编程》总结.docx(43页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、 C专家编程总结 C专家编程总结 C专家编程总结 开头读C专家编程之前,有一个很担忧的问题:94年出的讲语言的书,在现在(201*)还有多少是适用的。因此,一边读,一边用VS201*做试验。最终发觉大局部内容都还在用。读完后,觉得最精彩的局部有二:一是讲解如何理解声明,二是深入地讲解数组名与指针。下文是将看书过程中所做的笔记进展的整理。 p.s:以下代码均在VS201*测试过 1.使用无符号数时要特殊留意(不推举使用无符号数) 当无符号数与有符号数在同一条表达式中消失时,有符号数会被转换为无符号数。e.g: intfeng=-1; unsignedintyan=5; boolresult=(f
2、engvoid(*signal(intsig,void(*func)(int)(int);/signal是一个函数,该函数接收一个int,一个函数指针,并返回一个函数指针 5.左值与右值 左值通常表示存储结果的地方(地址),其值在编译时可知右值通常表示地址的内容,其值通常要到运行时才知道 6.指针与数组名不等同的状况(定义为数组,却声明为指针,或者反过来) 前提学问(假设有定义:intarray10,*ptr;): a.使用数组名下标访问(如:array1),会直接将数组名的地址加上偏移值作为变量的地址(即array1的地址) b.使用指针下标访问(如:ptr1),会先取指针指向的内容,然后将
3、这个内容加上偏移值作为变量的地址(即ptr1的地址) 不等同的缘由: 当定义为数组,却声明为指针时,相当于用指针下标访问的方法来解析一个数组名下标,即先取数组第0号元素的内容,然后将这个内容加上偏移值作为变量的地址,从而访问了不该访问的东西。反之亦然。7.指针与数组等同的状况 a.编译器将表达式中的数组名当作指向该数组第0号元素的指针,下标当作指针的偏移量,即arrayi会被当作*(array+i) b.编译器将函数参数声明中的数组名当作指向该数组第0号元素的指针,即在函数内部得到的是指针,而不是数组名 基于a状况,可知这条谣言是假的(至少在一维数组中肯定不成立):用指针迭代数组比用下标迭代数
4、组更快 基于b状况,可解释为什么在传递数组后,不能用以下方法计算数组长度 intArrayLength(intarr) returnsizeof(arr)/sizeof(arr0);/返回值必定是1,由于此时的arr是一个指针,而不是数组名 留意b状况的将数组改写为指针并不是递归定义的,e.g: 实参charzero1010被改写为char(*zero)10,这里将数组的数组改写为数组的指针 实参char*zero10被改写为char*zero,这里将指针数组改写为指针的指针 实参cahr(*zero)10不转变,由于此时的zero是指针,而不是数组8.interposition interp
5、osition指用户定义的函数取代库中声明完全一样的函数,留意这不是指重载,而是指下面这种: voidzero();/userdefinedfunctionvoidzero();/libraryfunction 消失interposition时,要特殊留意以下状况: voidzero();/userdefinedfunctionintmain() zero();/调用用户定义的函数zero,而不是库函数zero FengYan();/假设这是另一个库函数,并且函数内调用库函数zero,此时由于interposition,变成调用用户定义的zeroreturn0; 备注: 消失interposi
6、tion时,在VS201*会消失warning:inconsistentdlllinkage9.堆栈段作用 a.存储局部变量 b.函数调用时,存储有关的维护信息 c.用作临时存储区。e.g:计算一个很长的表达式时,会把局部结果先压到堆栈中 扩展阅读:C语言要点总结 C和指针C专家编程C陷阱与缺陷C语言编程要点 编程精粹-Microsoft编写优质无错C程序秘诀 总结 说明:总结的学问点主要源于上面的4本书,编程精粹-Microsoft编写优质无错C程序秘诀这本书未做总结,该书有清楚版的pdf格式的电子版。 -wuliming-201*-04-25 wuliming_scwuliming_ 名目
7、 字符与字符串的区分(c缺陷与陷阱1.5节).4指针与数组1(c缺陷与陷阱3.1节).5指针与数组2(c和指针.P141.).6指针和数组的一样与不同(c专家编程.P199.).8用malloc为字符串安排存储空间时的留意事项(c缺陷与陷阱3.2节).10字符串常量(c和指针.P269.).12用字符串常量初始化指针和数组(c专家编程.P87.).13二维数组下标操作的相关概念(c和指针.P156.).14指向一维、二维数组的指针(c和指针.P158.).17array_name和charstr=“abcdefghijklmnopqrstuvwxyz“;printf(“-%c-n%sn“,ch
8、,str); return0; 编译该程序可以通过,但是会产生警告;输出结过为:-z- Abcdefghijklmnopqrstuvwxyz/在Dev-C+4.9.9.2编译环境中可以通过,但是在VC.0中通不过 指针与数组1(c缺陷与陷阱3.1节) c语言中的数组值得留意的地方有以下两点: 1、c语言中只有一维数组,而且数组的大小必需在编译期间就作为一个常数确定下来(C99标准允许变长数组,GCC编译器中实现了变长数组)。然而,c语言中数组的元素可以是任何类型的对象,固然也可以是另外一个数组。这样,要仿真出一个多维数组就不是一件难事。 2、对于一个数组,我们只能够做两件事:确定该数组的大小,
9、以及获得指向该数组下标为0的元素的指针。其他有关数组的操作,哪怕它们乍看上去是以数组下标进展运算的,实际上都是通过指针进展的。换句话说,任何一个数组下标运算都等同于一个对应的指针运算,因此我们完全可以依据指针行为定义数组下标的行为。 现在考虑下面的例子:inti;int*p; intcalendar1231; 上面声明的calendar是一个数组,该数组拥有12个数组类型的元素,其中的每个元素都是一个拥有31个整型元素的数组。因此,sizeof(calendar)的值是:3112sizeof(int)。 考虑一下,calendar4的含义是什么?由于calender是一个有着12个数组类型元素
10、的数组,它的每个数组类型元素又是一个有着31个整型元素的数组,所以calendar4是calendar数组的第5个元素,是calendar数组中12个有着31个整型元素的数组之一。因此,calendar4的行为也表现为一个有着31个整型元素的数组的行为。例如,sizeof(calendar4)的结果是:31sizeof(int)。 又如,p=calendar4;这个语句使指针p指向了数组calendar4中下标为0的元素。由于calendar4是一个数组,我们可以通过下标的形式来指定这个数组中的元素:i=calendar47,这个语句也可以写成下面这样而表达的意思保持不变:i=*(calend
11、ar4+7),还可以进一步写成:i=*(*(calendar+4)+7)。 下面我们再看:p=calendar;这个语句是非法的,由于calendar是一个二维数组,即“数组的数组”,在此处的上下文中使用calendar名称会将其转换为一个指向数组的指针。而p是一个指向整型变量的指针,两个指针的类型不一样,所以是非法的。明显,我们需要一种声明指向数组的指针的方法:intcalendar1231;int(*monthp)31;monthp=calendar; int(*monthp)31语句声明的*monthp是一个拥有31个整型元素的数组,因此,monthp就是一个指向这样的数组的指针。mon
12、thp指向数组calendar的第一个元素。 指针与数组2(c和指针.P141.) 1、数组的名的值是一个指针常量,不能试图将一个地址赋值给数组名; 2、当数组名作为sizeof操作符的操作数时,sizeof(arrayname)返回的是整个数组的长度,而不是指向 数组的指针的长度; 3、当数组名作为单目操作符int*b; a和b能够互换吗?它们都具有指针值,它们都可以进展间接访问和下标操作。但是,它们还是有很大的区分的:声明一个数组时,编译器将依据声明所指定的元素数量为数组保存内存空间,然后再创立数组名,它的值是一个常量,指向这段空间的起始位置。声明一个指针变量时,编译器只为指针本身保存内存
13、空间,它并不为任何整型值安排内存空间。而且,指针变量并未被初始化为指向任何现有的内存空间,假如它是一个自动变量,它甚至根本不会被初始化。把这两个声明用图的方法表示,可以发觉它们之间存在显著的不同:ab?因此,上述声明后,表达式*a是完全合法的,但表达式*b却是非法的。*b将访问内存中某个不确定的位 置,或者导致程序终止。另一方面,表达式b+可以通过编译,但是a+却不能,由于a的值是一个常量。 #include intmain() /留意sizeof(num)的长度应当为10*4=40intnum=0,1,2,3,4,5,6,7,8,9;printf(“sizeof(num)=%dn“,size
14、of(num);/留意sizeof(str)的长度应当为11,包括字符串后面的“0“charstr=“0123456789“;printf(“sizeof(str)=%dn“,sizeof(str);/留意sizeof(str1)的长度应当为10,不包括字符串后面的“0“,但是,最好将字符串的最终一个字符设定为空charstr1=“0“,“1“,“2“,“3“,“4“,“5“,“6“,“7“,“8“,“9“;printf(“sizeof(str1)=%dn“,sizeof(str1);/printf(“sizeof(ptoint)=%d,(*ptoint)9=%dn“,sizeof(ptoin
15、t),(*ptoint)9);/printf(“sizeof(ptostr)=%d,(*ptostr)9=%cn“,sizeof(ptostr),(*ptostr)9);/由于p指向的是数组num5,所以对下标取负值后,不会超出数组的正常取值范围/该例子也说明白为什么下标检查在c语言中是一项困难的任务:下标引用可以作用于任意的指针,而不仅仅是数组名/作用于指针的下标引用的有效性即依靠于该指针当时恰好指向什么内容,也依靠于下标的值int*p=num+5;printf(“p-1=%d,p0=%d,p1=%dn“,p-1,p0,p1);/下面的表达式中,“num5和5num“的值是一样的,把它们转换
16、成对等的间接访问表达式,它们都等同于*(num+2)/“5num“这个奇怪的表达式之所以可行,缘于C实现下标的方法。对编译器来说,这两种形式并无差异/但是,决不应当编写形如“5num“的表达式,由于它会大大的影响程序的可读性printf(“num5=%d,5num=%dn“,num5,5num);getchar(); return0; 输出结果为: 指针和数组的一样与不同(c专家编程.P199.) 在实际应用中,数组和指针可以互换的情形要比两者不行互换的情形更为常见。让我们分别考虑“声明”和“使用”这两种状况。声明本身还可以进一步分为3种状况:外部数组的声明; 数组的定义(定义是声明的一种特别
17、状况,它安排内存空间,并可能供应一个初始值);函数参数的声明; extern,如externchara;不能改写为指针的形式 声明定义,如chara10;不能改写为指针的形式数组 函数的参数,可以随便选择数组在表达式中使用的形式或者指针的形式 如c=ai,可以随便选择数组形式或者是指针形式 也既是:作为函数参数时、在语句或表达式中使用数组时,我们可以采纳数组或者指针的任何一种形式,除此之外的其他状况下,指针和数组不要互换。下面就数组和指针一样的状况做具体的说明:规章1、表达式中的数组名被编译器当作一个指向该数组第一个元素的指针。 假设我们声明:inta10;int*p=a; 就可以通过一下任何
18、一种方式来访问ai: pi*(p+i)*(a+i) 事实上,可以采纳的方法许多。对数组的引用如ai在编译时总是被编译器改写成*(a+i)的形式,C语言标准要求编译器必需具备这个概念性的行为。 编译器自动把下标值的步长调整到数组元素的大小。假如整型数的长度是4个字节,那么ai+1和ai在内存中的距离就是4。对起始地址执行加法操作之前,编译器会负责计算每次增加的步长。这就是为什么指针总是有类型限制,每个指针只能指向一种类型的缘由所在,由于编译器需要知道对指针进展解除引用操作时应当取几个字节,以及每个下标的步长应取几个字节。规章2、下标总是和指针的偏移量一样。 把数组下标作为指针加偏移量是c语言从B
19、CPL(C语言的祖先)继承过来的技巧。在人们的常规思维中,在运行时增加对c语言下标的范围检查是不切实际的。由于取下标操作只是表示将要访问该数组,但并不保证肯定要访问。而且程序员完全可以使用指针来访问数组,从而绕过下标操作符。在这种状况下,数组下标范围检测并不能检测全部对数组的访问的状况。事实上,下标范围检测被认为不值得参加到c语言当中。 还有一个说法是,在编写数组算法时,使用指针比使用数组更有效率。这个颇为人们所接收的说法在通常状况下是错误的。使用现代的产品质量优化的编译器,一维数组和指针引用所产生的代码并不具有显著的差异。不管怎样,数组下标是定义在指针的根底上,所以优化器经常可以把它转化为更
20、有效率的指针表达式,并生成一样的机器指令。 规章3、在函数参数的声明中,数组名被编译器当作指向该数组第一个元素的指针。 在函数形参定义这个特别状况下,编译器必需把数组形式改写成指向数组第一个元素的指针形式。编译器只 向函数传递数组的地址,而不是整个数组的拷贝。这种转换意味着在声明函数的时候,以下三种形式都是合法的(同时无论实参是数组还是真的指针也都是合法的): my_function(int*turnip)my_function(intturnip)my_function(intturnip200) 用malloc为字符串安排存储空间时的留意事项(c缺陷与陷阱3.2节) 11 字符串常量(c和
21、指针.P269.) 当一个字符串常量消失在表达式中时,它的值是指针常量。编译器把该字符串的一份拷贝存储在内存的某个位置,并存储一个指向第一个字符的指针。我们可以对字符串常量进展下标引用、间接访问以及指针运算。“xyz”+1 字符串常量实际上是个指针,这个表达式计算“指针值加上1”的值。它的结果也是个指针,指向字符串中的其次个字符y*“xyz” 对一个指针执行间接访问操作时,其结果就是指针所指向的内容。字符串常量的类型是“指向字符的指针”,所以这个间接访问的结果就是它所指向的字符:x。留意表达式的结果并不是整个字符串,而只是它的第一个字符。“xyz”2 同样可以推断出上面这个表达式的值就是字符z
22、。 #include /承受一个无符号整型值,把它转换成字符,并打印出来 /假如是打印16进值的数,可以用这种方法:putchar(“0123456789ABCDEF“value%16)voidbinary_to_ascii(unsignedlongvalue) unsignedlongquotient;quotient=value/10;if(quotient!=0)binary_to_ascii(quotient);putchar(“0123456789“value%10); intmain() /字符串常量实际上是个指针,这个表达式计算“指针值加上1“的值。它的结果也是个指针, /指向字
23、符串中的其次个字符:yprintf(“%sn“,“xyz“+1); /对一个指针执行间接访问操作时,其结果就是指针所指向的内容。 /字符串常量的类型是“指向字符的指针“,所以这个间接访问的结果就是它所指向的字符:xprintf(“%cn“,*“abcdefg“); /同样可以推断出上面这个表达式的值就是字符zprintf(“%cn“,“abcdefg“3); binary_to_ascii(1234567); getchar(); return0; 用字符串常量初始化指针和数组(c专家编程.P87.) 定义指针时,编译器并不为指针所指的对象安排空间,它只是安排指针本身的空间,除非在定义时同时赋
24、给指针一个字符串常量进展初始化。例如,下面的定义创立一个字符串常量(为其安排内存):char*p=“breadfruit”; 留意只有对字符串常量才是如此。不能希望为浮点数之类的变量安排空间,如:float*pip=3.14;/*错误,无法通过编译*/ 在ANSIC中,初始化指针时所创立的字符串常量被定义为只读。假如试图通过指针修改这个字符串值,程序会消失未定义的行为。在有些编译器中,字符串常量被存放在只允许读取的文本段中,以防止它被修改。 数组也可以用字符串常量进展初始化:chara=“gooseberry”; 与指针相反,由字符串常量初始化的数组是可以修改的。比方下面的语句:strncpy
25、(a,“black”,5);将数组的值修改为“blackberry”。 #include#include intmain(void) char*p=“thisisaexample“; /char*pi=3.14;/这样定义是错误的,无法通过编译 /p0=“T“;/修改该字符串常量时,编译是没问题,但是运行时会消失特别 chara=“gooseberry“;strncpy(a,“black“,5); printf(“%sn“,p);printf(“%sn“,a); return0; 二维数组下标操作的相关概念(c和指针.P156.) 1415 16 指向一维、二维数组的指针(c和指针.P158.
26、) 17 array_name和/*arrayofMAXcharacters*/char*p=a;/*p为指向数组的指针*/ char*pa=/*该语句是不正确的,pa的类型为“char*“,而/*该语句是正确的,pb的类型为“char(*)MAX“*/ #include voidmain() chara5=“a“,“b“,“c“,“d“,“0“;char*p=a; /运行下面这句后,vc6.0提示的错误为:cannotconvertfrom“char(*)5“to“char*“, /所以,应当定义一个指向一样类型和大小的数组的指针来获得“point_to_str= printf(“%dn%d
27、n“,printf(“%sn%sn“,p,point_to_str); 运行结果为:12450441245040abcdabcd 数组作为函数的参数时,不能通过sizeof运算符得到该数组的大小 当把数组作为函数的参数时,你无法在程序运行时通过数组参数本身告知函数该数组的大小,由于函数的数组参数相当于指向该数组第一个元素的指针。这意味着把数组传递给函数的效率特别高,也意味着程序员必需通过某种机制告知函数数组参数的大小。为了告知函数数组参数的大小,人们通常采纳以下两种方法:第一种方法是将数组和表示数组大小的值一起传递给函数,例如memcpy()函数就是这样做的:memcpy(dest,sourc
28、e,length); 其次种方法是引入某种规章来完毕一个数组,例如在C语言中字符串总是以ASCII字符NUL(“0“)完毕,而一个指针数组总是以空指针完毕。请看下述函数,它的参数是一个以空指针完毕的字符指针数组,这个空指针告知该函数什么时候停顿工作: voidprintMany(char*strings) inti=0; while(stringsi!=NULL) puts(stringsi+); C程序员常常用指针来代替数组下标,因此大多数C程序员通常会将上述函数编写得更隐藏一些:voidprintMany(char*strings) while(*strings) puts(*string
29、s+); 尽管你不能转变一个数组名的值,但是strings是一个数组参数,相当于一个指针,因此可以对它进展自增运算,并且可以在调用puts()函数时对strings进展自增运算。 用strlen()求字符串的长度(c和指针.P159.) 库函数strlen的原型为:size_tstrlen(charconst*string); strlen返回一个类型为size_t的值。这个类型是在头文件stddef.h中定义的,它是一个无符号整型类型。在表达式中使用无符号数可能导致不行预期的结果。例如,下面两个表达式看起来是相等的: if(strlen(str1)=strlen(str2)if(strlen
30、(str1)-strlen(str2)=0) 但事实上它们是不相等的,第1条语句会根据预想的那样工作,但第2条语句的结果将永久是真的。strlen的结果是无符号数,所以操作符=左边的表达式也将是无符号数,而无符号数决不行能是负的。表达式中假如同时包含了无符号数和有符号数,可能会产生惊奇的结果。和上面的一对语句一样,下面两条语句并不相等,缘由一样。 if(strlen(str1)=10)if(strlen(str1)-10=0) 假如将strlen的结果值强制转换成int,就可以消退这个问题。类似的,sizeof()的返回类型也是size_t,和strlen()一样,也存在类似的现象(sizeo
31、f()是一个运算符,不是函数)。 对无符号类型的建议: 尽量不要在代码里面使用无符号类型,以免增加不必要的简单性。尤其是,不要仅仅由于无符号数不存在负值而用它来表示数量。 尽量使用像int这样的有符号类型,这样在涉及升级混合类型的简单细节时,不必担忧边界状况。 对于返回类型为无符号的函数(strlen()、sizeof(),最好将结果转换成整型((int)strlen()、(int)sizeof()),这样可以避开消失比拟微妙的bug(在java里面,就没有无符号数)。 #include#include#include intmain() charstr1=“0123456789“;chars
32、tr2=“abcdefghijk“; /sizeof()的返回类型也是无符号类型,无符号类型的运算结果也被转换成无符号类型,不行能为负/(int)sizeof(str1)(int)sizeof(str2)0这个表达式将得到预期结果if(sizeof(str1)-sizeof(str2)0)printf(“sizeof(str1)-sizeof(str2)“的计算结果是无符号型的,不行能为负n“);if(strlen(str1)=strlen(str2)printf(“strlen的返回值为无符号整型类型,把两个无符号整型类型做比拟,会得到预期的结果n“);if(strlen(str1)-str
33、len(str2)=0)printf(“strlen(str1)=%dn“,strlen(str1);printf(“strlen(str2)=%dn“,strlen(str2); printf(“(strlen(str1)-strlen(str2)=0)表达式的值为:%dn“,strlen(str1)-strlen(str2)=0);printf(“strlen(str1)-strlen(str2)“的结果是无符号类型,无符号数不行能是负值,所以该条件永久成立n“);/留意:sizeof()和strlen()取得的值是不相等的/sizeof()求得的长度包括字符串末尾的那个空字符“0“/st
34、rlen()求得的长度不包括字符串末尾的空字符printf(“sizeof(str1)=%dnstrlen(str1)=%dn“,sizeof(str1),strlen(str1); getchar();return0; char*和constchar*的兼容性问题(c专家编程.P19.) 有时候必需特别专注的阅读ANSIC标准才能找到某个问题的答案。一位销售工程师把下面的代码作为测试例子发给SUN的编译器小组。 #include voidfoo(constchar*P) intmain(intargc,char*argv) foo(argv); return0; 在VC6.0下编译这段代码,
35、编译器会发出警告: cannotconvertparameter1from“char*“to“constchar*“ 提交代码的工程师想知道为什么会产生类似的警告,他认为,实参char*s与形参constchar*p应当是相容的,标准库中全部的字符串处理函数都是这样的。那么,为什么实参char*argv与形参constchar*P实际上不能相容呢?答案是确定的,它们并不相容。现在我们回忆一下标准中有关简洁赋值的局部,它位于ANSIC第6.3.16.1节,描述了以下约束条件:要使上述赋值形式合法,必需满意以下条件之一: 两个操作数都是指向有限定符或无限定符的相容类型的指针,左边指针所指向的类型必
36、需具有右边指针所指向类型的全部限定符。 正是这个条件,使得函数调用中实参char*能够与形参constchar*匹配。它之所以合法,是由于在下面的代码中:char*cp; constchar*cpp;cpp=cp; 左操作数是一个指向有const限定符的char的指针;右操作数是一个指向没有限定符的char的指针; char类型和char类型是相容的,左操作数所指向的类型具有右操作数所指向类型的限定符(无),再加上自身的限定符const(留意反过来不能赋值)。 标准第6.3.16.1节没有说明char*实参加constchar*形参是否相容。标准6.1.2.5节中叙述实例的局部声称:const
37、float*类型并不是一个有限定符的类型,它的类型是“指向一个具有const限定符的float类型的指针”,也就是说const限定符是修饰指针所指向的类型,而不是指针。类似地,constchar*也是一个没有限定符的指针类型,它的类型是“指向有const限定符的char类型的指针的指针”。由于char*和constchar*都是没有限定符的指针类型,但它们所指向的类型不一样(前者指向char*,后者指向constchar*),因此它们是不相容的。因此类型为char*的实参和类型为constchar*的形参是不相容的,编译器会产生一条诊断信息。 空指针相关的问题(c缺陷与陷阱3.5节) #inc
38、lude#includeintmain()char*p=NULL;if(p=(char*)0)printf(“pisanullpointn“);elseprintf(“pisnotanullpointn“);/该语句不会引起编译错误,但是运行时会消失特别if(strcmp(p,(char*)0)=0)printf(“can“tdereferencepn“); /该语句不会引起编译错误,但是运行时会消失特别printf(“%d“,*p); getchar();return0; NULL和NUL的区分 NULL是在头文件中特地为空指针定义的一个宏。NUL是ASCII字符集中第一个字符的名称,它对应
39、于一个零值。C语言中没有NUL这样的预定义宏。留意:在ASCII字符集中,数字0对应于十进制值48,不要把数字0和“0“(NUL)的值混淆起来。 NULL可以被定义为(void*)0,而NUL可以被定义为“0“。NULL和NUL都可以被简洁地定义为0,这时它们是等价的,可以互换使用,但这是一种不行取的方式。为了使程序读起来更清楚,维护起来更简单,你在程序中应当明确地将NULL定义为指针类型,而将NUL定义为字符类型。 对指针进展解引用操作可以获得它的值。从定义来看,NULL指针并未指向任何东西。因此,对一个NULL指针进展解引用操作是非法的。在对指针进展解引用操作之前,必需确保它并非NULL指
40、针。 未初始化的指针和NULL指针的区分(c和指针.P95.) 未初始化的指针 NULL指针 26 理解函数的声明(c缺陷与陷阱2.1节)27 28 函数参数的传值调用(c和指针.P122.) #include charga=“abcdefghijklm“; voidmy_array_func(charca10) / printf(“printf(“ca=%#xn“,ca); printf(“printf(“ printf(“sizeof(ca)=%dnn“,sizeof(ca); voidmy_pointer_func(char*pa) / printf(“printf(“pa=%#xn“,pa); printf(“printf(“ printf(“sizeof(pa)=%dnn“,sizeof(pa);