1. 指针
1.1 自增符的使用
++*p;//p指向的内容加一
(*p)++; //p指向的内容加一
*p++;//p本身自增
*++p; //p本身自增
因为诸如*和++这样的一元运算符在表达式求值时按从右到左的顺序和运算分量结合。
1.2 指针运算比数组下标运算快
1.3 数组名
一个数组名即该数组第0个元素的位置,所以赋值语句pa = &a[0]等价于pa = a
1.4 数组下标求值
在求数组元素a[i]的值时,C语言实际上先将其转换成*(a + i)的形式再求值
而对于指针pa而言,pa[i] 等价于 *(pa + i)
1.5 数组名与指向数组首地址的指针的区别
前者非变量,后者为变量
1.6 函数参数传入指针
在函数的定义中,char s[]与char *s是等价的。
当函数参数传入一个较大数组的子数组的指针时,并不会对函数本身造成影响
1.7 指针使用负下标
如果确信某个元素存在,则使用p[ -1]、p[ -2 ]这样的表达式在语法上是合法的。
int b[10] = {1,2,3,4,5,6,7,8,9,10}; int *a = b + 3;
则:a[-3] = 1; a[ -2] = 2;
1.8 alloc与afree的栈式管理
先分配的后释放
调用alloc之前:
allocbuf:
调用alloc之后:
allocbuf:
afree(p)是将空闲单元起始指针指向p位置
1.9 比较运算
在知道指针值意义的情况下,可以对其进行比较运算
int b[10] = {0,1,2,3,4,5,6,7,8,9}; int *p1 = &b[2]; int *p2 = &b[6];
则p2 – p1 = 4
1.10 指针相关的有效运算
1.11 strcpy函数
原书上的函数:
void strcpy( char *s, char *t){ while( *s++ = *t++); }
这里的指针s是临时变量,就算自增也不会改变实参中存储的地址,改变的只是形参指向的地址里的内容,所以用实参可以正确找到首地址,从而正确完成了strcpy函数的功能。
非常感谢@garbageMan的提醒。
1.12 函数参数为二维数组
f( int daytab[2][13])
= f(int daytab[][13])
=f(int (*daytab)[13])
传入一个指针,指针每个元素的内容是一个数组
1.13指向数组的指针和指针数组
int (*daytab)[13] -->指针指向的内容是int[13]的数组
int *daytab[13]à13个指针指向int
指针的实质是根据定义的类型和其中存储的地址来解析内存里的数据
print (Int *s){
s[1] = 5;//即为*(s+1) = 5;
};
*(s+1) = 5;
根据指针所存的地址及所定义的类型,改变其中的数据
int (*daytab)[13]
所定义的类型为int[13]的数组
所以,对该指针解引用得到的是一段13个int长的内存区域的首地址
即:
int a[4][4]; int (*b)[4] = a;
b[2][2] = *(*(b+2)+2) = (*(s+2))[2] != *(s+2)[2]
分析:
*b解引用得到:int[4]
*b的值为这段int[4]的首地址
**b为这段int[4]首地址指向的内容即为b[0][0]的值
1.14 指针数组的初始化
即用指针来初始化数组
1.15 指向函数的指针
1.15.1 一个实例:
支持-n进行数字排序的排序函数
1 #include <stdio.h> 2 #include <string.h> 3 #define MAXLINES 5000 /* max #lines to be sorted */ 4 char *lineptr[MAXLINES]; /* pointers to text lines */ 5 int readlines(char *lineptr[], int nlines); 6 void writelines(char *lineptr[], int nlines); 7 void qsort(void *lineptr[], int left, int right, 8 int (*comp)(void *, void *)); 9 int numcmp(char *, char *); 10 /* sort input lines */ 11 main(int argc, char *argv[]) 12 { 13 int nlines; /* number of input lines read */ 14 int numeric = 0; /* 1 if numeric sort */ 15 if (argc > 1 && strcmp(argv[1], "n")== 0) 16 numeric = 1; 17 if ((nlines = readlines(lineptr, MAXLINES)) >= 0) { 18 qsort((void**) lineptr, 0, nlines1, 19 (int (*)(void*,void*))(numeric ? numcmp : strcmp)); 20 writelines(lineptr, nlines); 21 return 0; 22 } else { 23 printf("input too big to sort\n"); 24 return 1; 25 } 26 }
1 /* qsort: sort v[left]...v[right] into increasing order */ 2 void qsort(void *v[], int left, int right, 3 int (*comp)(void *, void *)) 4 { 5 int i, last; 6 void swap(void *v[], int, int); 7 if (left >= right) /* do nothing if array contains */ 8 return; /* fewer than two elements */ 9 swap(v, left, (left + right)/2); 10 last = left; 11 for (i = left+1; i <= right; i++) 12 if ((*comp)(v[i], v[left]) < 0) 13 swap(v, ++last, i); 14 swap(v, left, last); 15 qsort(v, left, last1,comp); 16 qsort(v, last+1, right, comp); 17 }
1.15.2 指向函数的指针&返回为指针的函数
指向函数的指针:
int (*comp)(void *, void *);
返回为指针的函数:
int *comp(void *, void *);
C在编译时,每个函数都有一个入口地址,该入口地址就是函数指针所指向的地址
有了指向函数的指针变量后,可用该指针变量调用函数
1.15.3 函数指针的定义
1.void (*f)(int x);
调用(*f)(x);
2.typedef int (*fun_ptr)(int,int);
fun_ptr max_func = max;
c = max_func(a,b);
1.15.4 函数指针数组
1.标准定义:
int (*op[2])(int,int);
2.强制类型转换
定义为普通的int型指针数组
在要使用时,强制类型转换为相应的函数指针类型
int *a;
int add(int a, int b);
a = add;
r = ((int (*)(int,int))(a))(numa,numb);
1.16复杂指针的理解
基本形式:
char (*(*x())[])()
*x()如上式5,表示返回值为指针的函数
剩余部分表述的就是所返回的指针的类型:
返回的指针类型如上式6,返回值char的函数指针数组
所以,
x是一个函数,该函数的返回值是一个指向类型为char的函数指针数组的指针
char (*(*x[3])())[5]
(*x[3])()如上式6为函数指针数组
其他的部分描述函数指针数组的返回值
所以,x是一个返回值为char[5]的长度为3的函数指针数组
2.内存布局
2.1数组的内存布局
int a[10];
内存是连续分配的相邻区域
int *p = &a;
p = p + 1;
2.2 大端模式 & 小端模式
大端模式:即指数据的高位,保存在内存的低地址中,而数据的低位,保存在内存的高地址中
例:
65534(0x0000FFFE)
小端模式(一字节存储单位):
0x0000 0x0008 0x0010 0x0018
FE FF 00 00
大端模式:
0x0000 0x0008 0x0010 0x0018
00 00 FF FE
3.结构
3.1 结构变量的定义方法
struct {…} x,y,z;
语法上与int x,y,z;相似
3.2 结构变量的定义方法
typedef struct{…} myType;
3.3 结构变量的初始化
struct point maxpt = {320,200};
3.4 对结构体的合法操作
3.5 结构数组的初始化
struct key{ char *word; int count; } keytab[] = {“auto”,0,”break”,0};
3.6 字节对齐
参加博文《关于C语言中结构体中的结构体成员导致的字节对齐问题》
4.其他
4.1 逗号表达式
逗号运算符,优先级别最低,它将两式连起来,其求解过程先表达式1,后表达式2,整个表达式是表达式2的值
(3+5,6+8) = 14
(a = 3*5,a*4) = 60
4.2 命令行参数
argc 程序执行时命令行中参数的数目
argv 指向字符串数组的指针
4.3 联合
在单独存储区域中管理不同类型的数据
4.4 位字段
struct { unsigned int is_keyword : 1; unsigned int is_extern : 1; unsigned int is_static : 1; }flags;
分配空间大小为flags分配字段类型最长的倍数,然后一个字节一个字节地存储。在字节内的存储方式未知,根据不同的编译器决定从右往左还是从左往右。GCC是从右往左。