在C语言中,数组参数是以引用(reference)形式进行传递的,也就是传址调用,而标量和常量则是按值(value)传递的。
scanf 一个数组参数时,前面不需要加上“&”符号。如char *str; scanf("%s",str)是正确的,scanf("%s",&str)也是正确的。(一维数组,即使加上一个“&”也没什么不对,因为编译器会把它解析为 &arr[0])
三个字母词(trigraph)是三个字母词的字符序列,合起来表示一个字符。例如:??( 表示 [ 。有的编译环境会默认忽略trigraph,如果要使用,请打开。
注释以/*开始,以*/结束,它不允许嵌套。注释将被预处理器去除。
具有静态存储类型的变量在整个程序执行过程中一直存在,而不仅仅在声明他的代码块的执行时存在。注意,修改变量的存储类型并不表示修改该变量的作用域,它仍然只能在该代码块内部按名字访问。具有external属性的实体总是具有静态存储属性。
为了保持最佳的可移植性,把字符的值限定在有符号和无符号字符范围的交集之内,或者不要在字符上执行算数运算。
用它们在使用时最自然的形式来表示字面值。
不要把整型值和枚举值混在一块儿使用。
不要依赖隐士声明。
在定义类型的新名字时,使用typedef而不是#define.
用const声明其值不会修改的变量。
使用名字常量而不是字面值常量。
不要在嵌套的代码块之间使用相同的变量名。
除了实体的具体定义位置之外,在它的其他声明位置都是用extern关键字。
由于c语言并不具备bool型,所以这些测试语句在测试值时用的都是整型表达式。零值为假,非零值为真。
c不具备任何输入输出语句,I/O是通过库函数实现的! 它们也是通过调用库函数来完成的。
switch语句中的case只是决定了循环进入的入口,然后会一直向下执行。(除非遇到break)。
a=x=y+3; 并不等同与a=y+3;x=y+3; 认为a和x被赋予了相同值y+3的想法是不正确的。 因为int a;char x;int y;则y的值赋给x是可能会被截短。
sizeof x ;等价与sizeof(x);
算术转换时,总是“倾向于”把操作数的类型转换为能表示更大范围的类型。转换顺序为int,unsigned int,long int ,unsigned long int,float,double,long double.
结构体分配内存时会进行“内存对齐”。它的起始存储位置必须满足能被4整除的地址。所以对结构体的成员列表进行重新排列,让那些对边界要求严格的成员首先出现,可以减少内存的浪费。
可以使用offsetof宏(定义与stddef.h) offsetof(type,member)来获取member在type中的位置(member存储的位置距离结构体开始的存储位置偏移的字节数)。
位段例子:
struct CHAR{
unsigned ch :7;
unsigned font :6;
unsigned size :19;
};
联合变量可以被初始化,但这个初始值必须是联合的第一个成员的类型,而且它必须位于一对花括号内。
用malloc函数分配内存后,要检查返回的指针是否为NULL。
只有动态分配的内存才可以用free函数释放,而且用完之后必须用free释放。
分配内存时使用sizeof来计算数据类型的长度,可以提高程序的可移植性。
字符串常量:当一个字符串常量出现在表达式中时,它的值是个指针常量。编译器吧指定字符的一份拷贝存在内存的某个位置,并存储一个指向第一个字符的指针。
"xyz"+1 是一个指向字符y的指针!"xyz"[2]就是字符z。
不同寻常的代码始终应该加上一条注释,描述它的目的和原理。
编译一个c程序的第一步是对它进行预处理。
不要在宏定义的末尾加上分号,使其成为一条完整的语句。
在宏定义中使用参数,但忘了在它们周围加上括号。
忘了在整个宏定义的两边加上括号。
避免使用具有副作用的宏。使用宏的时候一定要倍加小心。
可以使用编译选项-Dname=stuff 来定义一个变量的值其效果等于在源文件中加入 #define name=stuff 。
调试用的printf语句后面要加上fflush调用。
检查fopen的返回值。
改变问家的位置将丢弃任何被退回(unget)到流的字符。
再试用fgets时指定大小的缓冲区(不要用gets)。
使用gets函数时由于没有指定缓冲区大小,所以总会存在溢出的危险。不要使用gets.
使用scanf系列函数时,在每个非数组,非指针参数前加上&符号。
使用任何scanf系列函数时,格式代码和参数指针类型应匹配。
在使用scanf系列函数转换double,long double,short和long整型时,在各是代码中加上合适的限定符。
应防止sprintf函数的输入溢出缓冲区。
在有些长整数长于普通整数的机器上打印长整数时,应在格式代码中指定l修改符。
使用自动数组作为流的缓冲区时应多加小心。
int abs(int value),函数返回他的参数的绝对值。如果其结果不能用一个整数表示,这个行为是未定义的。(当value=INT_MIN;时就会出现这种情况。gcc编译器中将返回INT_MIN本身。
longjmp不能返回到一个已经不再处于活动状态的函数。
从异步新号的处理函数中调用exit或abort函数是不安全的。
避免exit函数的多重调用。
使用assert可以简化程序的调试。
遗留问题:
在你的系统中,你能声明的静态数组最大长度螚达到多少? 使用动态内存分配,你能获得的最大内存是多少? (感觉这个问题跟系统实现有关,需要了解系统内存分配的实现。
scanf 一个数组参数时,前面不需要加上“&”符号。如char *str; scanf("%s",str)是正确的,scanf("%s",&str)也是正确的。(一维数组,即使加上一个“&”也没什么不对,因为编译器会把它解析为 &arr[0])
三个字母词(trigraph)是三个字母词的字符序列,合起来表示一个字符。例如:??( 表示 [ 。有的编译环境会默认忽略trigraph,如果要使用,请打开。
注释以/*开始,以*/结束,它不允许嵌套。注释将被预处理器去除。
具有静态存储类型的变量在整个程序执行过程中一直存在,而不仅仅在声明他的代码块的执行时存在。注意,修改变量的存储类型并不表示修改该变量的作用域,它仍然只能在该代码块内部按名字访问。具有external属性的实体总是具有静态存储属性。
为了保持最佳的可移植性,把字符的值限定在有符号和无符号字符范围的交集之内,或者不要在字符上执行算数运算。
用它们在使用时最自然的形式来表示字面值。
不要把整型值和枚举值混在一块儿使用。
不要依赖隐士声明。
在定义类型的新名字时,使用typedef而不是#define.
用const声明其值不会修改的变量。
使用名字常量而不是字面值常量。
不要在嵌套的代码块之间使用相同的变量名。
除了实体的具体定义位置之外,在它的其他声明位置都是用extern关键字。
由于c语言并不具备bool型,所以这些测试语句在测试值时用的都是整型表达式。零值为假,非零值为真。
c不具备任何输入输出语句,I/O是通过库函数实现的! 它们也是通过调用库函数来完成的。
switch语句中的case只是决定了循环进入的入口,然后会一直向下执行。(除非遇到break)。
a=x=y+3; 并不等同与a=y+3;x=y+3; 认为a和x被赋予了相同值y+3的想法是不正确的。 因为int a;char x;int y;则y的值赋给x是可能会被截短。
sizeof x ;等价与sizeof(x);
算术转换时,总是“倾向于”把操作数的类型转换为能表示更大范围的类型。转换顺序为int,unsigned int,long int ,unsigned long int,float,double,long double.
结构体分配内存时会进行“内存对齐”。它的起始存储位置必须满足能被4整除的地址。所以对结构体的成员列表进行重新排列,让那些对边界要求严格的成员首先出现,可以减少内存的浪费。
可以使用offsetof宏(定义与stddef.h) offsetof(type,member)来获取member在type中的位置(member存储的位置距离结构体开始的存储位置偏移的字节数)。
位段例子:
struct CHAR{
unsigned ch :7;
unsigned font :6;
unsigned size :19;
};
联合变量可以被初始化,但这个初始值必须是联合的第一个成员的类型,而且它必须位于一对花括号内。
用malloc函数分配内存后,要检查返回的指针是否为NULL。
只有动态分配的内存才可以用free函数释放,而且用完之后必须用free释放。
分配内存时使用sizeof来计算数据类型的长度,可以提高程序的可移植性。
字符串常量:当一个字符串常量出现在表达式中时,它的值是个指针常量。编译器吧指定字符的一份拷贝存在内存的某个位置,并存储一个指向第一个字符的指针。
"xyz"+1 是一个指向字符y的指针!"xyz"[2]就是字符z。
不同寻常的代码始终应该加上一条注释,描述它的目的和原理。
编译一个c程序的第一步是对它进行预处理。
不要在宏定义的末尾加上分号,使其成为一条完整的语句。
在宏定义中使用参数,但忘了在它们周围加上括号。
忘了在整个宏定义的两边加上括号。
避免使用具有副作用的宏。使用宏的时候一定要倍加小心。
可以使用编译选项-Dname=stuff 来定义一个变量的值其效果等于在源文件中加入 #define name=stuff 。
调试用的printf语句后面要加上fflush调用。
检查fopen的返回值。
改变问家的位置将丢弃任何被退回(unget)到流的字符。
再试用fgets时指定大小的缓冲区(不要用gets)。
使用gets函数时由于没有指定缓冲区大小,所以总会存在溢出的危险。不要使用gets.
使用scanf系列函数时,在每个非数组,非指针参数前加上&符号。
使用任何scanf系列函数时,格式代码和参数指针类型应匹配。
在使用scanf系列函数转换double,long double,short和long整型时,在各是代码中加上合适的限定符。
应防止sprintf函数的输入溢出缓冲区。
在有些长整数长于普通整数的机器上打印长整数时,应在格式代码中指定l修改符。
使用自动数组作为流的缓冲区时应多加小心。
int abs(int value),函数返回他的参数的绝对值。如果其结果不能用一个整数表示,这个行为是未定义的。(当value=INT_MIN;时就会出现这种情况。gcc编译器中将返回INT_MIN本身。
longjmp不能返回到一个已经不再处于活动状态的函数。
从异步新号的处理函数中调用exit或abort函数是不安全的。
避免exit函数的多重调用。
使用assert可以简化程序的调试。
遗留问题:
在你的系统中,你能声明的静态数组最大长度螚达到多少? 使用动态内存分配,你能获得的最大内存是多少? (感觉这个问题跟系统实现有关,需要了解系统内存分配的实现。