argc与argv
参考链接:
数组与链表
参考链接:
数组和链表都是用来存储数据的,数组理解起来比较简单,但其有比较多的缺点:
- 数组的大小是固定的,部分程序员会偷懒定义一个比较大的数组,这就造成了空间浪费,因为C语言在编译的时候会根据声明的数组大小在内存中开辟一段连续的空间作为数组的存储地址,是在程序运行之前,而不是使用数组的时候;不但造成空间浪费,保不齐就还是会有超出程序员预想的长度,轻则模块停止运行。
- 数组时一次分配完全部内存,而链表则是在需要时再分配内存。
- 在数组的头部插入数据代价过大。
隐式转换
参考链接:
运算符优先级
-
++、-- 运算符的优先级大于乘、除、取余的优先级
-
关系运算符的优先级比算数运算符优先级低,但是比赋值运算符的级别高。
-
逻辑非的优先级高于逻辑与的优先级,而逻辑与的优先级又高于逻辑或的优先级。
-
条件运算符由
?
和:
组合而成,结合方向自右向左。 -
运算符的优先顺序
逻辑非 > ~ > 算术运算符 > 移位运算符 > 关系运算符 > & > ^ > | > 逻辑与 > 逻辑或 > 条件运算符 > 赋值运算符 > 逗号运算符
-
对于一个正数,原码是将该数转换成二进制,它的反码和补码与原码相同。对于一个负数,原码是将该数按照绝对值大小转换成的二进制数,最高位即符号位为1;它的反码是除符号位外将二进制数按位取反,所得的新二进制数称为原二进制数的反码;它的补码是将其二进制的反码加1。
break
- break语句是跳出循环体的语句,而非仅仅跳出break语句所在的if语句。
- break是跳出break语句所在循环语句的语句,并不是跳出所有的循环语句。
空间分配
- 为了方便处理具有相同类型的变量,C语言中使用数组来存储这些变量。
C语言在编译的时候会根据所声明的数组大小在内存中开辟一段连续的空间来作为数组的存储地址,因此,在声明时,必须声明数组的长度。并且,声明的数组大小不可以用变量,因为内存的分配在程序运行之前,而不是在使用数组的时候。
声明数组时,系统为变量分配连续的存储空间。
数组
一维数组
- 若给所有元素赋初值,“元素个数”可以省略。如:int a[ ]={1,2,3,4,5};
- 可以只给一部分元素赋初值,但元素个数不能省略。未被赋初值的元素则为0。如:int a[5]={1,2,3};。此时a[0]=1,a[1]=2,a[2]=3,a[3]=0,a[4]=0。
- 若使全部元素都为0,可以将其定义为“全局变量”或“静态变量”,也可以写成:int a[5]={0};a[5]={0,0,0,0,0}。
- 若数组在定义时未进行初始化,则各元素的值是随机的。如:int a[5];
- 上述数组初始化的方法都是在定义时进行的,用赋值语句是错的。
- 如果赋多初值,后续值被忽略。
- 字符型数组存放数据内容时,字符型与整型是互通的,但是用整型存放数据会造成空间浪费。
二维数组
- 若给所有元素赋初值,“行数”可以省略,但“列数”不能省。
- 二维数组的首地址及数组元素的地址只能用下面方式获得:
- 二维数组元素首地址:数组名 或 数组名[0] 或 &数组名[0][0]
- 二维数组第i行元素组成的一维数组首地址:数组名[i] 或 数组名+i(i表示二维数组第i行)
- 二维数组元素的地址:&数组名[i][j] 或 &数组名[i]+j(i表示二维数组第i行,j表示i表示二维数组第j列)
函数调用
- 被调函数作为函数语句单独出现
- 被调函数作为表达式出现
- 被调函数作为函数的参数出现
变量存储类型
- 自动型(auto),默认
- 静态型(static),自动变量在函数调用结束后其所占用的内存空间会被释放,有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,即其占用的内存空间不被释放,在下一次函数调用时,该变量已有值,这时就可以声明局部变量为“静态局部变量”,用关键字static进行声明。
- 局部静态变量是在静态存储区分配存储单元的,在整个程序运行期间都不释放。因此在函数调用结束后,它的值并不消失。
- 局部静态变量是在程序编译过程中被赋值的,且只赋值一次,在程序运行时其初值已经确定,以后每次调用函数时不再赋值,而是保留上一次函数调用结束时的值。
- 局部静态变量的初值为0(对整型变量)或空字符(对字符型变量)。
- 虽然静态局部变量在函数调用结束后仍然存在,但是其他函数是不能引用它的。
- 由于静态局部变量占内存多(长期占用不释放,不能像动态存储那样一个存储单元可以供多个变量使用),而且由于其值可以改变,不能弄清楚局部静态变量的当前值是多少,降低了程序的可读性,因此不建议过多地使用局部静态变量。
- 寄存器型(register),如果一些变量运用频繁,那么从内存中读取数据要消耗很多时间,为了提高程序的运行速度,C语言中允许将局部变量的值放在CPU中的寄存器中,需要时直接从寄存器中读取数据,不必再到内存中读取数据。这种变量称为寄存器变量,用关键字register声明。
- 只有局部自动变量和形式参数可以作为寄存器变量,其他类型的变量是不可以的。局部静态变量不能定义为寄存器变量。不能把变量既放在静态存储区又放在寄存器中,二者只能居其一。
- 一个计算机系统中的寄存器数目是有限的,不能任意定义多个寄存器变量。不同系统允许使用的寄存器变量也是不同的,而且对寄存器变量的处理方式也是不同的。有的系统将寄存器变量当做自动变量处理。
- 外部型(extern),全局变量是在函数的外部定义的,它的作用域是从变量的定义处开始到本程序文件的结束。如果在定义点之前的函数想要引用该变量,则应该在引用之前用关键字extern对该变量进行声明,声明该变量为外部全局变量。声明过后,就可以从声明处起,合法地使用该变量。
- extern不能用来初始化变量,即extern int a=3是不正确的。
- 使用extern的作用是扩展全局变量的作用域。
- 在系统编译遇到extern时,先在本文件中寻找全局变量的定义,如果找不到,在连接时从其他文件中寻找全局变量的定义。
- 在不同文件中引用全局变量时,因为全局变量的值可能会被改变,因此在使用时要特别注意。
- 静态全局变量,在设计一个程序时,有时不希望某些全局变量被其他文件引用,这时可以用关键字static对全局变量进行声明。
- 使用static声明全局变量,可以避免文件中的一些全局变量被其他文件引用。
- 无论是否对全局变量进行static声明,全局变量均是静态存储方式。
- 使用static声明的全局变量,在本文件中定义在全局变量之前的函数也是不能引用的。
- 供用户使用的存储空间分为三类:
- 程序区:存放可执行程序的机器指令
- 静态存储区:程序在运行过程中需要占用的固定存储单元的变量,如全局变量
- 动态存储区:在程序运行过程中根据动态分配内存空间的变量,如形式参数、局部变量。
宏定义
- 预编译时不做任何语法检查,只有在编译已被宏展开后的源程序时才会发现语法错误。
- 不占用内存空间
- 宏名的有效范围为定义命令之后到本源程序文件结束。可以用# undef命令来终止宏定义的作用域。
- 与函数区别:
- 函数在定义和调用中所使用的形式参数和实际参数都受到数据类型的限制,而带参数宏的形式参数和实际参数可以是任意数据类型。
- 函数调用时是先计算实际参数表达式的值,然后代入形式参数。而宏定义展开时,只是替换。
- 函数调用时,编译系统会为其分配内存单元,而宏展开时系统不会为其分配内存单元,宏展开也没有“返回值”的概念。
- 多次使用宏,宏展开后源程序增长,而函数调用不会使源程序增长。
- 函数只能有一个返回值,而用宏可以设法得到多个值。
条件编译
共有三种形式:
#ifdef 宏名
程序段1
#else
程序段2
#endif
或
#ifdef 宏名
程序段1
#endif
判断宏名在此之前是否被定义过,若定义过,则编译程序段1,否则编译程序段2。若没有#else
部分,则直接执行#endif
。程序段可以是语句组,也可以是命令行。
#ifndef 宏名
程序段1
#else
程序段2
#endif
或
#ifndef 宏名
程序段1
#endif
其中#ifndef
与#ifdef
作用相反,如果宏名没有被定义过,就编译程序段1,否则就编译程序段2。
#if 表达式
程序段1
#else 表达式
程序段2
#endif
或
#if 表达式
程序段1;
#endif
与普通的if语句一样,首先计算表达式
的值,如果为非0,就编译程序段1,如果为0,就编译程序段2或执行#endif
命令。