《C语言》-(指针)
指针:
-
格式:
变量类型 *变量名; 如:int *p;
-
注意点:
1.指针变量只能存储地址;
2.指针就一个作用,能够根据一个地址值,访问对应的存储空间;
3.指针变量p前面的int代表p只能指向int类型的数据;
-
注:
在64位编译器中,指针变量都是占用8个字节,但是为什么还要分为:char *p; int *p;等,是因为在取值时,*p会从p存储的地址开始,取一定的字节(如:int就会从p所存储的地址开始向下4个字节)
一、指针的基本使用
例:
int *p; // 定义了一个指向int类型数据的指针变量p
int a = 90; // 定义了一个int类型的数据a = 90
p = &a; // &a :取得变量a的地址,并且赋值给指针变量p
*p = 10; // 对p所指向的存储空间赋值(*)
解析:a = 90 --> 10;
注意点:
int *p; 中的*和*p = 10;中的*意思是不一样的;
int *p;中的*代表一个指针变量(标志)
*p = 10;中的*代表对p指向的存储空间进行赋值
代码练习一:
运行结果:
二、指针变量的使用注意
-
注意点一:
// 不建议这样写 int *p 只能指向int类型的数据
// 警告: warning: incompatible pointer types assigning to 'int *' from 'double *' [-Wincompatible-pointer-types]
int *p;
double a = 10.0;
p = &a;
-
注意点二:
// 指针变量只能存储地址
// 警告(warning: incompatible integer to pointer conversion assigning to 'int *' from 'int' [-Wint-conversion])
int *p;
p = 200;
-
注意点三:
// 指针变量未经过初始化,不要拿来间接访问其指向的存储空间(不明确)
// 没有警告、输出0
int *p;
printf("%d\n", *p);
-
注意点四:
// 定义变量时的*仅仅是一个象征,没有其他特殊含义
int a = 9;
int *p = &a; // 定义变量时的*仅仅是一个象征,没有其他特殊含义
// *p = &a; // 不正确的写法
// 报警(warning: incompatible pointer to integer
conversion assigning to 'int' from 'int *'; remove & [-Wint-conversion])
p = &a;
*p = 20; // 这里的*的作用:访问(赋值)指针变量p指向的存储空间
printf("%d\n", a);
-
代码练习:
运行结果:
三、指针和数组
1.数组元素的访问方式
-
数组名[下标]; 如:ages[i];
-
指针变量名[下标]; 如:p[i]; // 前提是指针变量p指向数组
-
*(p + i);
2.指针变量的+1,究竟是加多少取决与指针变量的类型
- int *p; p + 1 相当于地址值+4;
- char *p; p + 1 相当于地址值+1;
- double *p; p + 1 相当于地址值+8;
-
代码练习:
#include <stdio.h> /* 一、数组元素的访问方式 1.数组名[下标] 如:ages[i] 2.指针变量名[下标] 如:p[i] 前提是指针变量p指向数组 3.*(p + i) 前提是指针变量p指向数组 二、指针变量+1究竟加多少,取决于指针的类型 */ int main() { int ages[5] = {10, 12, 33, 56, 55}; /* // 方式1:遍历整个数组 for (int i = 0; i < 5; i++) { printf("%d\n", ages[i]); } */ // 方式2:通过指针间接访问数组元素 int *p; p = &ages[0]; // 数组名就是数组的地址,也是数组首元素的地址 // p = ages; printf("%d\n", *p); // 输出 10 // 输出地址值 // 总结:如果p指向数组首元素(第0个元素),那么p+1指向的就是第1个元素,p+2指向的就是第2个元素,并不是将地址值加1,这里是加4,因为是int类型的指针 /* p ——> &ages[0] p+1 ——> &ages[1] p+2 ——> &ages[2] p+i ——> &ages[i] */ printf("%p\n", p); // 输出 0x7fff535e3c30 printf("%p\n", p + 1); // 输出 0x7fff535e3c34 printf("%p\n", p + 2); // 输出 0x7fff535e3c38 // 方式2:通过指针间接访问数组元素 for (int i = 0; i < 5; i++) { printf("%d\n", *(p + i)); } // 访问数组元素的三种方式 // 1.数组名[下标] 如:ages[i] printf("%d\n", ages[3]); // 输出 56 // 2.指针变量名[下标] 如:p[i] printf("%d\n", p[3]); // 输出 56 // 3.*(p + i) printf("%d\n", *(p + 3)); // 输出 56 return 0;
四、指针和字符串
-
定义字符串的两种方式:
1.利用数组
char name[] = "itcast";
- 特点:这个字符串里面的字符可以修改
- 使用场合:字符串的内容需要经常修改
2.利用指针:
char *name = "itcast";
- 特点:这个字符串其实是一个常量字符串,里面的字符不允许修改;
- 使用场合:字符串的内容不需要修改,而且这个字符串经常使用;
-
代码练习:
运行结果:
五、数组指针及字符串的输入
#include <stdio.h>
int main()
{
// 一、定义字符串数组的两种方式
// 方式1:利用2维数组
char names[3][5] = {"jack", "rose", "jake"};
// 方式2:利用指针数组
char *names2[3] = {"jack", "rose", "jake"};
// 二、接受用户输入的字符串
// 1.先定义一个字符串用来存储用户输入的字符串
char names3[20];
// char *names3; // 这里不能用这种方式来定义一个字符串,因为这么字符串将来要接受用户输入的字符,是要变动
的,而这种方式定义的时一个字符串常量,运行时会程序奔溃(Segmentation fault: 11)
// 2.提示用户输入一个字符串
printf("请输入一个字符串:\n");
// 3.接受用户输入的字符串
// scanf("%s", &names3);
scanf("%s", names3); // 数组名就是地址,这里的%s会将用户输入的字符串从这个地址开始一个一个地存到names3这个字符串变量内
// 4.将接受到的字符串打印出来
printf("%s\n", names3);
return 0;
}
六、返回指针类型的函数
#include <stdio.h>
char test();
char *test2();
int main()
{
char *name = test2();
printf("%s\n", name); // 输出 rose
return 0;
}
// 返回char类型的函数
char test()
{
return 'A';
}
// 返回指针(char类型)的函数
char *test2()
{
return "rose"; // 在前面学过 char *name = "jake";
}
七、指向函数的指针
1.定义指向函数的指针
如:有一个函数: double haha(int a, char *s, double b);
double (*p)(int, char *, double); //定义了一个指向函数的指针
p = haha; // 将这个指向函数的指针指向haha函数 上面的两句可以整合成一句: double (*p)(int, char *, double) = haha;
2.函数的调用
-
直接调用:
haha(10, "jake", 12.5);
-
间接调用:
p(10, "jake", 12.5);
-
间接调用:
(*p)(10, "jake", 12.5); //(*p)这里的小括号千万不能省略,固定格式
代码练习:
#include <stdio.h> void test(); int sum(int n1, int n2); int main() { // (*p)是固定写法,代表指针变量p将来肯定指向的时函数 // 左边的void是代表指针变量p指向的函数是没有返回值的 // 右边的()是代表指针变量p指向函数没有形参 // 1.定义了一个指向函数的指针p void (*p)(); // 2.将这个指向函数的指针p指向test函数 // 函数名就是地址 p = test; // 函数的调用 p(); //1.间接方式 (*p)(); // 2.间接调用, test(); // 3.直接调用 // 练习 // (*p)是固定写法,代表指针变量p将来肯定指向的时函数 // 左边的int是代表指针变量p指向的函数是返回的时int类型的数据 // 右边的(int, int)是代表指针变量p指向函数又两个int类型的形参 int (*p2)(int, int); // 这里形参变量名可以省略 p2 = sum; int a = p2(10, 12); // 间接调用 // int a = (*p2)(10, 12); // 间接调用 // int a = sum(10, 12); // 直接调用 printf("%d\n", a); return 0; } void test() { printf("调用了test函数\n"); } int sum(int n1, int n2) { return n1 + n2; }