在说指针之前,肯定要去了解一个问题:指针是什么?
指针是一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值;
由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元,地址形象化起名指针
通过地址可以找到内存单元
指针是个变量,存放内存单元的地址(编号)
那么我们来看一段程序:
#include<stdio.h>
int main()
{
int a = 10;
int* p = &a; //指针变量,存储地址,存放在指针中的值当成地址处理
//对变量a进行取地址操作,将地址存到p中,p就是一个指针变量
printf("a的地址是%p", p);
return 0;
}
这段程序注释已经给出,int*是一种变量类型,而p的类型就是int*,所以p可以存储地址,
而*p(解引用)一般用来存值
那么:
一个小单元多大?一个字节,如何编址?
对于32位的机器,假设有32根地址线,每个地址线在寻址产生一个正电或负电
地址就是
00000000 00000000 00000000 00000000 ~~~
11111111 11111111 11111111 11111111 共2的32次方个地址
每个地址标识一个字节,
2^32Byte == 2^32/1024KB == 2^32/1024/1024MB ==2^32/1024/1024/1024GB == 4GB
这也就是地址的工作原理了
在32位的机器上,地址由0或者1组合32位成序列,需要用四个字节的空间来存储,所以一个指针变量的大小就是4个字节
在64位机器上,一个指针变量就应该是8个字节大小
那我们不禁需要思考一个问题:
指针大小均为4,那么指针类型究竟有什么实际意义?
/*int* pa = &a;
*pa = 0; //四个字节的内容均改为00
char* pc = &a;
*pc = 0; //只动了一个字节的内容
int*p 能够访问4个字节
char*p 能够访问1个字节
double*p 能够访问8个字节*/
指针类型决定了指针进行解引用操作时,能够访问的空间大小
指针可以+-整数吗?--可以
因为指针类型决定了指针一步有多远(指针的步长),加减整数实际上就是走了几步
int*p p+1 --> 4个字节
char*p p+1 --> 1个字节
double*p p+1 --> 8个字节
=========================================================================
同理,应用到数组中,也可以使用指针的步长变化进行数组的遍历:
#include<stdio.h>
{
int arr[10] = { 0 };
//char* p = arr;//数组名,首元素地址
int* p = arr;
int i = 0;
for (i = 0; i <= 9; i++)
*(p + i) = 1;
for (i = 0; i <= 9; i++)
printf("%d ", arr[i]);
return 0;
}
当然,也可以这样打印数组:
void print_arr()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = arr;
char* a = arr;
for (int i = 0; i < sz; i++) {
printf("%d ", *p);
p += 1;//p++ 指针加整数:跨步长(int,char,double..等)操作
}//1 2 3 4 5 6 7 8 9 10
printf("\n");
for (int i = 0; i < sz; i++) {
printf("%d ", *a);
a += 2;
}//1 0 2 0 3 0 4 0 5 0
printf("\n");
a = arr;
for (int i = 0; i < sz; i++) {
printf("%d ", *a);
a += 4; //注意,如果此时不把指针复原,指针会越界
}//1 2 3 4 5 6 7 8 9 10
printf("\n");
//思考:利用指针倒序打印数组?
p -= 1;//因为此前已经移动了指针的地址到p+10,所以可以减一成为p+9
for (int i = 0; i < sz; i++) {
printf("%d ", *p);
p -= 1;
}//10 9 8 7 6 5 4 3 2 1
}
同时,一定注意指针越界的问题,如果直接让指针变量自增,可能会出现越界的问题。
二维数组同样可以进行类似操作,我们一会儿再讲这个问题。
=========================================================================
指针既然可以移动,并且在字符串或者数组上都可以,那我们是不是可以使用指针实现求串(或者数组)的长度?--当然可以,这里给出字符串类型的求长,数组的也类似。
int my_strlen(char* str)
{
//strlen-->求字符串长度
char* start = str;
char* end = str;
while (*end != '\0')
{
end++;
}
return end - start;
}
在使用指针指向数组的时候,要注意越界的问题,同时也要注意:允许某个指针与指向数组最后一个元素后的内存位置的指针比较,不允许与指向第一个元素前的内存位置的指针比较
=========================================================================
那么,我们可以给任意变量赋初始值,指针类型也不例外:
不知道指针初始化该指向谁,就使用NULL
NULL -- 用来给指针初始化的。
检查有效性:
/*pa = NULL;
if(pa != NULL)
{......}
else{......}*/
那么在详解一里,我们最后再看一下野指针的问题,二级指针将放在详解二里介绍:
野指针,野指针是什么?
野指针:指针指向的位置不可知(随机的,不正确的,没有明确限制的)
野指针的成因:
int x;//局部变量不初始化,默认随机值
int* p;//局部指针变量不初始化,野指针
指针越界也会野指针
//或者指向一个被释放的值(函数)
如何避免?
指针初始化,变量被释放就置NULL,小心指针越界,使用之前检查有效性
那么指针详解一就到这里了,喜欢的小伙伴可以点个赞支持一下。