目录
指针基本概念
1.字符指针
2.指针数组
3.数组指针
对数组名的理解
小结
指针基本概念
在初阶指针中我们了解到一些指针的基本概念:
1.指针就是个变量,用来存放地址,地址唯一标识一块内存
2.指针的大小是固定的4/8个字节(32位/64位平台)
3指针是有类型的,指针的类型决定了指针的+整数的步长,指针解引用时操作的权限
例如,char*类型的指针解引用,它的权限(或步长)在32位平台下只有一个字节,而int*型的指针在32位平台下的权限(步长)为4个字节。
1.字符指针
#include<stdio.h>
int main()
{
char ch = 'w';
char* pc = &ch;
*pc = 'w';//这里的pc就是一个字符指针
return 0;
}
这里的pc就是一个字符指针,可以通过解引用pc来对w进行操作。
#include<stdio.h>
int main()
{
char arr[]="abcdef";//数组内容为字符串
//char *p="abcdef";//指针存储的内容为字符串"abcdef"的首个字母的地址
const char *p="abcdef";//abcdef为常量字符串,需要加const来修饰
return 0;
}
这两个定义有什么区别, char arr[]='' abcdef''只是一个对数组普通的初始化,将字符串''abcdef''放数组arr中
char *p="abcdef"中,abcdef是常量字符串,其前面需要用const来修饰,那么第二个操作是不是直接将整个字符串保存在字符指针中了呢?答案是否定的。
该操作实际上是将常量字符串''abcdef''的首个字符的地址保存到字符指针*p中
而我们应该如何验证呢?
#include<stdio.h>
int main()
{
char arr[] = "abcdef";
const char* p = "abcdef";
printf("%s\n",p);
printf("%c",*p);
return 0;
}
若此时p中存储的是字符串"abcdef"首字符的地址,那么第一个printf打印的结果应为"abcdef"
第二个printf中对字符指针p进行*解引用的结果应该是字符串首字符a。
于是我们得到了结论:该操作实际上是将常量字符串''abcdef''的首字符的地址保存到字符指针*p中
有这样一道面试题来练手,如下:
#include <stdio.h>
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
const char *str3 = "hello bit.";
const char *str4 = "hello bit.";
if(str1 == str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if(str3 == str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
可以看到str1与str2是不相同的,而str3与str4是相同的,那么这究竟是什么原因呢?
char str1[] = "hello bit.";
char str2[] = "hello bit.";
两个数组的内容是相同的,但是开辟的并不是同一块空间 ,str1和str2都是数组名,代表了数组首元素的地址,而两个数分别开辟了不同的内存空间,所以首元素的地址不同,所以str1与str2不同而对于str3和str4,"hello bit."由const修饰,为常量字符串同时str3与str4都是字符指针,存储的是字符指针"hello bit."的首字符的地址,且其是由const修饰的常量字符串,故str3与str4指向的空间的地址相同,所以str3==str4;
2.指针数组
类比:
整型数组-存放整型的数组;
字符数组-存放字符的数组;
指针数组-存放指针的数组;
#include<stdio.h>
int main()
{
int* arr1[10];//整形指针的数组
char *arr2[4];//一级字符指针的数组
char **arr3[5];//二级字符指针的数组
return 0;
}
使用指针数组模拟实现二维数组
#include<stdio.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
int* arr[3] = {arr1,arr2,arr3};
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d", arr[i][j]);
}
printf("\n");
}
return 0;
}
用i遍历左边的数组,用j遍历右边的数组 ,结果如下图:
需要特别注意的是,指针数组模拟实现的二维数组与真正的二维数组不同的是,该指针数组中各元素地址的存放不一定是连续的。
3.数组指针
首先来做一个区分
整形指针-指向整型变量的指针,存放整型变量的地址的指针变量;
字符指针-指向字符变量的指针,存放字符变量的地址的指针变量;
数组指针-指向数组变量的指针,存放数组变量的地址的指针变量;
int*p1[10];//指针数组(p1先与[]结合)
int(*p2)[10];//数组指针(p2先与*运算符结合)
p2是指针指向的是数组,称为数组指针变量。
对数组名的理解
数组名是数组首元素的地址,但是有两个例外,如下
1.sizeof(数组名),这里的数组名不是数组首元素的地址,数组名此时表示整个数组,sizeof(数组名)计算是整个数组的大小,单位是字节。
2.&数组名,这里的数组名表示整个数组,&数组名取出的是整个数组的地址
除此之外,所有地方的数组名都是数组首元素的地址。
#include<stdio.h>
int main()
{
int arr[10]={0};
printf("%p\n",arr);
printf("%p\n",&arr[0]);
printf("%p\n",&arr);
return 0;
}
前两个输出都表示的是数组首元素的地址,而第三个应该表示的是整个数组的地址,但是我们可以观察到三者的输出结果是相同的,
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr);
printf("%p\n", arr+1);
printf("%p\n", &arr[0]);
printf("%p\n", &arr[0]+1);
printf("%p\n", &arr);
printf("%p\n", &arr+1);
return 0;
}
观察运行结果
前两个输出+1,都只跳过了4个字节,而第三个+1跳过了40个字节,正好是数组十个元素所占的字节数,由此可见 &数组名 代表的是整个数组的地址。
#include<stdio.h>
int main()
{
int(*p)[10]=&arr;
return 0;
}
int(*p)[10]=&arr; 定义了一个数组指针,p的类型是int (*)[10]
小结
还没写完.....