配套代码笔记仓库。目录目录指针变量与地址指针与指针变量直接访问与间接访问空指针与野指针空类型定义与初始化的书写规则指针运算指针与数组指针与一维数组指针与二维数组指针与字符数组const 与指针指针数组与数组指针多级指针指针变量与地址int i=100;i是变量名,也就是地址。100是存放在这个地址的变量的值。指针与指针变量int i = 100; int *p = &i; int **q = &p;p是一个指针变量,他所存放的值是指针,指向另一个变量i的地址。直接访问与间接访问同样对于上面那个存放值为100的变量,既可以通过i直接访问,也可以通过*p, **q来间接访问。#include <stdio.h> #include <stdlib.h> int main() { int i = 1; int *p = &i; // 相当于 // int *p; // p = &i; int **q = &p; printf("i = %d\n", i); printf("&i = %d\n", &i); printf("p = %d\n", p); printf("&p = %d\n", &p); printf("*p = %d\n", *p); printf("q = %d\n", q); printf("*q = %d\n", *q); printf("**q = %d\n", **q); // i = 1 // &i = 1175115956 // p = 1175115956 // &p = 1175115944 // *p = 1 // q = 1175115944 // *q = 1175115956 // **q = 1 #if 0 float *q; double *d; char *c; printf("%d\n", sizeof(i)); printf("%d\n", sizeof(p)); printf("%d\n", sizeof(q)); printf("%d\n", sizeof(d)); printf("%d\n", sizeof(c)); // out: // 4 // 8 // 8 // 8 // 8 /* 指针在某一个平台所占的大小是一样的 */ /* 其指向的类型的空间的大小,由指针的类型决定 */ #endif #if 0 printf("i = %d\n", i); printf("&i = %d\n", &i); printf("p = %d\n", p); printf("&p = %d\n", &p); printf("*p = %d\n", *p); // out: // i = 1 // &i = 1343894748 // p = 1343894748 // &p = 1343894736 // *p = 1 #endif exit(0); }空指针与野指针野指针:int *p = 0x14532534,不确定这个地址的情况,盲目的指过去,那么读或者写都是非法的。空指针:int *p = NULL,避免野指针。#include <stdio.h> #include <stdlib.h> int main() { int *p; *p = 1; printf("%p --> %d\n", p, *p); // 有的编译器报段错误,有的编译器能输出 // 0x7feb1910dad0 -- > 420327424 exit(0); }空类型void *q万能类型。定义与初始化的书写规则int *p; int* p;指针运算& * 关系运算 ++ --指针与数组指针与一维数组#include <stdio.h> #include <stdlib.h> // TYPE NAME = VALUE; // a[i]value: a[i] = *(a+i) = *(p+i) = p[i] // &a[i]: &a[i] = a+i = p+i = &p[i] int main() { int a[] = {5, 1, 7, 2, 8, 3}; int y; int *p = &a[1]; y = (*--p)++; printf("y = %d\n", y); // out: y = 5 printf("a[0] = %d\n", a[0]); // out: a[0] = 6 #if 0 int *p = (int[3]){1, 2, 3}; // 只是不要数组名了 for (int i = 0; i < 3; i++) { printf("%p --> %d\n", &p[i], p[i]); } // 0x7ffd12681964 --> 1 // 0x7ffd12681968 --> 2 // 0x7ffd1268196c --> 3 #endif #if 0 int a[3]; int *p = a; int i; for (i = 0; i < sizeof(a) / sizeof(*a); i++) { printf("%p --> %d\n", &a[i], a[i]); } for (i = 0; i < sizeof(a) / sizeof(*a); i++) { scanf("%d", p++); } p = a; for (i = 0; i < sizeof(a) / sizeof(*a); i++, p++) { // printf("%d\n", *p++); printf("%p --> %d\n", p, *p); } // out: // // 0x7ffdad36c478 --> -563487456 // 0x7ffdad36c47c --> 32710 // 0x7ffdad36c480 --> 0 // 1 // 2 // 3 // 0x7ffdad36c478 --> 1 // 0x7ffdad36c47c --> 2 // 0x7ffdad36c480 --> 3 #endif #if 0 int a[3] = {1, 2, 3}; int i; int *p = a; p++; // p从a[0]挪到a[1] printf("%p,%p\n", p, p + 1); // *a相当于*(a+0)相当于a[0] // for (i = 0; i < sizeof(a) / sizeof(a[0]); i++) for (i = 0; i < sizeof(a) / sizeof(*a); i++) { // printf("%p--> %d\n", &a[i], a[i]); // printf("%p--> %d\n", a + i, a[i]); printf("%p--> %d\n", p + i, *(p + i)); } printf("\n"); #endif exit(0); }指针与二维数组#include <stdio.h> #include <stdlib.h> int main() { int a[2][3] = {1, 2, 3, 4, 5, 6}; int i, j; int *p = *a; int(*q)[3] = a; #if 0 //(W) int *p = a; // 报错,不兼容 // 因为a是行指针,不是int类型指针 // int *p = *a; *p = &a[0][0]; // for (i = 0; i < 6; i++, p++) for (i = 0; i < 6; i++) { // printf("%d ", *p); printf("%d ", p[i]); } printf("\n"); #endif #if 1 printf("%p %p\n", a, a + 1); printf("%p %p\n\n", q, q + 1); for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { // printf("%p --> %d ", &a[i][j], a[i][j]); // printf("%p --> %d ", *(a + i) + j, *(*(a + i) + j)); printf("%p --> %d ", *(q + i) + j, *(*(q + i) + j)); } printf("\n"); } #endif exit(0); }指针与字符数组#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char *str = "hello"; printf("%d %d\n", sizeof(str), strlen(str)); // out: 8 5 //(F) strcpy(str, "world"); // 这里企图把 "world" 覆盖 "hello"这个串常量 str = "world"; puts(str); // char str[] = "hello"; // printf("%d %d\n", sizeof(str), strlen(str)); // out :6 5 #if 0 char str[] = "hello"; // str[6] //(F) str = "world"; strcpy(str, "world"); puts(str); #endif #if 0 char str[] = "I love china!"; char *p = str + 7; puts(str); puts(p); // I love china! // china! #endif exit(0); }const 与指针常量指针:指向常量的指针const修饰*p,指针指向的值不能变指针常量:这个指针是一个常量const修饰指针,指针指向不能变/** * const int a; * int const a; * * 常量指针 * const int *p; * int const *p; * * 指针常量 * int *const p; * * const int *const p; * */ #include <stdio.h> #include <stdlib.h> #define PI 3.14 int main() { int i = 1; int j = 100; const int *const p = &i; //(F) p = &j; //(F) *p = 10; #if 0 int *const p = &i; //(T) *p = 10; //(F) p = &j; // [main][~/workspace/Linux-C-Notes/Chapter6]$ make const // cc const.c -o const // const.c: In function ‘main’: // const.c:29:7: error: assignment of read-only variable ‘p’ // 29 | p = &j; // | ^ // make: *** [<builtin>: const] Error 1 printf("i = %d\n", *p); #endif #if 0 int i = 1; int j = 2; // 常量指针 const int *p = &i; //(T) i = 2; // 直接用i改还是可以改成功的 //(F) *p = 2; //(T) p = &j; printf("i = %d\n", i); #endif #if 0 const float pi = 3.14; // const 将变量常量化,相比于宏,多了检查语法 //(F) pi = 3.14159; // float *p = π const float *p = π // *p = 3.14159; // [main][~/workspace/Linux-C-Notes/Chapter6]$ make const // cc const.c -o const // const.c: In function ‘main’: // const.c:28:16: warning: initialization discards ‘const’ qualifier from // pointer target type [-Wdiscarded-qualifiers] // 28 | float *p = π // | #endif exit(0); } 指针数组与数组指针数组指针:指向数组的指针。【存储类型】 数据类型 (*指针名)【下标】 = 值如:int (*p)[3]; 看成 int[3] *p;指针数组:【存储类型】 数据类型 * 数组名【长度】如:int *arr[3]; 看成 int *[3] arr;#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char *name[5] = {"Follow me", "Basic", "Great", "Fortran", "Computer"}; // 指针数组 int i, j, k; char *tmp; for (i = 0; i < 5 - 1; i++) { k = i; for (j = i + 1; j < 5; j++) { if (strcmp(name[k], name[j]) > 0) k = j; } if (k != j) { tmp = name[i]; name[i] = name[k]; name[k] = tmp; } } for (int i = 0; i < 5; i++) { puts(name[i]); } exit(0); }多级指针