561 lines
9.5 KiB
Markdown
561 lines
9.5 KiB
Markdown
# 目录
|
||
- [目录](#目录)
|
||
- [指针](#指针)
|
||
- [变量与地址](#变量与地址)
|
||
- [指针与指针变量](#指针与指针变量)
|
||
- [直接访问与间接访问](#直接访问与间接访问)
|
||
- [空指针与野指针](#空指针与野指针)
|
||
- [空类型](#空类型)
|
||
- [定义与初始化的书写规则](#定义与初始化的书写规则)
|
||
- [指针运算](#指针运算)
|
||
- [指针与数组](#指针与数组)
|
||
- [指针与一维数组](#指针与一维数组)
|
||
- [指针与二维数组](#指针与二维数组)
|
||
- [指针与字符数组](#指针与字符数组)
|
||
- [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 <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`,避免野指针。
|
||
|
||
```c
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
|
||
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 <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);
|
||
}
|
||
```
|
||
|
||
|
||
|
||
### 指针与二维数组
|
||
|
||
```c
|
||
#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);
|
||
}
|
||
```
|
||
|
||
|
||
|
||
### 指针与字符数组
|
||
|
||
```c
|
||
#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修饰指针,指针指向不能变
|
||
|
||
```c
|
||
/**
|
||
* 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;`
|
||
|
||
|
||
|
||
```c
|
||
#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);
|
||
}
|
||
```
|
||
|
||
|
||
|
||
|
||
|
||
## 多级指针
|
||
|