diff --git a/Chapter3/C3-输入输出专题.md b/Chapter3/C3-输入输出专题.md index 4e4ffa8..8189b83 100644 --- a/Chapter3/C3-输入输出专题.md +++ b/Chapter3/C3-输入输出专题.md @@ -338,7 +338,7 @@ int puts(const char *s); #include #define STRSIZE 32 - +j int main() { char str[STRSIZE]; diff --git a/Chapter5/C5-数组.md b/Chapter5/C5-数组.md index f20fe31..459384e 100644 --- a/Chapter5/C5-数组.md +++ b/Chapter5/C5-数组.md @@ -324,7 +324,7 @@ static void primer(void) ```c size_t strlen(const char *s); - // strlen函数可以后去字符串的长度,不包括尾'\0' + // strlen函数可以获取字符串的长度,不包括尾'\0' // 以'\0'作为结束,所以对于"hello\0abc",abc就不计入 // sizeof是完整的识别。 diff --git a/Chapter6/C6-指针.md b/Chapter6/C6-指针.md new file mode 100644 index 0000000..a9a8c2d --- /dev/null +++ b/Chapter6/C6-指针.md @@ -0,0 +1,560 @@ +# 目录 +- [目录](#目录) +- [指针](#指针) + - [变量与地址](#变量与地址) + - [指针与指针变量](#指针与指针变量) + - [直接访问与间接访问](#直接访问与间接访问) + - [空指针与野指针](#空指针与野指针) + - [空类型](#空类型) + - [定义与初始化的书写规则](#定义与初始化的书写规则) + - [指针运算](#指针运算) + - [指针与数组](#指针与数组) + - [指针与一维数组](#指针与一维数组) + - [指针与二维数组](#指针与二维数组) + - [指针与字符数组](#指针与字符数组) + - [const 与指针](#const-与指针) + - [指针数组与数组指针](#指针数组与数组指针) + - [多级指针](#多级指针) + + +# 指针 + +## 变量与地址 + +`int i=100;` + +`i`是变量名,也就是地址。 + +`100`是存放在这个地址的变量的值。 + + + +## 指针与指针变量 + +```c +int i = 100; +int *p = &i; +int **q = &p; +``` + +p是一个指针变量,他所存放的值是指针,指向另一个变量`i`的地址。 + + + +## 直接访问与间接访问 + +同样对于上面那个存放值为`100`的变量,既可以通过`i`直接访问,也可以通过`*p, **q`来间接访问。 + + + +```c +#include +#include + + + +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`,避免野指针。 + +```c +#include +#include + +int main() +{ + int *p; + + *p = 1; + + printf("%p --> %d\n", p, *p); + // 有的编译器报段错误,有的编译器能输出 + // 0x7feb1910dad0 -- > 420327424 + + exit(0); +} +``` + + + +## 空类型 + +`void *q` + +万能类型。 + + + +## 定义与初始化的书写规则 + +```c +int *p; +int* p; +``` + + + +## 指针运算 + +`&` ` *` 关系运算 `++` `--` + + + +## 指针与数组 + +### 指针与一维数组 + +```c +#include +#include + +// 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); +} +``` + + + +### 指针与二维数组 + +```c +#include +#include + + + +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); +} +``` + + + +### 指针与字符数组 + +```c +#include +#include +#include + +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修饰指针,指针指向不能变 + +```c +/** + * const int a; + * int const a; + * + * 常量指针 + * const int *p; + * int const *p; + * + * 指针常量 + * int *const p; + * + * const int *const p; + * + */ + +#include +#include + +#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: *** [: 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;` + + + +```c +#include +#include +#include + + +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); +} +``` + + + + + +## 多级指针 + diff --git a/Chapter6/arr.c b/Chapter6/arr.c new file mode 100644 index 0000000..76864ad --- /dev/null +++ b/Chapter6/arr.c @@ -0,0 +1,90 @@ +#include +#include + +// 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); +} \ No newline at end of file diff --git a/Chapter6/chararr.c b/Chapter6/chararr.c new file mode 100644 index 0000000..2a7dfd3 --- /dev/null +++ b/Chapter6/chararr.c @@ -0,0 +1,54 @@ +#include +#include +#include + +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); +} \ No newline at end of file diff --git a/Chapter6/const.c b/Chapter6/const.c new file mode 100644 index 0000000..7c9525b --- /dev/null +++ b/Chapter6/const.c @@ -0,0 +1,91 @@ +/** + * const int a; + * int const a; + * + * 常量指针 + * const int *p; + * int const *p; + * + * 指针常量 + * int *const p; + * + * const int *const p; + * + */ + +#include +#include + +#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: *** [: 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); +} diff --git a/Chapter6/douarr.c b/Chapter6/douarr.c new file mode 100644 index 0000000..1a9363a --- /dev/null +++ b/Chapter6/douarr.c @@ -0,0 +1,50 @@ +#include +#include + + + +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); +} \ No newline at end of file diff --git a/Chapter6/point.c b/Chapter6/point.c new file mode 100644 index 0000000..9bd9207 --- /dev/null +++ b/Chapter6/point.c @@ -0,0 +1,72 @@ +#include +#include + + + +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); +} \ No newline at end of file diff --git a/Chapter6/point1.c b/Chapter6/point1.c new file mode 100644 index 0000000..fc0b2b9 --- /dev/null +++ b/Chapter6/point1.c @@ -0,0 +1,15 @@ +#include +#include + +int main() +{ + int *p; + + *p = 1; + + printf("%p --> %d\n", p, *p); + // 有的编译器报段错误,有的编译器能输出 + // 0x7feb1910dad0 -- > 420327424 + + exit(0); +} \ No newline at end of file diff --git a/Chapter6/point_arr.c b/Chapter6/point_arr.c new file mode 100644 index 0000000..6b270b9 --- /dev/null +++ b/Chapter6/point_arr.c @@ -0,0 +1,35 @@ +#include +#include +#include + + +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); +} \ No newline at end of file