指针随笔解疑

本文详细探讨了CPU如何与内存条交互,指针在C语言中的重要性、定义及分类,包括基本类型指针、数组指针,以及动态内存分配的必要性、实例和与静态内存的对比。重点讲解了传统数组的局限性,为何需要动态内存,以及跨函数内存使用的挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


cpu如何对内存条进行处理?

cpu与内存条间有三条线,分别为控制线,数据线,地址线。控制线控制数据传输的方向,数据线是数据传输的渠道,地址线是用来确定内存条单元位置。

32根地址线可以控制pow(2,32)个字节,pow(2,32)=pow(2,30)*pow(2,2)=1024 *4
1B(Byte)=8b(bit)
1K=pow(2,10)B
1M=pow(2,10)KB=pow(2,20)B
1G=1024M=pow(2,30)B
字长 == 数据总线长度 == 地址总线长度(但是实际中地址总线很多高位用不到,所以默认置0,省去了一些地址总线,总的长度是小于64的,只是64位的机器理论上可寻址的范围在2的64次方B)


指针

一、指针的重要性

表示一些复杂的数据结构
快速的传递数据
使函数返回一个以上的值
能直接访问硬件
能够方便的处理字符串
是理解面向对象语言中引用的基础

总结:指针是c语言的灵魂

二、指针的定义

1.地址

内存单元的编号
从零开始的非负整数

范围:32位->4G【0~4G-1】
64位->8G【0~8G-1】

2.指针

指针就是地址,地址就是指针
				
指针变量就是存放内存单元编号的变量,或者说指针变量就是存放地址的变量
        
指针和指针变量是两个不同的概念 
        
但是要注意:通常我们叙述时会把指针变量简称为指针,实际他们含义并不一样 
        
指针的本质就是一个操作受限的非负整数,地址只能进行相减运算

三、指针的分类

1、基本类型指针

代码如下:

#include<stdio.h>

int main()
{
	//定义指针变量 
	int * p;/*p是变量名字,int *表示p变量存放的是int类型变量的地址 
		     int * p:不表示定义了一个名字叫做*p的变量
			 int * p:应该这样理解:p是变量名,p变量的数据类型是int *类型
			 		  所谓int *类型就是存放int变量地址的类型 
		   */
	int i = 3;
	int j;
	
	p = &i;
		/*
		  1.p保存了i的地址,因此p指向i;
		  2.p不是i,i也不是p,更准确的说,修改p的值不影响i的值,反之亦然。
		  3.如果一个指针变量指向了某个普通变量,则
		  		*指针变量    就完全等同于   普通变量
			例子:
				如果p是个指针变量,并且p存放了普通变量i的地址
				则p指向了普通变量i
				*p	就完全等同于   i
				或者说:	在所有出现*p的地方都可以替换成i
							在所有出现i的地方都可以替换成*p 
							
				*p  就是以p的内容为地址的变量 
		*/    
	j = *p;
	
	printf("%d %d",*p,j);
	return 0;
}



//指针就是地址,地址就是 指针
//地址就是内存单元的编号 
//指针变量就是存放地址的变量
//指针和指针变量是两个不同的概念 
//但是要注意:通常我们叙述时会把指针变量简称为指针,实际他们含义并不一样 

附注:

*的含义
		1. 乘法
		2. 定义指针变量:int * p;
		 	//定义了一个名字叫p的指针变量,int * 表示p只能存放一个int变量的地址 
		3.指针运算符(解地址符)
如何通过被调函数修改主调函数普通变量的值
		1. 实参必须为该普通变量地址
		2. 形参必须为指针变量
		3. 在被调函数中通过对 *形参名 进行赋值的方式,就可以修改主调函数相关变量的值

2、指针和数组

指针和一维数组

一维数组名是一个指针常量,他存放的是一维数组第一个元素的地址

下标和指针的关系

如果p是一个指针变量,则p[i]永远等价于*(p+i)

确定一个一维数组需要几个参数

需要两个参数:
数组第一个元素的地址
数组的长度

代码如下:

#include<bits/stdc++.h>
using namespace std;

