C语言笔记

      再看C语言发现有很多没清楚的地方,写在这里作为一个笔记,高手飘过!!

1.  C语言规定char类型占一个字节,如果在你的机器中char为16位,那么当你用sizeof运算法计算double(假设机器中double64位)时,值为4;即:sizeof(double)结果为  4.

2.  刷新输出缓冲区的3中情况:缓冲区满、遇到换行符(\n)、遇到要求输入

3.  sizeof以字节为单位给出其操作数的大小,如果其操作数为类型必须使用小括号(sizeof(int)  sizeof n  (int n;)),sizeof返回size_t类型,strlen以字符为单位给出字符串的长度且不包括字符串结尾的空字符('\0')。strlen的计算遇到空字符时立即结束,sizeof则计算类型包含的全部空间。

4.  scanf()将键盘输入的文本转换为所需的数据类型(整形,浮点型,字符串等),scanf返回读入成功字符的个数,如果没有成功读入字符则返回0,如果遇到文件末尾则返回EOF(EOF为-1,在stdio.h中定义);printf()将各种类型转换为文本输出。

5.  赋值表达式的值是其左侧的值。a = 1,这个表达式的值为a 的值即1.

6.  scanf进行输入时,当scanf遇到不匹配的输入时将不匹配值留在输入流中,在下一次调用scanf再次尝试用此值进行输入。

7.  关系运算符的优先级低于算术运算符但是高于赋值运算符;!优先级高于乘法,和增量运算符(++、--)相同仅次于圆括号;&&优先级高于||,这二者低于关系运算符但是高于赋值运算符;条件运算符也高于赋值运算符?:。

8.  逗号运算符从左至右依次执行,逗号只是顺序符,逗号左边的所产生的所有副作用都在程序运行到逗号右边之前生效(变量值的改变),其最终值为右边表达式的值。

9.  关系运算符的运算结果为真、假,真(true = 1),假(false = 0)。

10.  putchar()接收一个大于一个字节的参数时,用参数的第字节决定输出字符。

11.  getchar()和putchar()不是真正的函数,而是定义为预处理器宏。

12.  缓冲分完全缓冲和行缓冲,键盘属于行缓冲输入方式。

13.  流是一个理想化的数据流,实际的输入或输出(包括文件和设备)会映射到流上,这样会让不同属性的多种输入输出具有统一的属性,C程序处理流而不是处理特定的文件。键盘和显示设备作为每个C程序自动打开的文件(流)对待,键盘用stdin流表示,显示设备由stdout流表示,getchar()、putchar、printf、scanf同这两个流打交道。

14.  一般情况下getchar返回0-127之间的值,对于一个扩展的字符集,则可能返回0-255之间的值。getchar可以读取到文件末尾(EOF),因此在接收getchar返回值时应保存在int类型的变量中,不能存在char类型的变量中,对于char类型是有符号整型表示的系统中是可以的。

15.  getchar()和scanf()区别:getchar接受输入流中的任何字符,包括空格和换行符;scanf将跳过空格,并将换行符留在输入流中,不读入;因此在编写程序时一般可以用putchar和scanf配合,用putchar剔除输入流中错误的或不需要保留的字符。

16.  函数原型的声明可以放在main函数之外开始的之前的位置,亦可以放在main函数内变量声明的任何位置。

17.  实际参数的形式可以是常量、变量或一个复杂的表达式;任何形式的参数传递都是值传递形式,即实际参数的值被复制一份给形式参量。

18.  当一个函数被调用时其形式参量被创建,并且用实际参数计算后的值对创建的形式参量进行初始化。

19.  函数返回值可以是常量、变量的值和任何表达式计算得到的值。

20.  函数的声明仅仅将函数的类型告诉编译器,函数的定义是函数功能的具体实现;一般函数的声明包含在所使用的头文件中。

21.  void print()和void print(void)函数原型声明在ANSI C中有点不同,第一个ANSI C的编译器会假设你没有使用函数原型声明,不会进行参数检查,后面那个表示不接受任何参数,在调用时会检查是否非法传参。

22.  C语言中所有函数地位等同,main函数可以被其它函数调用,也可以被其自身递归调用。

23.  const int array[10],只读数组在声明时必须进行初始化,不能在声明只读数组后对其进行初始化;自动类型的变量和数组在声明时不会进行初始化;初始化列表个数大于数组维数则编译报错,若少于不足的被初始化为0。

