栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言之指针初级

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言之指针初级

目录

指针是什么

指针的原理

计算机中的32位与64位

总结

关于指针 

 指针的简单操作

指针和指针类型

指针的大小

指针类型的意义

野指针

野指针的成因

如何规避野指针

指针运算

指针和数组

数组名是什么?

整个数组的地址

二级指针

指针数组

指针与const

指针是什么

指针:在计算机科学中,指针是编程语言中的一个对象,利用地址,他的值直接指向存在电脑储存器中的另一个地方的值。由于通过地址能找到所需的变量单元,可以说地址指向变量单元。因此将地址形象化的成为指针。意思是通过他能找到以他为地址的内存单元

指针的原理

内存:内存是电脑上特别重要的存储器,计算机中所有程序的运行都在内存中进行。

所以为了有效地使用内存,就把内存分成了一个个细小的内存单元,每个内存单元的大小都是一字节。为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。

计算机中的32位与64位

32位——32根地址线——通电——每根线的通电状态(0/1)

64位——64根地址线——通电——每根线的通电状态(0/1)

电信号转化成数字信号就变成了1,0组成的2进制序列

以32位为例

00000000000000000000000000000000

……

11111111111111111111111111111111

总共可以表示的地址数为2^32个,这些序列都可以作为内存的编号,每个序列都可以作为内存的一个地址,然而表示地址的二进制数为32位最大为2^32因此用占用空间为4字节,对于64位则占用空间为8字节。

如果电脑为32位内存大小为0.5gb,那么电脑管理的每个内存单元大小为1bit

既然内存有地址,那么指针就可以拿出内存单元的地址

在C语言中指针用来存放变量的地址,指针本身也是个地址,只不过是存放地址的地址。

总结
  • 指针是用来存放地址的,地址是唯一标识一块地址空间的
  • 指针大小在32位平台上是4字节,在64位平台上是8字节 

关于指针 

 当一个变量所占空间大于一个地址单元时,那么他会往下面继续排列所占用的地址连续,如果取址这个变量,那么拿到的是这个变量第一个地址单元的地址。(取址a——&a)

经过仔细地计算和权衡,我们发现一个字节给一个对应的地址是比较合适的。

#include 
void main() {
	int a = 10;//占用4个字节,假设地址1字节
	int* pa=&a;//拿到的是a的4个字节中第一个字节的地址
	printf("%dn", *pa);//通过*pa可以很好的找到a
}

 指针的简单操作
int main() {
	int a = 56;
	printf("%pn",&a);
	int* pa = &a;
	*pa = 20;
	printf("%dn", a);
	return 0;
}

这里*号代表pa是指针变量

int代表pa执行的对象是int类型

这里存放a的地址是为了找到a,并对其进行控制

*pa就代表了a,这里的*号是解引用操作符目的是找到a

指针和指针类型

指针的大小

指针类型的大小都是相同的,指针有多大,取决于地址编号有多大(不是管理的内存空间)。

printf("%dn", sizeof(char*));
printf("%dn", sizeof(int*));
printf("%dn", sizeof(long*));
printf("%dn", sizeof(long long*));

指针类型的意义
#include 
void main() {
	int a = 0x11223344;//16进制,一个位表示4个2进制位,由此观之a总共占了4字节
	int* pa = &a;
	*pa = 0;
	//解引用后监测a的地址可以看到a地址所对应的数(4字节【16进制的11223344】)全部变成0
}
#include 
void main() {
	int a = 0x11223344;//16进制,一个位表示4个2进制位,由此观之a总共占了4字节
	char* pa = &a;
	*pa = 0;
	//解引用后监测a的地址可以看到a地址所对应的数(仅有开始的1字节【16进制的44】)变成00
}

由此观之:指针类型决定了解引用的权限有多大

#include 
void main() {
	int arr[10] = { 0 };
	int* pa = arr;
	char* pc = arr;
	printf("%pn", pa);
	printf("%pn", pa+1);
	printf("%pn", pc);
	printf("%pn", pc+1);
	//pa和pc两个地址的首位置相同,但是步长不同pa跳过4字节,pc跳过1字节
}

由此观之:指针类型决定了指针走一步能走多远(int*四字节,char*一字节)

注意:

  • 浮点型指针解引用是向内存中拿一个浮点类型的数
  • 整型指针解引用是向内存中拿一个整型的数

野指针

