Files
Linux-C-Notes/C06-指针/C6-指针.md
2024-06-23 17:45:58 +08:00

528 lines
9.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 目录
- [目录](#目录)
- [指针](#指针)
- [变量与地址](#变量与地址)
- [指针与指针变量](#指针与指针变量)
- [直接访问与间接访问](#直接访问与间接访问)
- [空指针与野指针](#空指针与野指针)
- [空类型](#空类型)
- [定义与初始化的书写规则](#定义与初始化的书写规则)
- [指针运算](#指针运算)
- [指针与数组](#指针与数组)
- [指针与一维数组](#指针与一维数组)
- [指针与二维数组](#指针与二维数组)
- [指针与字符数组](#指针与字符数组)
- [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 = &pi;
const float *p = &pi;
// *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 = &pi;
// |
#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);
}
```
## 多级指针