C语言知识点总结

fun((w1,w2),(w3,w4,w5))   含有参数的个数是2个

左半部分是一个逗号表达式,右半部分是一个逗号表达式 。括号括起来的,算是一个表达式,所以一共

2个参数!

类型所占存储字节数

int 2;float 4;double 8;char 1;

一个指针变量中存放的是一个存储单元的地址值;一个存储单元的“一”所代表的字节数是不同的,

int 型一个存储单元占用2个字节,float型一个存储单元占用4个字节……

所以指针类型一定要与指针所指对象的类型保持一致!否则指针在进行移动时,会出错,达不到预期的目的!

int型移动到下一个需要“+2”,而double则需要“+8”,如果是int型变量,却用的是double型指针,则想移动到下一个相当于+8,而不是+2,

一下子移动了4个! 所以要保持一致!

除了赋地址值外,还可以给指针变量赋“空”值……eg: int *p=NULL    注意:NULL四个字母都是大写且 p=NULL;等价p=‘\0’;等价p=0;

在使用NULL时,需要在头文件预定义: #include "stdio.h"  NULL的值为0,当执行以上赋值语句后,称P为"空指针"!

^int *p;^ :在没有定义或赋值给P地址的情况下,P的地址是不确定的,并不一定是空值,而是一个随机的地址,在赋值"空值即NULL"后

P的值确定为一个"空值"!

求地址运算符 & 只能应用于变量和数组元素,不可用于表达式,常量,或register变量!(变量和数组都是有确定地址的,而表达式没有地址,如X+Y,只是调用X的地址中的值,和Y的地址中的值,

再进行运算,表达式本身没有地址;常量有地址,但是常量的地址并不确定,所以也求不出来;而register变量是"寄存变量",并不存储于内存当中,而是以其他方式存储,所以在内存当中找不到它的地址!)

&*就象乘和除一样,两者放在一起可约掉!他们是可以相互抵消的!

++或-- 的优先级别和*的级别是相同的!而+=或-=或*=或/=的优先级别仅高于逗号运算符,它们级别要比*的级别低!

++或--都是自右向左进行结合的,所以++*P先*P,再++,取出物体后将其本身+1,再放回原来的地址;  k=100,k++是先K后+,表达式值是100,K=101;++K,是先+后K,即表达式和K的值都是101;

*p++是自右向左进行的,先P++,指向原来P所指向的存储单元的下一个单元,再*(P++),即下一个存储单元的内容;所以(*P)++的括号不能

省略,这样才是指“*P中的内容,的本身+1,再放回原来的地址”;记注,++或--运算是自右向左进行的!

*叫做“间指运算符”!

只有当指针指向一串连续的存储单元时,指针的移动和比较大小才有意义,一定是“连续的存储单元”!

实参是地址的时候,形参对应的一定是“指针”;如果实参是指针的话,实际上也代表地址,所以形参对应的还是“指针”;

把数据从 被调用函数 返回到 调用函数 的唯一途径是通过return语句返回数值,这就限定了只能返回一个数据!用以下方法可解决想返回多个值的问题!

当调用函数时,在调用函数内部实参是地址值时,且对应的形参是个指针的话,那就可以通过形参的改变来改变实参的值,这样就不必局限于一个

return 语句只能返回一个值了,而是可以返回2个或2个以上的值;但一定要符合上述的应用条件!

当p=a时(P和A存放的都是数组的首地址时),a[i]=*(a+i)=p[i]=*(p+i)且 &a[i]=a+i=p+i;

*(p--) 相当于M=P--;先算M,P--是先P后-,所以M=P值不变,所以*(p--)=*p;

同理,a[i--]=a[m]  M表达式=I--,还是先I后-,所以a[y=i--]=a[y]  括号中的I的值有变化,比原来少1,但表达式y的值没有变化;

*--P  自右向左运算,先--P,使P的地址少一个,再取其值;

a[--i]还是相当于a[--i]=a[m] m是表达式--i,--I先-后I,I比原来少一个值,再算,即a[i]的前一个数组!;

p--  ,m=p--,  m=p,再p=p-1;   --p   ,m=--p  ,p=p-1,m=p;

当a和P 是相同地址时的区别:

如果a指 的是数组的话,那么A是不可以改变的,他是定植,而P的值可以改变;

