第5章
1, sizeof
sizeof(int) 返回整型变量的字节数
sizeof x 返回变量x占据的字节数,从定义上讲字符变量的长度为1个字节。
sizeof(数组名) 返回数组的长度,以字节为单位
判断表达式的长度并不需要对表达式进行求值。sizeof(a=b+1)并没有向a赋值
2前缀表达式和后缀表达式
前缀和后缀形式的增值操作符都复制一份变量值的拷贝。前缀操作在进行复制之前增加变量的值,后缀操作符在进行复制之后才增加变量的值,这些操作符的结果不是被它们所修改的变量,而是变量的拷贝。
3, 短路求值
&& 左操作数先求值,如果它的值为真,然后紧接着对右操作数进行求值。如果左操作数为假,那么右操作数不再进行求值,因为整个表达式的值肯定是假的。
|| 首先对左操作数进行求值,如果为真,则右操作数便不再求值。
4, (&&,||)与(| ,&)的区别
1,&&,|| 的短路求值性,而(| ,&)对两边的操作数都需要进行求值。
2,&&,||用于测试零值和非零值,(| ,&)用于比较操作数中对应的位。
5 逗号操作符
很少会想到用它。
6 . 和 ->
S是一个结构变量,s.a表示访问s中名叫a的成员。
当拥有一个指向结构的指针而不是结构本身,且欲访问它的成员变量时,就需要使用->操作符,而不是'.'。
7 布尔值
常用写法会出现错误的点:
#define FALSE 0
#DEFINE TRUE 1
if( flag == FALSE)
if(!flag)
if(flag == TRUE)
if(flag)
当flag设置为任意的整型值,呢么第2句判断是不等价的。提示:不要使用简写手法来测试变量时0还是非0,因为这类错误的 暗示该变量在本质上是布尔型的,如果一个变量用于表示布尔值,应该始终设置它为0或者1.
8 左值和右值
a=b+25 a是左值,因为它标识了一个可以存储结果值的地点。b+25是右值,因为它指定了一个值。
b+25=a 此时a作右值,它包含一个值。但是b+25作左值,它标识一个未知的地址,所以语句非法。
int a,*pi
pi =&a
*pi=20 pi的值是内存中某个特定位置的地址,*操作符使机器指向那个地址,所以合法。
第6章
1. 一个字包含4个字节,但是它仍然只有1个地址,至于它的地址是它左边那个字节的地址还是它右边那个字节的地址,由机器规定,即是小端字节序还是大端字节序的问题。
2. 边界对齐
3. 指针存储的内容: 是地址
4. int *a
.......
*a=12 :不合法的原因?a是一个指针,但是没有被初始化,所以不知道a指向那个存储地址,*a就是对未知的地址进行操作。偶尔这个a包含了合法的地址,那么你会在无意的情况下修改了地址的内容。
5 NULL指针
它是一个特殊的指针变量,表示不指向任何东西。NULL指针的概念,表示给你一种方法,用于表示某个特定的指针目前未指向任何东西。
同理在数据库中的null,传说中的“空值”,它表示的概念为,不确定它的内容,有可能是1,有可能是一堆垃圾。它不代表数据库的这个字段真就空了,木有值。
6 指针常量
* 100=25 错误的原因是:100是整型值,*操作符只能作用于指针类型表达式。改变的方式则是*(int *)100=25;这个就是直接对硬件地址进行操作了。
7 指针的指针
书上讲的比较简单,其实还有更复杂的。
- a = (int **) malloc(sizeof(int *) * NR);
http://www.linuxany.com/archives/1231.html
8 指针表达式
*p++ ++产生p的拷贝;++增加p的值 ;在拷贝上进行间接访问操作;
++*p 对p进行间接访问;将访问结果++
++*p++
9 指针运算
指针 - 整数
指针 - 指针 :当两个指针都指向同一个数组中的元素时,才允许从一个指针减去另一个指针。
指针关系运算 : 局限于都指向同一个数组中的元素时。
第七章
1 传值和传引用
C函数的所有参数均以“传值调用”方式进行传递,这意味着函数将获得参数值的一份拷贝,这样函数可以放心的修改这个拷贝值,而不必担心会修改调用程序实际传递给它的参数。
C的规则很简单:所有参数都是传值调用。
但是,如果被传递的参数是一个数组名,并且在函数中使用下标引用该数组的参数,那么在函数中对数组元素进行修改实际上修改的是调用程序中的数组元素。函数将访问调用程序的数组元素,数组并不会被赋值。这个行为被称为传址调用。对此解释为“数组名的值实际上是一个指针,传递给函数的就是这个指针的一份拷贝,下标引用实际上是间接访问的另一种形式,它可以对指针执行间接访问操作,访问指针指向的内存位置。参数实际上是一份拷贝,但在这份拷贝上执行间接访问操作所访问的仍然是原先的数组。”
第八章
1 在C中几乎所有使用数组名的表达式中,数组名的值是一个指针常量,也就是数组第一个元素的地址。“指向****的常量指针”
2 数组和指针的区别
数组有确定数量的元素,而指针是一个标量值。编译器用数组名来记住这些属性。当数组名在表达式中使用的时候,编译器才会为它产生一个指针常量。所以
int b[9],b=b+1是不可以的。
3 数组名不用指针常量来表示的场合
数组名作为sizeof操作符,返回整个数组的长度,而不是指针的长度。
&操作符,取一个数组名的地址产生的是一个指向数组的指针。
4 下标引用 int a[10] *(a+3)
数组名在表达式中是一个指针常量,经过指针运算,结果是一个指向所需元素的指针,然后对这个指针执行间接访问操作。
5 静态和自动初始化
存储与静态内存的数组只初始化一次,在程序开始执行之前。
自动变量位于运行时堆栈中,执行流每次进入它们所在的代码块时,这类变量的内存位置可能并不相同,在程序开始前,编译器没办法对这些位置进行初始化。
6 字符串常量与字符串数组
char mesg[]="hello" char *message="hello"
7 多维数组
matrix[1][5]
matrix : 指向包含10个整型元素的数组的指针
matrix +1 上述的下一行
*(*(matrix+1)+5)
8 指向数组的指针
int v[10],*p=v 合法,v,p具有相同的类型:指向整型的指针
int v[1][1] ,*p=v 不合法,p是指向整型的指针,而V是指向整型数组的指针。应为int (*p)[1]
int *p=&v[0][0]
int **p 与指向整型数组的指针并不是一回事。
第九章
1,字符串长度 不计算最后的NULL。
strlen()返回size_t 这个是无符号整数类型,
if(strlen(x) > strlen(y) ) 正确
if (strlen(x) -strlen(y) >0) 有BUG,因为无符号数绝对不可能是负的。 给提醒,在使用别人的api的时候返回类型是什么也是很关键的注意点。
2 字符串函数
char * strcpy(char * dest,char *src)
bug1 :如果src与dest在内存中有重叠,其结果是未定义的。
返回dest的拷贝
char * strcat(char *dest,char *src)
要求dest原先包含了一个字符串,可以是空字符串。同样会出现bug1.返回dest的拷贝
char * strcmp(char const *s1,char const *s2)
小 返回小于0的值相等 返回0
大 返回大于0的值
char * strncpy(char * dest,char *src,size_t len)
将源字符串的字符赋值到目标数组,它正好向dest写入len,如果strlen(src)小于len,dst用额外的NUL填充到len长度,如果大那么只有len被复制,且结果不会以nul结束。
char * strncat(char * dest,char *src,size_t len)
总是以NUL结束。
char * strncmp(char * dest,char *src,size_t len)
char * strchr(char *const *str,int ch)
查找str中ch第一次出现的位置。
char * strrchr(char *const *str,int ch)
查找str中ch最后一次出现的位置。
char * strpbrk(char *const *str,char const *group)
查找group中任何一个字符的字符位置。
char * strstr(char const *s1,char const *s2)
size_t strspn(char const *str,char const *group);
返回str起始部分匹配group中任意字符的字符数。
size_t strcspn(char const *str,char const *group);
void * memcpy(void *dst,void const *src,size_t length);
void *memmove(void *dst,void const *src,size_t length);
把源操作数复制到一个临时位置,这个位置不会与源或目标操作数重叠,然后再把它从临时位置复制到目标操作数。
void *memcmp(void *dst,void const *src,size_t length);
void *memchr(void *dst,int ch,size_t length);
void *memset(void *dst,int ch,size_t length);
memset(buffer,0,size)把buffer的前size个字节都初始化为0
3 memcpy 与strcpy的区别
memcpy是用于copy源空间的数据到目的空间中。
strcpy用于字符串copy,遇到‘\0’,将结束。http://www.cppblog.com/junfeng568/archive/2006/03/11/4022.html