void f(int *Aprr,int len){
//	for(int i=0;i<len;i++)
//		cout<<*(Aprr+i)<<" ";
//	cout<<endl;
	Aprr[2] = 88;//Aprr[2]等价于*(Aprr+2),也等价于a[2],也等价于*(a+2)
}
int main(){
	int a[3] = {1,2,3};
	int b[5] = {34,23,43,12,34};
	int c[100] = {12,12,234,34,12,23};
	cout<<a[2]<<endl;
	f(a,3);
//	f(b,5);
//	f(c,100);
	cout<<a[2]<<endl;
	return 0;
}

指针变量的运算

指针变量不能相加,不能相乘也不能相除
如果两个指针变量指向的是同一块连续空间中的不同存储单元,这两指针变量才可以相减

一个指针变量到底占多少字节

预备知识:
sizeof(数据类型)
功能:返回值就是该数据类型所占字节数
例子:sizeof(char) = 1; sizeof(int) = 4; sizeof(double) = 8;

	假设p指向char类型变量(1个字节)
	假设q指向int类型变量(4个字节)
	假设r指向double类型变量(8个字节)

p,q,r所占字节数相同
验证代码如下:

#include<bits/stdc++.h>
using namespace std;
int main(){
	char ch = 'a';
	int i = 99;
	double j = 99.6;
	char * p = &ch;
	int * q = &i;
	double * r = &j;
	
	cout<<sizeof(p)<<" "<<sizeof(q)<<" "<<sizeof(r)<<endl;
	return 0;
}

总结:一个指针变量,无论它指向的变量占几个字节,该指针变量本身只占4个字节或8个字节(电脑32位或64位)。一个变量地址使用该变量首字节的地址来表示。

指针和二维数组

3、指针和函数

4、指针和结构体

5、多级指针

专题:动态内存分配【重点难点】

一、传统数组的缺点

1、数组长度必须事先制定,且只能是常整数,不能是变量。
例子:

int a[5]; // ok
int len = 5; int a[len]; //error

2、传统形式定义的数组,该数组的内存无法手动释放。
在一个函数运行期间,系统为该函数中数组所分配的空间会一直存在,直到该函数运行完毕时,数组的空间才会被系统释放。
3、数组的长度一旦定义,其长度就不能再更改。数组的长度不能再函数运行的过程 中动态的扩充或缩小
4、A函数定义的数组,在A函数运行期间可以被其他函数使用,但在A函数运行完毕之后,A函数中的数组将无法在被其他函数使用。即传统定义的数组不能跨函数使用。

二、为什么需要动态分配内存

动态数组很好地解决了传统数组这4个缺陷,传统数组也叫静态数组

三、动态内存分配举例_动态数组的构造

四、静态内存和动态内存的比较

静态内存是由系统自动分配,由系统自动释放
静态内存是在栈分配的

动态内存是由程序员手动分配,手动释放
动态内存是在堆分配的

五、跨函数使用内存问题

#include<bits/stdc++.h>
using namespace std;
void f(int ** q){
	int i = 5;
	*q = &i;
}
int main(){
	int * p;
	f(&p);
	cout<<*p<<endl;//语法正确但逻辑错误
	//在f函数运行结束之后,i的内存已经被释放了,主函数没有访问权限,此时p没有指向,是一个野指针
	//此时还能输出5是因为这个内存内保存了5这个垃圾值 
	cout<<*p<<endl;//再次输出垃圾值已经消失 
	return 0;
}
#include<bits/stdc++.h>
using namespace std;
void f(int ** q){
	*q = (int *) malloc(sizeof (int));
	//q = 5;
	//*q = 5等价于p = 5; 
	**q  = 5;//*p = 5;
}
int main(){
	int * p;
	f(&p);
	cout<<*p<<endl;
	
	free(p);
	
	cout<<*p<<endl;
	
	return 0;
}

二进制全部为零的含义–00000000000000

1、数值零
2、字符串结束标记符’\0’
3、空指针 NULL
NULL表示的是零,而这个零不代表数字,而表示的是内存单元的编号零

计算机规定,以零为编号的存储单元内容不可读,不可写。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值