Linux下C语言教程-李慧芹老师-第六章

配套代码笔记仓库

目录

指针

变量与地址

int i=100;

i是变量名,也就是地址。

100是存放在这个地址的变量的值。

指针与指针变量

1
2
3
int   i = 100;
int *p = &i;
int **q = &p;

p是一个指针变量,他所存放的值是指针,指向另一个变量i的地址。

直接访问与间接访问

同样对于上面那个存放值为100的变量,既可以通过i直接访问,也可以通过*p, **q来间接访问。

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#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,避免野指针。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <stdlib.h>

int main()
{
int *p;

*p = 1;

printf("%p --> %d\n", p, *p);
// 有的编译器报段错误,有的编译器能输出
// 0x7feb1910dad0 -- > 420327424

exit(0);
}

空类型

void *q

万能类型。

定义与初始化的书写规则

1
2
int *p;
int* p;

指针运算

& * 关系运算 ++ --

指针与数组

指针与一维数组

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#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);
}

指针与二维数组

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#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);
}

指针与字符数组

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#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修饰指针,指针指向不能变

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
* 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;

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
31
32
33
34
35
#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);
}

多级指针


Linux下C语言教程-李慧芹老师-第六章
http://sinlatansen.github.io/2024/04/11/Linux下C语言教程-李慧芹老师-第六章/
作者
fugu
发布于
2024年4月11日
许可协议