C语言指针详解

一.对指针的认识

1.内存和地址

一个内存单元就是一个字节,内存就像房间,地址就是房间号,可以根据地址找到某个内存单元(好比用房间号找房间)

内存单元的编号==地址==指针

如何理解编址?

cpu和内存之间有大量的数据交互,所以cpu和内存之间用一条线连起来

我们来理解一下地址总线,在32位机器下有32条地址线,一条地址线有两种情况(0或1,表示脉冲的有无),所以32条地址总线有2^32种情况

cpu将地址的信息通过地址总线传给内存,内存拿到地址可以找到地址所对应的对象,将数据通过数据总线传回cpu的寄存器中

2.指针变量和地址

&是取地址操作符,取出的地址放到变量中去,这个变量就叫指针变量,

指针变量是存放地址的变量,

int main()
{
	int a = 0;
	int* p = &a;//取出a的地址放入p中
	printf("%p\n",p);//int有4个字节,取出的是首字节的地址
    //解引用操作符*,可以把通过指针,找到指针指向的对象
	//可以把对象的值改变
	*p = 20;
	printf("%d\n", a);

	return 0;
}

3.如何理解指针类型:

int main()
{
	int a = 10;
	int* p = &a;
	//*说明p是一个指针变量,int表示p指向的对象的类型是整形类型

	return 0;
}

如果是(x86)32位环境下,就有32根地址线,一个地址就有32bit的大小,也就是4个字节

64位平台下就是8个字节

32位平台下地址是32个bit位,指针变量大小是4个字节
64位平台下地址是64个bit位,指针变量大小是8个字节
注意指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的

指针类型的意义:决定了解引用向前或向后走多远的距离

比如char*类型的指针解引用访问1个字节,int*类型的指针解引用访问4个字节

void* 类型的指针可以接收任何类型的地址,一般void* 用于函数的参数部分,用于接收不同类型的指针,但是void* 的指针不能用于指针计算

4.const修饰变量与指针变量

const修饰变量,变量就拥有了常属性,变量不能被修改,但本质上还是变量

通过地址还是能把变量的值改变,这样不就打破语法规则了,所以我们要用const去修饰指针变量

有两种修饰指针变量的方法:

1.

2.

5.指针的运算

指针的运算有3种:都可以用于打印数组

1.指针加减整数:

2.指针 - 指针:的绝对值是两个指针之间的元素个数

3.指针之间的逻辑运算:例如指针之间比较大小等价于地址与地址比较大小

6.野指针

野指针:指针指向的位置是不知道的

野指针的成因有很多种

例如:

1.指针未初始化,未初始化指针默认为随机值

2.指针指向数组的越界访问:指针指向超出了数组的范围

3.指针指向的空间释放:

n出函数后把n的空间还给了操作系统,再去找n的位置就相当于非法访问了,你就没有权限去访问了,但那个空间还在那里

assert断言要包含头文件assert.h,assert(p != NULL),括号里为真,继续执行下面的语句,为假停止执行并点出文件名和行号

如果不使用assert了,可以在assert.h前面加上NDEBUG,就把assert禁用掉了

#define NDEBUG 
#include<assert.h>

二.对于指针在数组中的理解

1.数组名表示数组首元素的地址

sizeof(数组名)计算的是整个数组的大小

&arr:取出的是整个数组的地址

除这两种外数组名都表示数组首元素的地址

假设数组名是arr

虽然数组名指向数组首元素的地址和 &数组名  都是指向首元素的,

但是arr+1跳过1个元素,&arr跳过整个数组

2.二级指针

一级指针通过a的地址找到a所对应的元素10

二级指针通过p的地址找到p所对应的元素0x11223344

3.指针数组与数组指针

指针数组是存放指针数组,数组中的每个元素都是指针

int* arr[5] :指针数组

int (*p)[5]:指针p指向的是长度为5,每个元素是int的数组,p是数组指针变量

p指向的是整个数组,&arr取出的是整个数组的地址

int main()
{
 int arr[10] = {0};
 int(*p)[10] = &arr; 
}

去掉变量就是类型

int(*)[5]:数组指针类型

三.各种类型的指针变量

1.字符指针变量

int main()
{
	char* p = "abcdef";
	//是把字符串的首字符的地址放入指针变量p中
	//这种常量字符串不可以改变值的
	//因为它存在于内存中的代码段中
	char arr[] = "abcdef";
	//这种把字符串存入了数组中
	//就可以改变值了
	// 因为数组中的每个元素都可以重新赋值
	//创建一个数组开辟一个空间 

	return 0;
}

2.二维数组数组名的含义

二维数组的数组名表示整个第一行的地址(第一行整个一维数组的地址)

二维数组:*一次找到一维数组,*两次找到一个元素

 3.函数指针变量

函数指针变量是用来存放函数地址变量

int main()
{
	int (*p) (int a, int b);

	return 0;
}

函数指针变量p 指向的函数的参数是两个int类型的,返回类型是int

函数指针变量的类型:int(*)(int a,int b)

函数指针数组:存放函数地址的数组

int (*p)(int a, int b) arr[5];

这个数组有5个元素,每个元素都是一个函数的地址

int main()
{
	int(*pf3)(int, int) = Add;
	printf("%d\n", (*pf3)(2, 3));//*可以不写,*是一个摆设
	printf("%d\n", pf3(3, 5));
	return 0;
}

 qsort函数是一个排序函数,可以排序各种数据

 

  • 19
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值