所以   a++,a=p(或其他),p=&a(a已经是地址了,不需要再加一个求地址符),   即所有改变A的值的方法  都非法;

       P++,P=A,P=&a[i],即改变P 值的所有方法   都   合法;其余的在A与P的运用求数组上没有区别;

当数组名作为实参时,对应的形参可以为:

调用函数:aaa(int *a)=aaa(int a[])=aaa(int a[M])(M为数组个数)   ;其中*a,a[],a[M]中的A可以不写成A,可以改写成其他字母,

表示的含义是一样的,传递给相同的地址,或“开辟”一个首地址相同的数组(实际上并不是开辟一个新数组,而是引用传递上来的首地址),a[m]的理解形式同上(看似开辟一个数组个数为M的新数组,实际上是引用传递上来的首地址,与用*a是相同的道理)!

在定义数组时:int a[];是非法的,因为不能不确定数组的个数,从而内存不知道开辟多少空间;

如果主函数是a[m] ,调用函数中出现的是s[m],则s[m]只是形式上与a[m]相似,但在被调用函数中并没有为型参开辟一串存储单元,如果A与S是相同的地址则没有开辟新的存储单元,如果不同,则会开辟新的存储单元,但在调用函数结素后,新开辟的存储单元会被释放掉!

而只是开辟了一个指针变量的存储单元,在被调用函数中引用的数组元素实际上就是调用(实参)函数中的数组元素,调用函数只是把数组的首地址传递给了形参指针,所以仍然遵循“按值传递”。

调用函数的概念:

1:在调用函数fun中,形参a,可以写成a[n],a[],*a,他是一个指针变量,在调用函数FUN时,系统只为形参A开辟一个存储单元,并把MAIN函数

中的AAA数组首地址存进去,使他指向AAA数组地址;

2:如果在调用函数FUN中定义了一个数组B数组,那么在调用函数FUN中,系统为他开辟了一串连续的存储单元,B是一个地址常量,存放的是

B数组中的首地址;

3:但是在被调用函数FUN执行完毕后,系统将释放掉在FUN中定义的数组和指针的存储单元,

  所谓释放,就是释放掉数组和指针所占的存储单元,从而在C环境下当执行完毕FUN函数后,系统将找不到

  任何在FUN中定义的数组和指针,所以在调用函数中将定义的数组B的地址返回给住函数的指针P 的话,系统找不到B的位置,这时指针变量P将不指向任何对象而成为“无向指针”,因为释放掉的地址相当于将大门关闭,当去寻找它时,由于门没有打开,所以就当寻找错误处理了!。

所以:所有企图在调用函数FUN中返回“指针或数组”的地址的行为  都是 不能做到的!!!

在字符串当中,系统将自动在结尾加上‘\0’,用strlen计算字符串长度时不计‘\0’在内,而用sizeof计算字符串长度时将计算‘\0’的长度在内;

以'\0'结尾的字符型数组 都可以叫做“字符串”;在使用‘\0’前一定要加上头文件#include "stdio.h";

由于字符串以'\0'结尾,所以 若要定义一个含有10个字符的字符串,则需要一个11个元素的一唯字符数组;

如果元素长度在没加\0的情况下和字符串长度相同,那就不是合法的字符串了,在这种情况下,只把它当做字符数组,而不是字符串;

所以在定义字符串时,字符型数组元素的个数一定要大于当前字符的个数,比如8个元素的字符串,就至少需要9个元素的一唯数组进行存放;

在一唯数组中,可以有\0也可以没有,有的话是字符串,没有的话是普通的一唯数组;但是字符串一定要存放在一味数组里;即字符串存储单位就是一味数组;

字符数组中每个元素可以存放一个字符,但它并不限定最后一个字符应该是什么,但是字符串最后一个字符必须是'\0',即必须以\0结尾;

所以只有元素个数大于当前字符的个数,只有满足这个条件才可能成为字符串;

不能直接把字符串常量或其他字符数组中的字符串直接赋值给字符串变量;

%s  是输出 字符串的,并且%S后接的一定是地址,从而从此地址输出此地址与之后的串!

用%S格式输入字符串时,空格和回车都是作为输入数据的分割符,而不能被读入!  当输入的字符串长度超过字符数组所能容纳的个数时,系统并不报错,但会得到错误的结果!

当输入项为字符指针时,该指针必须已经指向确定的有足够的存储空间的连续存储单元;当输入项为数组元素地址时,输入数据将从这一元素开始存放,没有放满的后面的元素系统将默认为0或'\0',即空值;

