指针,一般是代指针变量,指针是C语言中至关重要的一部分。由于内容较多,且较难,所以我们掰开了揉碎了慢慢讲,今天我们开始先讲解字符指针,指针数组,数组指针。
一、字符指针
指针与数据类型相同,有多种分类
int a = 0;
int* pd = &a; // 取a的地址,并将其存入指针变量pd中
double b = 5.20;
double* pb = &b; // 取b的地址
float c = 13.14;
float* pc = &c; // 取c的地址
char ch = 'w';
char* ph = &ch; // 取ch的地址
这些常见的指针变量我们很好理解,但是请看下列代码,并思考一下存在指针变量中的是什么
char* ph = “Hello bit!” // 思考一下,存在ph中的是什么呢?
存的是一个字符串吗?存的是整个字符串的地址吗?还是字符' H '?
我们写一段代码来看一下
#include
int main()
{
char* ph = "Hello bit";
printf("%p ",ph);
return 0;
}
我们不难发现,存入其中的还是地址,大家猜猜,存的是谁的地址呢?没错其实存的就是第一个字符的地址,当把一个常量字符串传给一个指针变量的时候,存入指针变量的就是常量字符串的第一个字符的地址。
怎么证明呢?我们可以尝试打印一下整个字符串
int main()
{
char* ph = "Hello bit";
printf("%p \n",ph);
printf("%s ",ph);
return 0;
}
打印字符串的规律,是从第一个字符开始,当遇到\0时停止打印,从这里就可以看出来指针变量ph中存放的就是常量字符的第一个字符的地址。
这里我们放一道经典面试题
// 一个经典面试题
char str1[] = "Hello world!";
char str2[] = "Hello world!";
if (str1 == str2)// 数组的名字就是数组第一个元素的地址
// 创建两个数组就是开辟了两块内存空间,所以两个数组的地址不同
{
printf("str1 is the same as str2\n");
printf("str1 的地址是%p\n", str1);
printf("str2 的地址是%p\n", str2);
}
else
{
printf("str1 is not the same as str2\n");
printf("str1 的地址是%p\n", str1);
printf("str2 的地址是%p\n", str2);
}
const char* str3 = "Hello world!";
const char* str4 = "Hello world!";
if (str3 == str4) // 常量字符不可以改变,所以一般会共同使用一个常量字符
{
printf("str3 is the same as str4\n");
printf("str3 的地址是%p\n", str3);
printf("str4 的地址是%p\n", str4);
}
else
{
printf("str3 is not the same as str4\n");
printf("str1 的地址是%p\n", str3);
printf("str2 的地址是%p\n", str4);
}
return 0;
}
大家先不要看后面解释,自己考虑一下答案
观看上面打印结果和代码的注释,我相信你们一定可以理解上面的题。
二、指针数组
指针数组,数组数组,顾名思义是一个数组,这个数组是专门存放指针的。
int main()
{
char* arr[4] = {"How are you?", "I'm fine", "Thank you", "And you?"};
int i = 0;
for (i = 0; i < 4; i++)
{
printf("%s 的第一个字符的地址是%p \n",arr[i],arr[i]);
}
return 0;
}
这里我们客串一下上面讲的字符指针,在学完上面的一节,我们知道在cahr* arr[4]这一个指针数组存放的是每一个字符串的第一个的字符的地址,我们打印出来观察结果
为了更好的理解指针数组,我选择了用一维数组模拟二维数组这一个例子来演示
int arr1[3] = { 1, 2, 3 };
int arr2[3] = { 4, 5, 6 };
int arr3[3] = { 7, 8, 9 };
int* arr_num[3] = { arr1,arr2,arr3 };
int k = 0;
for (k = 0; k < 3; k++)
{
int j = 0;
for (j = 0; j < 3; j++)
{
printf("%d ",arr_num[k][j]);
}
printf("\n");
}
在上述代码,我们把arr1,arr2,arr3 的首元素的地址存放在指针数组int* arr_num[3]中,我们可以通过使用二维数组的方式使用它,运行结果如下
在这里我值得注意的是,arr_num[k][j]可以改写成 *(arr_num[k]+j)
arr_num[k] + j 代表的数组中每一个元素的地址*(arr_num[k] + j)则是解引用,即是数组中的每一个元素。
三、数组指针
看到这里的朋友们可能会产生疑问了,数组指针~指针数组,他们两个有什么关系吗?
实际上是,一点关系也没有,数组指针,则是指向数组的一种指针。请看代码。
int main()
{
数字类型的指针有 int* double* float*
//int a = 0;
//int* num = &a;
字符的指针是char*
//char ch = 'W';
//char* pch = &ch;
指针数组,存放指针变量的数组
//int arr1[3] = {1 ,2 ,3 };
//int arr2[3] = {4 ,5 ,6 };
//int* arr_num[2] = {arr1, arr2};
// 数组指针,指向数组地址的指针
int num[3] = {1,2,3};
int(*arr_num)[10] = #
printf("%p \n",arr_num); // 打印结果明显与下面不同啊,下面打印首元素的地址,加1只是
// 加4个字节(int)
printf("%p \n", arr_num + 1); // 而这个的加多少取决于数组的字节大小(int 4 * 3 = 12)
// &数组名 -- 是数组的地址; 数组名 -- 数组首元素的地址
// 数组的地址与数组首元素的地址在数值上是相同的, 但意义上
// 不同
printf("%p \n",&num[0]);
printf("%p \n", &num[0] + 1);
printf("%p \n",num);
printf("%p \n", num + 1);
return 0;
}
这里是指针变量的使用
void Print_1(int arr[3][4],int x, int y)
{
int i = 0;
for (i = 0; i < x; i++)
{
int j = 0;
for (j = 0; j < y; j++)
{
printf("%d ",arr[i][j]);
}
printf("\n");
}
}
void Print_2(int (*pt)[4], int x, int y)
{
int i = 0;
for (i = 0; i < x; i++)
{
int j = 0;
for (j = 0; j < y; j++)
{
printf("%d ", (*(pt + i))[j]);// 二维数组名代表的二维数组第一行的地址
// 数组指针 +1 代表跳过一行数组
// 所以 pt + i 是第i行数组
}
printf("\n");
}
}
int main()
{
int arr_num[3][4] = { {1, 2, 3, 4},{4, 5, 6, 7},{7, 8, 9, 0}};
Print_1(arr_num,3 ,4);
Print_2(arr_num,3 ,4);
return 0;
}
今天的分享就到这里咯,喜欢的伙伴们记得评论点赞奥。