24.  C99标准之前声明数组时方括号内只能使用整数常量表达式,在C中数值整数(ex:23)、宏定义数值整数(ex:# defineSIZE 5)、sizeof表达式被认为是整数常量,const值不是整数常量(与c++不同);并且表达式的值必须大于0。

25.  只有在函数原型和函数定义头的场合中才能用int *array代替int array[].

26.  C保证在为数组分配存储空间的时候,指向数组之后的第一个位置的指针也是合法的(但是对这一地址里面的内容不作任何保证),这常用语两个指针访问数组时。

27.  一元运算符*和++优先级相同,但是其结合方向是从右至左的,因此*ptr++和*(ptr++)是不一样的。

28.  当创建一个指针时(指针未初始化ex:int *ptr),系统只分配了用来存储指针本身的内存空间,并不分配用来存储指针所指内容(存储数据)的内存空间。

29.  ANSI C规定如果多个字符串文字中间没有间隔或者间隔是空格符,则将它们串联起来看作是一个字符串(char *ptr = "hello" "world" 等价于 char *ptr = "helloworld");字符串常量属于静态存储类,即多次调用的过程中只有一个副本存在;整个引号中间的所有内容作为指向该字符串存储我只的指针 ,如&"hello"为"hello"在内存中的地址。

30.  用字符串常量初始化时,字符串数组和指向字符串的指针都是在程序运行时才进行初始化;字符串数组初始化是从静态存储区将一个字符串复制给数组,字符指针初始化则是将字符串的地址复制给指针变量;字符指针也可以用数组形式访问字符串的值。

31.  一般不要使用字符指针指向一个字符串常量(ex:char *p = "Hello"),因为在有些编译器中会将所有对"Hello"的引用都用同一个内存地址代替,如果某一指针改变了"Hello"的值,则其余使用"Hello"的地方都有可能会受到影响,ANSI C 也不建议如此做。一个可以替代的方案:const char *p = "Hello",阻止通过p改变相应的字符串,或者char p[] = "Hello",如此会导致字符串的复制,而不是地址的复制。

32.  如果想要将一个字符串读入到程序中,必须首先预留存储字符串的空间;char *name; scanf("%s", name);name是一个位初始化的指针,可能指向任何位置,会导致致命错误;可以讲name声明为数组,或者用内存分配函数分配空间。

33.  gets()函数的原型是char *gets(char *s){... return s}(不是精确的);ptr = gets(s);这里s必须是初始化(分配过空间)的指针,ptr则可以用返回值进行初始化,ptr的值和s的值相等;gets遇到文件尾返回NULL;gets的不足是它不检查预留空间是否能够容纳实际输入的数据,多出来的字符简单的溢出到相邻的内存区。

34.  fgets()函数需要一个参数n指定读入字符数,读到n-1个字符或者遇到换行符结束;fgets会将读取到的换行符存储在字符串中,stdin代表标准输入(一般指键盘)。

35.  一个C变量具有3种链接属性之一:外部链接,内部链接(static声明),空链接;具有代码块作用域或者函数原型作用域的变量有空链接属性,即此变量仅在代码块或者函数原型所私有;具有文件作用域的变量可能有内链接或外链接属性,内链接变量仅在当前文件中可见,外链接可在一个程序多个文件中可见。

36.  一个C变量具有两种存储时期之一:静态存储时期和自动存储时期;如果一个变量具有静态存储时期,它将在程序执行期间一直存在(文件作用域变量具有静态存储时期,37.  static声明变量的链接类型并非储存时期)。具有代码块作用域的变量一般(static声明除外)具有自动存储时期,程序进入定义这些变量的代码块时为其分配内存,当退出代码块时释放其内存。

38.  C使用作用域、链接和存储时期定义了5种存储类:自动(auto)、寄存器(register)、具有代码块作用域的静态、具有外部链接的静态、具有内部链接的静态(static)。

自动变量除非你进行显示的初始化,否则自动变量不会被自动初始化。

39.  寄存器变量一般存储在寄存器中(看寄存器资源等因素),因此不能用&获取其地址;它也具有代码块作用域、空链接、自动存储时期这些属性。可以使用register声明的类型是有限的,一般为int型,double这些则不行。

40.  静态变量(static)是指变量的存储位置在程序运行周期中固定不变,若没有对其显示进行初始化,则它被初始化为0;对于函数的参数不能声明为静态类型。

41.  外部变量(extern)可以被显示的初始化,不同于自动变量的是只可以用常量表达式来初始化文件作用域的变量;若没有对外部变量进行显示的初始化,则它们将自动被初始化为0。

42.  外部(文件作用域)变量定义声明和引用声明(extern)区别:定义声明要求分配存储空间,引用声明告知编译器参考之前对此变量的定义不分配内存空间;一个外部变量只可以进行一次初始化,而且一定是在变量被定义时进行的。

43.  函数也具有存储类,函数可以是外部的(默认)或者静态的和内联的(C99标准);外部函数可以被其它文件中的函数调用,静态函数只可以在定义它的文件中使用。

44.  time()可以返回系统时间,它的返回值为数值类型;一般来说time函数的参数为time_t类型对象的地址,时间值存在这个参数对象中,然而可以传送空指针(0)作为参数,此时时间仅通过返回值机制提供。为获取数值时间很有用,ex:(unsigned int)time(0)。

45.  free()可以使用不同于malloc()指针的指针变量,但必须一致的是指针中存储的地址;如:int * mymalloc(){... temp = malloc() ... return (int *)temp;}  pt = mymalloc; free(pt)和free(temp)都可以释放分配的内存。int(* p)[6]; p = (int (*)[6])malloc(n*6*sizeof(int))--->分配多维数组。

46.  C程序中的内存可以大致分为3中类型:静态变量的静态存储区在编译时分配在程序运行过程中一致存在;自动变量使用的堆栈内存,在程序运行过程中分配和释放;动态分配内存区由调用内存分配函数分配和释放。

47.  将常量放在一个头文件中时,一般来说必须声明为使用静态外部存储类(static const double PI = 3.14),只有这样避免在多个文件中包含此头文件时出现重定义现象(static限制了所有的常量只能在本文件中使用,由于常量都一样所以每个文件实际用到的变量虽然是不同的拷贝,但是值是相同的没有影响)。

48.  C程序自动打开3个文件:标准输入(stdin通常为键盘),标准输出(stdout通常为显示器),标准错误输出(stderr通常是显示器);getcha、gets、scanf;putchar、puts、printf。

49.  exit函数关闭所有打开的文件并终止程序,同时exit中的参数还会传递给操作系统;exit函数和return函数有很大的不同,无论何时调用了exit都将导致程序的终止,因此在递归等一些特殊的地方只能使用return函数;非main函数中调用exit也将终止程序。

50.  C程序只有在读取超出文件结尾以后才会发现文件的结尾,因此对文件输入不能使用do while循环。

51.  fclose函数成功关闭文件返回0,否则返回EOP。

52.  如果需要在不损失精度的前提下保存或恢复数据,使用二进制模式,并利用fread和fwrite函数;如果是保存文本信息或创建可以用普通文本编辑器查看的文件,使用文本模式getc和fprintf之类的函数。

53.  结构体的声明仅仅是告知编译器如何表示数据,并没有让计算机为数据分配空间;结构体变量的定义struct book lib;为其分配空间;结构体变量的初始化和数组类似,并且其约束规则与普通变量相同。

54.  ANSI C允许把一个结构体赋值给另一个结构体(不能对数组这样做),相对应的成员相互之间进行赋值,即使包含数组数据成员亦可以进行赋值,此时的数组相当于直接赋值;结构体变量可以作为函数参数传递,也可以作为函数的返回值。

55.  在结构体中成员使用字符数组还是字符指针:结构体中的字符数组可以用在任何场景,而字符指针只能用于管理已创建的而且在程序其它地方已经分配空间的字符串;否则如果未对字符指针进行空间分配直接用其存储字符串则相当于使用了未初始化的字符指针一样,可能引起严重的后果,一个解决方法是在需要时对字符指针使用malloc进行内存分配(指针的初始化),最后记得使用free释放内存。

56.  结构体的伸缩型数组成员:伸缩型数组成员必须是最后一个数据成员;结构体中必须至少有一个其他成员;伸缩型数组成员想普通数组一样被声明,但是后面方括号内是空的;伸缩型数组成员不占用空间(未分配前)一般都是创建一个结构体的指针变量,并用malloc函数分配足够的空间,包括分配给伸缩数组成员的空间;ex:struct test *pf; pf = (struct test *)malloc(sizeof(struct flex) + size_t),size_t 为伸缩型数组的空间。

57.  结构体数据的保存到文件中一般使用二进制文件形式(fread,fwrite),主要是为了保存的高效和检索的方便。

58.  枚举类型声明代表整数常量的符号名称,实际上,enum常量是int类型的,在使用int类型的任何地方都可以使用它;默认枚举中的值从0开始,依次递增步长为1且递增以当前数据的前一个值为基准。

59.  typedef由编译器进行解释,而不是预处理器;typedef定义的作用域取决于它所在的位置,与变量相同。

60.  一个特殊的应用,如果两个结构体的声明都不适用标记,但是使用了相同的数据成员(成员名和类型均要求匹配),则C认为这两个结构体具有相同的类型;struct {char x;double y;} r1={'A', 2.0};   struct {char x;double y;} r2;r2=r1。

61.  C语言中声明时可以使用的修饰符,* 代表一个指针;()代表一个函数;[]代表一个数组;这些在使用时具有标记作用,尤其是较复杂的typedef声明时;ex:typedef char(*FRPTC())[5],()具有较高的优先级,因此优先解读--->将FRPTC声明为一个函数类型,该类型的函数返回一个指向含有5个元素的char数组的指针。

62.  ()和[]具有相同的优先级,并且结合方式至左至右,这在复杂的变量声明中很有用。

63.  位操作正对整形常量和变量,char类型也是整形的一种;左移操作空位补0,右移操作空位补位结果依机器而定;左移相当于乘以2的n次幂(n为移动位数),右移当操作数非负时相当于除以2的n次幂。

64.  对位进行操作的第二种方法是使用位字段,位字段是一个signed int或unsigned int中一组相邻的位,位字段由一个结构声明建立,该结构声明为每个字段提供标签,并决定字段的宽度;struct{unsigned int bit1 :1; unsigned int bit2 :1; unsigned int bit3 :2;}bit;可以像给结构体成员赋值一样的进行赋值,但是值必须在位的范围内,bit.bit1 =0;bit.bit2=1;bit.bit3=3;如果一个声明的总位数超过了一个unsigned int的位数则在一个unsigned int中继续存储,但是不允许一个字段跨越两个unsigned int之间的边界,编译器自动移位一个这样的字段定义,使字段按unsigned int边界对齐;这样会在第一个unsigned int中留下一个未命名的空洞字段,你可以使用未命名的字段宽度"填充"未命名的洞,使用一个宽度为0的未命名字段迫使下一个字段与下一个整数对齐;struct { unsigned int bit1: 1; unsigned int    : 3; unsigned int bit2: 2; unsigned int    : 0; unsigned int bit3: 3;};字段的放置位置依机器而定(从左至右或从右至左)。

65.  程序的编译步骤:1.编译器首先把源代码中出现的字符映射到源字符集(处理多字节字符)2.编译器查找反斜线紧跟的换行符实例,并组合在一起(较长的行写在多行上这时被组合成连贯的一行,因为预处理器是以逻辑行为单位进行处理的)3.编译器将文本划分为预处理语言符号序列(预处理部分)和空白字符及注释序列(用空格代替注释)4.进行预处理(预处理指令均是以#开始标识的)。

66.  预处理阶段不进行常量表达式的求值和任何计算工作,常量表达式的求值在编译阶段进行。

67.  const变量一般看作只读变量好些,因为它不能用来指定数组的大小。

68.  双引号字符串中的宏参数被看作普通文本不进行替换,如果你要对齐进行替换可以再其前面使用#,则可以将其转化成相应的字符串,该过程称为字符串化。

70.  可变宏:...和__VA_ARGS__  #define(...) printf(__VA_ARGS__),其中...代表可以接收的可变参数,__VA_ARGS__在展开中代表...。

71.  #define宏的作用域从文件中的定义点开始,直到用#undef指令取消宏为止,或者直到文件尾为止(二者中最先满足的那个结束宏的作用域),变量的代码块作用域对宏不起作用。

72.  C99支持内联函数,内联函数的定义和对该函数的调用必须在同一文件中,因此内联函数具有内部链接;在多文件程序中,每个调用内联函数的文件都要对内联函数进行定义,一个简单的方法为将内联函数定义在头文件中;因为内联函数具有内部链接所以在多个文件中定义同一内联函数不会发生重定义(与内部链接的变量一样)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值