scanf 与 gets 函数在输入字符串时的区别:在scanf中,空格与回车都是间隔符,而不能被读入;而gets函数空格是当作字符被读入的,只有回车是表示此字符串结素的意思;

printf与puts函数在输出字符串时的区别:在printf中,在输出字符串时并不自动输出回车,需要printf("%s\n",a);才能输出回车;而puts函数则自动输出回车;

gets与puts与scanf与printf在有关输入或输出字符串时,后面接的都是地址;

gets 与 puts函数在使用时需要加上头文件:#include "stdio.h";

在字符串数组当中,如果用字符串数组,相当于给这些字符串开辟存储单元;但如果用字符型指针数组,则虽然也可以同样输出那些在里面定义的字符串,但并没有为这些字符串开辟存储单元,用到这些字符串时,实际上只上用指针引用一下,在内存中没有内存!!!

数组是不能在执行语句中直接赋值的,只能一个一个的去赋值,一般在执行语句中用for语句为其赋值,或在定义语句中为其赋值,因为数组需要占用内存,所以 用的时候要求很严格;

但指针可以在执行语句和定义语句中以p="hasdkjfh i";形式直接赋值,因为它并没有占用内存,而只是使指针指向它,所以 不需要一个一个的赋值,随时赋值都是可以的;

转义字符:

\n  回车换行;                \t  横向跳格(tab);

\v  竖向跳格;                \r  回车符(至本行开头)

\f  换页符;                  \b  退格符;

\\  反斜杠符(一个反斜杠)    \‘  单引号字符;

\“ 双引号字符;              \ddd  (ddd代表一个3位的8进制数,\ddd将其变为10进制的数,此10进制数对应的字符就是\ddd所转义的字符!)

\0  空值;                    \xhh  (x是小写,代表是16进制;hh是一个2位的16进制数;\xhh将hh变为10进制数,此10进制数所对应的字符就是\xhh所转义的字符!)

转义字符只代表一个字符;\后的8进制数不能用0开头;\后的16进制由小写x开头,但不容许大写X或0x开头;

第10章:字符串……最后一节“19课后习题讲解”  中的第3题有个转义字符有问题,第5题很好,对理解指针型的数组很有用!

5题:其中aa[0],aa[1]是指向字符串asdf,ASDF的,并且存放了a,A的地址,即首地址,它们是 指针;D选项指的是只指向a,A的地址,这样的话下一项就是随机值,因为它本身没指向串,所以错了!;aa[0]+n,aa[1]+n都是地址,*(aa[0]+n) 是地址中的物体!;

在函数中“定义”和“说明”的区别:

定义是 为变量 开辟存储空间;而说明只是在函数中 告诉系统有这么个东西,否则系统将不能进行识别,但并没有开辟任何存储空间!;

局部变量和全局变量的 差别:

局部 变量在对应的 函数中结束调用后将释放掉存储在空间中的值,所以其他函数 将无法使用;但是 全局变量是在整个编写的 函数的 最后结束的 时候才将变量释放掉,所以在此期间其他函数可以使用而无需任何说明;在调用函数中,当结束调用的 时候,该调用函数将把所有的在此调用 函数中定义的 局部变量 他们的 临时存储空间释放掉,所以在其他函数中不能使用!

register也是自动类变量 ,它与auto的 区别是:register说明 变量 时时将变量存储 在 CPU当中,从而使计算速度加快,而 不是像一般变量那样,占用内存单元!

但是CPU       中的 寄存器 是有限的 所以只能定义少量的 寄存器 变量!CPU 中的 地址无法显示,所以 register变量没有地址,也就不能对它进行求地址运算!

其他的一般变量是可以直接pirntf("%d",&a); 这样直接输出a变量的 地址的 !地址是一个数!

static静态局部变量:

在 整个程序运行期间,静态局部变量存储在内存的 静态存储区 在其中占据着永久性的 存储单元;静态局部变量的初值是在编译时赋予的 在程序执行期间不再赋予;对于未赋予初值的 静态局部变量,C程序自动给它赋予初值 0 ! 

static 与 extern 的区别:

虽然两者都是静态变量,但static只限本编译单位使用,在其他编译单位中无法引用;而extern 可以在另一个单位中再次声明引用!

相关推荐