前言:通过指针我们可以访问存储于内存中的数据,也可以通过指针更改内存中的数据。那么今天让我们来揭开指针的神秘面纱吧!
目录
1.内存与地址的关系
关系:内存可以或分为一个一个的内存单元,内存单元中存放着程序的数据,一个内存单元的大小为1字节,并且每个内存单元都对应着一个独一无二的地址。
2.对内存的访问与使用
这里有一段代码:
#include <stdio.h>
int main()
{
int a = 10;
int* p = &a;//&a的意思就是取出内存中存放a的空间的地址,这句的意思就是将a的地址给p
*p = 12;//*p是访问p变量中存放的地址所指向的空间,并将空间的数据改为12
printf("%d", a);
return 0;
}
代码运行结果:
解释:如何访问和使用内存呢?
首先, 得有那块内存的地址,这是就需要用到 &(取地址操作符),比如&a 就是取出变量a所在内存单元的地址;然后,就是访问这块空间,就需要用到 *(解引用操作符),比如,*p,这时p中存放的是 a 的地址,*p就是访问a的内存单元。
下面是对上面代码和解释的图解:
3.对指针变量的定义的解读
int a = 10;
//这里先定义一个指针变量
int *p = &a;
解读:
* 与p 结合表示p是一个指针变量,注意指针变量中存储的数据是地址,int 表示 p指向的内存空间所存放的数据类型为 int。
int* 表示p的类型
图解:
4. 指针类型的大小
不管是int* 的指针还是char* 的指针其大小都是固定的,如果是32为机器,其大小为4字节,如果为64位机器,大小为8字节。
代码:
#include <stdio.h>
int main()
{
printf("%zd\n", sizeof(int*));
printf("%zd\n", sizeof(char*));
printf("%zd\n", sizeof(short*));
//......有兴趣可以自己测
}
x64环境:
x86环境下:
5. 指针类型的意义
示例代码:
#include <stdio.h>
int main()
{
int a = 10;
short b = 2;
int* pa = &a;
short* pb = &b;
}
1.如果是int* 的指针pa ,pa中存放的是a 地址的首地址,但因为pa 是int* 的指针所以他可以访问4个字节大小的内存单元,也就是一个int大小的内存空间;同理,pb 就可以访问2个字节大小的内存单元 。
2.int* 指针p进行加减运算时,也会加减相应的其指向数据类型的大小,比如,pa+1,就相当于pa中存放的地址+4,而pb+1,就是pb中存放的地址+2。
扩展(void*)
void* 的指针可以接受任何类型的指针,但是用解引用使用void* 类型的指针时,由于void*类型的指针不能直接解引用,所以必须强制类型转换成其他类型的指针。
6.传值调用和传值调用
图解:
解释:
最上面的代码的运行结果仍是10,因为传过来的是a的值,change函数中的a只是main中的一份临时拷贝,两者的地址不同,所以改变change中的a不会改变main中a的值。
而下面的代码是12,因为传过来的是a的地址,通过地址改变dea的值。
7.const修饰指针变量
7.1.const修饰*p
7.2.const修饰p
8.指针的运算
8.1 指针+-整数
#include <stdio.h>
int main()
{
int a = 0;
char b = 'a';
int* pa = &a;
char* pb = &b;
printf("%p\n", pa);
printf("%p\n", pa + 1);
printf("%p\n", pa - 1);
printf("%p\n", pb);
printf("%p\n", pb + 1);
printf("%p\n", pb - 1);
}
运行结果:
解释:因为pa指针是int*类型的,pa的+-相当于pa中存放的地址+-4(pa指向的数据类型的大小);pb+-,就相当于pb中存放的地址+-1。
8.2 指针-指针
代码:
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", (arr+9) - arr);//arr是数组首元素的地址,arr+9指向10
printf("%d\n", arr - (arr + 9));
return 0;
}
图解:
指针-指针的意思就是,两指针间有几个元素。
如果是高地址-低地址是正数;反之,是负数。
比如这题,arr 和arr+9之间有1,2,3,4,5,6,7,8,9这九个元素。
8.3指针的关系运算
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
if (arr > arr + 9)//比较两个指针的大小
printf(">");
else if (arr == arr + 9)
printf("=");
else if (arr < arr + 9)
printf("<");
return 0;
}
运行结果:
两个指针的关系运算实际上就是,比较指针中存放的地址的大小。
9. 指针使用时常见的错误
9.1 指针未初始化
错误代码:
#include <stdio.h>
int main()
{
int* p;//未初始化,并且使用指针
*p = 10;
printf("%d", *p);
return 0;
}
报错:
建议:
使用时一定要初始化,如果暂时不知道指针应该指向哪,可以先指针置NULL
9.2 越界访问
错误代码:
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = arr;
//错误:i= 10时 ,指针不再指向arr,而指向10的下一个空间,越界访问arr
for (int i = 0; i <= 10; i++)
{
printf("%d ", *(p + i));
}
return 0;
}
运行结果:
图解:
建议:清楚数据在内存分布,多写代码,多思考,多总结。
9.3 指向的变量空间被释放
错误代码:
#include <stdio.h>
int add(int a, int b)
{
int sum = a + b;
return ∑//当运行完这个函数时,在该函数中创建的变量都会给释放
}
int main()
{
int a = 10;
int b = 12;
int * psum = add(a, b);
printf("%d", *psum);
}
解释:psum 中时sum 的地址,而运行完add函数后,其内部定义的变量的空间均会被释放,此时psum指向的空间不再有数据,这时如果是用psum就变成了非法访问。
建议:不要返回函数中定义的变量的地址。
10.assert函数
介绍:assert 可以用来判断 指针是否为NULL,可以防止对空指针的解引用。
#include <assert.h>
int main()
{
int* p = NULL;
assert(p != NULL);//如果p等于NULL,会报错并终止程序
return 0;
}
祝语
愿大家指针学得越来越好!
标签:10,arr,int,地址,理解,深入,printf,指针 From: https://blog.csdn.net/2402_82658387/article/details/137042345