the C programming language 阅读笔记2

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. 相同类型指针间的赋值运算
  2. 指针值加或减一个整数值的运算
  3. 指向相同数组中的元素的指针之间的减或比较运算
  4. 将指针赋0或指针与0之间的比较运算

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复杂指针的理解

  基本形式:

  1. char **argv; //二维指针
  2. int (*daytab)[13];//指向一个int[13]数组的指针
  3. int *daytab[13];//指针数组
  4. void (*comp)();//函数指针
  5. void *comp();//返回值为指针的函数
  6. void (*op[2])();//函数指针数组

  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 对结构体的合法操作  

  1. 拷贝
  2. 作为一个单元对其赋值
  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是从右往左。

就算黑夜也有星光。
原文地址:https://www.cnblogs.com/shijiezhenmei/p/3651377.html