概念:野指针就是指针所指向的位置是不可知的(随机的,不明确的,没有明确限制的)

野指针的成因

1.指针未初始化

#include 
void main() {
	//这里的p就是一个野指针
	int* p;//p是一个局部的指针变量,局部变量不初始化的话,默认是随机值
	*p = 20;//非法访问内存
}

2.指针越界访问

#include 
void main() {
	int arr[10] = { 0 };
	int* p = arr;
	//指针指向的范围超出数组arr的范围,之后的地址所储存的东西我们不可预知(p+10)为野指针
	*(p + 10) = 20;
}

3.指针指向的空间释放

理解:当申请一块特定的空间时(知道本空间地址),后来此空间是释放掉了还给了操作系统就不属于自己了。

#include 
int* test() {
	int a = 10;
	return &a;
}
void main() {
	int* p = test();//出了作用域变量a销毁
	*p = 20;
}

如何规避野指针
  • 指针初始化(int* p=null)
  • 小心指针越界(C语言本身不会检测数组越界行为)
  • 指针指向的空间释放即时设置null
  • 指针使用之前检查有效性(判断指针是否为null如果不为null则直接用)

指针运算
  • 指针+-整数
  • 指针-指针
  • 指针的关系运算 

1.指针+-整数

2.指针的关系运算

标准规定

#include 
void main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int* pend = arr + 9;
	while (p<=pend)//指针关系运算
	{
		printf("%dn", *p);
		p++;//指针加减运算
	}
}

3.指针-指针

#include 
void main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%dn", &arr[9] - &arr[0]);
    //结果为9
}

指针与指针相减前提:两个指针指向同一块空间

指针-指针得到的时指针之间的元素个数

理解:指针+9-指针=9

注意:指针+指针没什么用,别纠结了


指针和数组

数组名是什么?
#include 
void main() {
	int arr[10] = { 0 };
	printf("%pn",arr);
	printf("%pn",&arr[0]);
	//最终得到的结果一样,由此观之,数组名是首元素的地址
}
#include 
void main() {
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int* p = arr;//验证数组名是首元素地址
	printf("%dn", arr[2]);
	printf("%dn", p[2]);
	printf("%dn", 2[arr]);
	printf("%dn", 2[p]);
	//arr[2] 等价于*(arr + 2),最后又有*(2+arr)等价于2[arr]
	//最终结果都为3
}

整个数组的地址
#include 
void main() {
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	printf("%pn", arr);
	printf("%pn", arr+1);
	printf("%pn", &arr);
	printf("%pn", &arr+1);
	//最终得到的结果3行和4行不同——>得出结论arr为数组首元素的地址,&arr为整个数组的地址
}

二级指针

指针变量也是变量,变量就有地址,那么一级指针变量的地址存放的地方就称为二级指针

#include 
void main() {
	int a = 10;
	int* pa = &a;//pa是指针变量,一级指针
	//这里的类型依据pa所对的类型int*——所以才出现后面的int**
	int** ppa = &pa;//pa也是个变量,是变量就有地址,用ppa存放,ppa为二级指针
	printf("%dn", **ppa);//*ppa=pa,*pa=a,推出**ppa=a;
}

指针数组

定义:存放指针的数组

整形指针的数组:int* parr[5];

指针与const

const修饰变量,这个变量就称为常变量,不可更改,但是他本质还是一个变量

#include 
void main() {
	const int num = 10;//加了const之后num不可更改
	int* p = #
	*p = 20;
	printf("%dn", num);
	//但是会发现却可以以解引用的方式修改num为20
}
#include 
void main() {
	const int num = 10;//加了const之后num不可更改
	int a = 9;
	int const * p = #//在*之前加了const则*p不可更改,但是p指向的内容却可更改
	p = &a;
	printf("%dn", num);
}
#include 
void main() {
	const int num = 10;//加了const之后num不可更改
	int a = 9;
	int const * const p = #//在*之前加了const则*p不可更改,在p前加const表示p的指向内容也不可更改
	printf("%dn", num);
}

总结:

const修饰指针变量的时候

  • const如果放在*左边,则修饰的是*p,则*p不可更改
  • const如果放在p的左边*的右边则修饰的是p,则p不可更改
  • const如果既放*左边也放p的左边*右边,则修饰的是p与*p,则两者均不可更改
  • 二级指针亦复如是const *pa与const **pa与const pa

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/917009.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号