*将程序分解成符号的过程,称为词法分析,每一个符号应该包含尽可能多的字符(贪心法)
*‘ ’空格符ASCII码值32,除了字符串和字符常量,符号的中间不能嵌有空白,老版C中允许用=+代替+=
*用单引号引起的一个字符实际上代表一个整数,整数值对应于该字符在编译器采用的字符集中的序列值,用双引号引起的字符串,代表的却是一个指向无名数组的起始字符的指针,该数组被双引号之间的字符以及一个额外的二进制值为0的字符'/0'初始化
* 'yes' 在vc6.0中最后得到的整数值即最后一个字符的整数值,在BORLAND C++中为y的整数值
* float (*h)()则h是一个函数指针,h所指向函数的返回值为浮点类型
*任何一个逻辑运算符的优先级低于任何一个关系运算符,移动运算符优先级比算术运算符低,比关系运算符高,按位异或运算符(^)的优先级介于按位与运算符与按位或运算符之间
*当一个声明的结尾紧跟一个函数的定义时,如果声明结尾的分号被省略,编译器可能会把声明的类型视作函数的返回类型
*f()是一个函数调用语句,而f;计算函数f的地址,却不调用该函数
*C中只有一维数组,而且数组的大小必须在编译期间就作为一个常数确定下来
*int a[3]; &a 是一个指向数组的指针,int *p = &a 在ANSI C中非法
*任何指针都是想象某种类型的变量
*给一个指针加上一个整数,与给该指针的二进制表示加上同样的整数,两者的含义截然不同
* *(a + 1)是数组a中下表为1的元素的引用,即a[i],由于a + i 与i+a的含义一样,因此a[i]与i[a]也具有同样的含义
* i = calendar[4][7]
i = *(calendar[4] + 7)
i = *(*(calendar + 4) + 7)
int calendar[12][13]; int *p; int i;
p = calender非法,因calendar是一个二维数组,再次上下文中使用calendar名称会将其转换为一个指向数组的指针,而p是一个指向整型变量的指针
int (*ap)[31];声明了*ap是一个拥有31个整形元素的数组,因此ap就是一个指向这样的数组的指针
*拼接字符串s和t
char *t; strcpy(r,s); strcat(r,t);错误,因为不能确定r指向何处
char r[100]; strcpy(r,s); strcat(r,t); 只要r和s执行的字符串不太大, 就正确
C语言会自动的将作为参数的数组声明转换为相应的指针声明
int strlen(char s[]){}等价于int strlen(char *s){}
extern char *hello 与extern char hello[]完全不同
*main (int argc, char *argv[]){}等价于main(int argc,char **argv){}前一种写法强调的重点在于argv是一个指向某数组的起始元素的指针,该数组的元素为字符指针类型
* char *p,*q;
p = "xyz";
p的值是一个指向由‘x',’y',‘z','/0'4个字符组成的数组的起始元素的指针
*赋值指针并不同时复制指针所指向的数据
*由0转换来的指针不等于任何有效地指针,当我们将0赋值给一个指针变量时,绝对不能企图使用该指针所指向的内存中存储的内容
*变量是对程序中存储空间的抽象
*指针变量定义:存储类型 数据类型 *指针名
存储类型指指针本身的存储类型,数据类型指指针的目标变量的数据类型
*不能用auto类型变量的地址初始化static型指针,如int i; static int *p = &i;错误
*void *类型指针表示不指定p是指向那一种类型数据的指针变量,使用时要进行强制类型转换
*程序中不能返回形参或局部变量的地址
*scanf("%d,%d,%d",&a,&b,&c);与scanf("%d,%d,%d/n",&a,&b,&c);运行结果不同
*函数在编译时被分配的入口地址(程序段的存储地址)称为函数指针,用函数名表示
*指向函数的指针变量:数据类型 (*指针变量名)();
数据类型是函数返回值的类型
*再给一个指向函数的指针变量赋值时,不用带参数,如p = max而不能p = max(x,y)
*p = a + i;是p指向二维数组的第i行
二维数组形参实际上是一位数组指针变量int a[][10] int (*x)[10]
二维数组存储空间固定,字符指针数组相当于可变列长的二维数组
*调出调试界面:F5,设置断点F9,F10把函数调用当成一个语句,而F11一步步执行
*int *p[3];指针数组
int (*p)[3];指向一位数组的指针
int *p(int);返回整型值真的函数
int (*p)(int)指向函数的指针,函数返回int型变量
int *(*p)(int);指向函数的指针,函数返回int型指针
int (*p[3])(int);函数指针数组,函数返回int型变量
int *(*p[3])(int);函数指针数组,返回int型指针
*若有struct student *p = &stu_1;
(*p).n等价于p->n;
p->n++ 等价于(p->n)++;
++p->n 等价于++(p->n)
*判断二进制文件是否结束:int feof(FILE *fp)
*%d整数形式转换输出
%ld长整数形式转换输出
%f带小数点形式转换输出(默认精确到小数点后6为,四舍五入)
%10d会有5个空格
%7.2f 7表示所有数字及小数点多占的位数,不够7位右对齐,2表示精确到小数点后2位
* /0产生一个空字符
*scanf中转换字符串:%d,%ld,%f,%lf
*float tax_rate; 在内存中分配一块32位存储空间,存储空间使用名称tax_rate标识
*scanf提供变量的地址
*fopen若不能打开指定的文件,则返回一个空指针NULL,其值为头文件stdio.h中被定义为0,正常退出时“程序状态值”为零,非零表示程序出错退出
*对二进制文件进行读写操作时,必须使用feof()函数来判断是否遇到文件尾,即:
!feof(input),其中input为指向源文件的指针
* if ( p == (char *) 0)正确
if ( strcmp(p ,(char *) 0 ) == 0)错误,因为strcmp函数的实现中包括查看他的指针参数所指向内存中的内容操作
*避免栏杆错误:用第一个入界点和第一个出界点表示一个数值范围
*另一种考虑不对称边界的方式:把上界视为某序列中第一个被占用的元素,把下界视为序列中第一个被释放的元素
* --n >= 0与n-- >= 0执行速度一样快,甚至更快。--n >= 0的大小先从n中减去1,然后将结果与0比较,第二个表达式首先保存n,从n中减去1,然后比较保存至与0的大小
*数组中实际不存在的“溢界”元素的地址位于数组所占内存之后,这个地址可以用于赋值和比较,若要引用该元素,那就是非法的啦
*C语言中只有四个运算符(&&,||,?:,,)存在规定的求值顺序,其他未定义。特别,赋值运算符并不保证任何求值顺序
*f(x,y)中的求值顺序是未定义的,g((x,y))的却是确定的先求x再求y,函数g只有一个参数,这个参数的值是这样求得的:先求x然后将x丢弃,再求y
*只有两个操作数都是有符号整数时,“溢出”才可能发生,为避免溢出,可将操作数都强制转化为无符号整数(unsigned)或者if( a > INT_MAX - b) complain();
*一个返回值为整数的函数如果返回失败,实际上是隐含的返回了某个“垃圾”整数,大多数C语言的实现都通过函数main的返回值来告知操作系统该函数的执行是成功还是失败,0代表成功,非0代表失败。
*某些C语言的实现提供了一个称为lint的程序,可以捕获连接器解决不了的错误
*若干个源程序可以再不同的时候单独进行编译,然后由连接器整合到一起,连接器并不理解C语言,然而它却能够理解机器语言和内存布局,连接器通常是把目标模块看成是由一组外部对象组成,每个外部对象代表着机器内存中的某个部分,并通过一个外部名称来标识,因此程序中的每个函数和每个外部变量,如果没有别声明为static,就都是一个外部对象
*连接器的输入是一组目标模块和库文件,输出是一个载入模块
*当连接器读入一个目标模块时,它必须解析出这个目标模块中定义的所有外部对象的引用,并作出标记,说明这些外部对象不再是未定义的
*int a;如果其位置出现在所有函数体之外,那么它就被称为外部对象a的定义
*C中未指定初始值的外部变量被初始化为0
*extern int a; 从连接器的角度看,上述声明是一个外部对象a的引用,而不是对a 的定义,即使它出现在函数的内部,也仍然具有同样的含义
*每个外部对象都必须在程序某个地方进行定义,因此,如果一个程序中包括了语句extern int a ,那么这个程序就必须在某个地方包括语句int a,这两个语句既可以出现在同一个源文件中,也可以位于不同的源文件中
*为了避免可能出现的命令冲突,如果一个函数仅仅被同一个源文件中的其它函数调用,我们就应声明改函数为static
*如果一个函数在被定义或声明之前被调用,那么他的返回类型就默认为整型
*如果一个函数没有float,short,char类型的参数,在函数声明中完全可以省略参数类型的说明,但函数定义中不能省略参数类型的说明
*声明可以有多次,定义只有一次
*一些内置函数:
double sqrt(double x);
double pow(double x, double y);
double ceil(double x);不小于x的最小整数
double floor(double x);不大于x的最大整数
int toupper(int x);
int tolower(int x);
int rand(void);
void exit(int retval)