指针 (C语言)
指针
指针的概念: 内存的地址编号(类似房间门牌号)
int a = 10;
通过代码查看a的指针(地址编号)
&: 取地址运算符
&a: 返回变量a的首地址
%p: 用于打印指针, 16进制
printf("a的地址: %p\n", &a);
指针变量: 用户存放指针(地址)的变量
定义的格式
数据类型 *变量名 = 初值
定义一个整型指针变量
int *p = NULL;//*代表定义的是指针变量 printf("%p\n", p); p = &a; printf("%p\n", p);
指针变量的作用
直接访问: 通过变量名获取内存中的值
printf("%d\n", a);
间接访问: 通过内存地址编号, 找到内容, 再获取内存中的值
printf("%d", *p);//*: 取值运算符 */ /* int a = 15, b = 10; int *x = &a; int *y = &b; x = y; *x = 20; printf("a = %d, b = %d\n", a, b); */ /* int a = 15, b = 20; int *x = &a; int *y = &b; *x = 11; int *p = &a; p = y; *y = 21; printf("a = %d, b = %d\n", a, b); printf("%d %d %d", *x, *y, *p); */ /* int a = 6, b = 8, c = 10; int *x = &a; x = &c; int *y = &b; int *z = &c; *z = 5; *x = 12; x = y; *y = *x + *z; printf("a = %d, b = %d c = %d\n", a, b, c); printf("%d %d %d\n", *x, *y, *z); */
*: 代表定义的是指针变量
&: 取地址运算符
int *p1 = &a;//定义指针变量p1, 存a的首地址
int *p2 = &b;//定义指针变量p2, 存b的首地址
p1 = p2;//把指针变量变量p2的值赋给指针变量p1
*: 取值运算符
printf("%d\n", *p1);//取出p1指向内存中的数据
指针常见的问题
1.内存地址比较低的内存单元, 有系统控制, 不允许访问
int *p = NULL; //*p = 10;//error
2.野指针, 定义指针变量时, 没有赋初值, 指向不定
int *p;
//*p = 100;//error
3.定义指针变量, *属于谁?
int *p1 = NULL;//推荐, int * 是p1的类型
int* p2 = NULL;
int*p3 = NULL;
int * p4 = NULL;
4.指针变量所占的字节数
a.与数据类型无关
b.与操作系统的位数相关, 64位占8个字节, 32位占4个字节
int *p = NULL; printf("%lu\n", sizeof(p));//8 printf("%lu\n", sizeof(int *)); printf("%lu\n", sizeof(char *)); printf("%lu\n", sizeof(short *)); printf("%lu\n", sizeof(long *)); printf("%lu\n", sizeof(float *)); printf("%lu\n", sizeof(double *)); printf("%lu\n", sizeof(bool *));
5.定义指针变量的数据类型有什么作用
a.指针变量的数据类型, 决定了*(取值运算符)取多少个字节的内容
int a = 260; int *p = &a; printf("%d\n", *p); char c = 'a'; char *p1 = &c; printf("%c\n", *p1);
b.定义指针变量的数据类型, 决定了指针变量+1操作时, 跳转多少个字节
long *p = NULL; printf("%p\n", p);//0x0 printf("%p\n", p + 1);//0x8 printf("%p\n", ++p);//0x8 printf("%p\n", p);//0x8 printf("%p\n", p++);//0x8 printf("%p\n", p);//0x10
指针的应用
指针在数组中的使用
1.数组在内存中是连续存储的
int array[5] = {1, 2, 3, 4, 5};
第一个元素的地址, 就是数组的首地址
printf("%p\n", &array[0]);
2.数组的名字就是数组的首地址
printf("%p\n", array); for (int i = 0; i < 5; i++) { // printf("%d ", array[i]); printf("%d ", *(array + i)); } //a[b] = *(a + b) //b[a] = *(b + a) //a[b] = b[a] printf("\n"); for (int i = 0; i < 5; i++) { printf("%d ", i[array]); } printf("\n");
有10个元素的整形数组, 随机赋值, [22, 66]
int a[10] = {0}; for (int i = 0; i < 10; i++) { *(a + i) = arc4random() % (66 - 22 + 1) + 22; printf("%d ", *(a + i)); } printf("\n");
冒泡排序
for (int i = 0; i < 9; i++) { for (int j = 0; j < 9 - i; j++) { if (*(a + j) > *(a + j + 1)) { int temp = *(a + j); *(a + j) = *(a + j + 1); *(a + j + 1) = temp; } } } for (int i = 0; i < 10; i++) { printf("%d ", *(a + i)); } printf("\n");
数组元素
a[0] *a
a[1] *(a + 1)
... ...
a[n -1] *(a + n - 1)
元素的首地址
&a[0] a
&a[1] a + 1
... ...
&a[n - 1] a + n - 1
int a[5] = {1, 2, 3, 4, 5}; printf("%d\n", a[1]); printf("%d\n", *(a + 1));
定义一个指针变量存数组的首地址
int *p = a; printf("%d\n", p[1]); printf("%d\n", *(p + 1));
数组名a(数组首地址) 和指向数组首地址的指针变量p
相同点
所有数组可以执行的操作, 指向数组首地址的指针变量p, 也都可以执行
不同点
1.数组名(数组首地址)是一个常量地址, 不能修改; 指针变量可以重新指向
int number = 10;
p = &number; //a = &number;//error
2.使用sizeof, 如果是数组名(数组首地址), 计算的是数组所占的字节数; 如果是指针变量, 计算的是指针变量所占的字节数
printf("%lu\n", sizeof(a));//20 printf("%lu\n", sizeof(p));//8
指针在字符串中的使用
字符数组
字符串
字符串数组
char string[10] = "jiujing";
%s打印的实质: 从给定地址开始, 依次打印字符, 直到遇到'\0'结束
printf("%s\n", string); printf("%s\n", string + 4);
char string[] = "I love you!"; *(string + 1) = '\0'; *(string + 7) = '\0'; printf("%s\n", string); printf("%s\n", string + 3); printf("%s\n", string + 7); printf("%s\n", string + 8);
计算字符串的长度, 不使用strlen
char str[] = "Do one thing at a time, and do well"; int i = 0; while(*(str + i) != '\0'){ i++; } printf("长度: %d\n", i);