# C进阶指南（2）：数组和指针、打桩

## 三、指针和数组

(Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type “array of type” is converted to an expression with type “pointer to type” that points to the initial element of the array object and is not an lvalue.)

 1 2 3 4 5 6 7 8 9 10 11 12 short  a[] = {1,2,3}; short  *pa; short  (*px)[];   void  init(){     pa = a;     px = &a;       printf("a:%p; pa:%p; px:%p\n", a, pa, px);       printf("a[1]:%i; pa[1]:%i (*px)[1]:%i\n", a[1], pa[1], (*px)[1]); }

（译者注：%i能识别输入的八进制和十六进制）

a 是 int 型数组，pa 是指向 int 的指针，px 是个未完成的、指向数组的指针。a 赋值给 pa 前，它的值被转为一个指向数组开头的指针。右值表达式 &a 并非意味着指向 int，而是一个指针，指向 int 型数组因为当使用一元符号&时右值不被转换为指针。

 1 2 int  a[]; int  *pa;

 1 2 extern  int *a; extern  int pa[];

### 3.1 数组作为函数形数

 1 2 3 4 5 void  sum(int data[10]) {}   void  sum(int data[]) {}   void  sum(int *data) {}

 1 2 3 typedef int[4] vector; vector m[2] = {{1,2,3,4}, {4,5,6,7}}; int  n[2][4] = {{1,2,3,4}, {4,5,6,7}};

 1 2 int  *p = n[1]; int  y = p[2];

 1 int  z = *(*(n+1)+2);

 1 int  x = n[1][2];

 1 2 3 4 5 void  sum(int data[2][4]) {}   void  sum(int data[][4]) {}   void  sum(int (*data)[4]) {}

 1 2 3 4 5 6 7 8 9 10 11 12 13 void  list(int *arr,  int max_i, int max_j){     int i,j;       for(i=0; i

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 int  main(int argc,  char **argv){     int arr1[4] = {1,2,3,4};     int arr2[4] = {5,6,7,8};       int *arr[] = {arr1, arr2};       list(arr, 2, 4); }   void  list(int **arr,  int max_i, int max_j){     int i,j;       for(i=0; i

 1 2 3 4 5 const  char *strings[] = {     "one",     "two",     "three" };

 1 2 3 4 void  list(int max_i,  int max_j, int arr[][max_j]){     /* ... */     int x = arr[1][3]; }

 1 2 3 4 5 6 7 8 9 static  void catch_int(int no) {     /* ... */ };   int  main(){     signal(SIGINT, catch_int);       /* ... */ }

## 四、打桩（Interpositioning）

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 /* _GNU_SOURCE is needed for RTLD_NEXT, GCC will not define it by default */ #define _GNU_SOURCE #include  #include  #include  #include  #include    static  uint32_t malloc_count = 0; static uint64_t total = 0;   void  summary(){     fprintf(stderr, "malloc called: %u times\n", count);     fprintf(stderr, "total allocated memory: %"  PRIu64 " bytes\n", total); }   void  *malloc(size_t size){     static void* (*real_malloc)(size_t) = NULL;     void *ptr = 0;       if(real_malloc == NULL){         real_malloc = dlsym(RTLD_NEXT, "malloc");         atexit(summary);     }       count++;     total += size;       return real_malloc(size); }

 1 2 3 4 5 6 7 8 $gcc -shared -ldl -fPIC malloc_counter.c -o /tmp/libmcnt.so $ export LD_PRELOAD="/tmp/libstr.so" \$ ps   PID TTY          TIME CMD  2758 pts/2    00:00:00 bash  4371 pts/2    00:00:00 ps malloc called: 184 times total allocated memory: 302599 bytes

### 4.1 符号可见性

 1 2 3 4 5 6 7 #if __GNUC__ >= 4 || __clang__   #define EXPORT_SYMBOL __attribute__ ((visibility ("default")))   #define LOCAL_SYMBOL  __attribute__ ((visibility ("hidden"))) #else   #define EXPORT_SYMBOL   #define LOCAL_SYMBOL #endif