马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
指针的概念
指针是一个特别的变量,它存储的是某块内存空间的地点值
地点的概念
每个数据都有自己的地点,每个地点存放一字节的数据。用下面的例子举例
int a[4]={1,2,3,4};
假设数组a的首地点是0x1000,则第一个元素 1 (元素 1 是int型,占4个字节)的存储方式如下:
内存地点 | 字节内容(十六进制) | 分析 | 0x1000 | 0x01 | 最低有效字节(LSB) | 0x1001 | 0x00 | | 0x1002 | 0x00 | | 0x1003 | 0x00 | 最高有效字节(MSB) | 大部门计算机系统都采用小端存储模式,即数据低位字节放在低地点处,高位字节放在高地点处
数组中所有的元素在内存中的存储方式如下:
地点 | 内容(值) | 分析 | 0x1000 | 1 | a[0](首元素) | 0x1004 | 2 | a[1] | 0x1008 | 3 | a[2] | 0x100C | 4 | a[3] |
数组名 a 其实就是数组首元素的地点(即 &a[0]),它本身不是一个变量,只是表示数组的起始地点
如果对 a 取地点(&a)得到的地点值与 a 类似,但类型差别:
- a 的类型是 int* (指向 int 的指针)
- &a 的类型是 int(*)[4](指向长度为4的数组的指针)
int *p = a;
指针变量 p 指向数组首元素,相当于 指针p 的值为 0x1000,就是数组的起始地点
指针的大小
32位的系统上,地点长度就是32位,也就是4个字节。所以一个指针变量就是4个字节。 char *p; sizeof(p) = 4;
取地点& 解引用*
&a 的结果是一个指针,指针的类型就是 a 的类型加上 * ,指针指向的类型是 a 的类型,指针指向的地点是 a 的地点。
*p 的结果是 指针p 所指向的内容,这个内容可以是一个数值、字符串、数组、指针。
注意:
指针的类型决定:
1.指针算术运算的步长,即 p+1 移动的字节数。
2.解引用时,访问多少字节的数据
例如:
- int a[10]={0x0101,1,2,3,4,5,6,7,8,9};
- int *p=a;
- printf("%d %d",*p,*(p+4)); //打印257 4
- printf("%d",*(char*)p); //打印1,(char*)类型强转只是告诉编译器:
- //1.如何解释该地址处的数据(按一字节读取),从低位数据开始读
- //2.指针算术的步长
- char *p=a;
- printf("%d %d",*p,*(p+4)); //打印1 1
复制代码 指针 与 数组
char *p = "abcde";
p:指针指向字符串开头,也就是第一个字节a的地点,sizeof(p)=4
p+1:指针指向了第二个字节b的地点,sizeof(p+1)=4
*p:指针所指向的内容,也就是第一个字节a,sizeof(*p)=1 p[0]:同上
&p:对指针变量 p 取地点,sizeof(&p)=4
&p+1:指针变量 p 的地点的下一个地点,然后将地点往后移动4个字节的大小(这里+1的步长是sizeof(char*)=4字节),sizeof(&p+1)=4
&p[0]+1:先取第一个字节a的地点,然后将地点向后移动1个字节的大小(这里+1的步长是sizeof(char)=1字节),得到p[1]的地点,也就是字符b的地点。sizeof(&p[0]+1)=4
int arr[5] = {1,2,3,4,5};
arr:表示整个数组,sizeof(arr)=5
arr+0:表示首元素的地点,sizeof(arr+0)=4
*arr:arr本质上是指向数组开头的指针,也就是指向第一个元素,*arr则是对第一个元素解引用,所以*arr=1,sizeof(*arr)=1
arr[1]:arr的第二个元素
&arr:对数组取地点,sizeof(&arr)=4
&arr+1:数组arr的地点的下一个地点,然后将地点往后移动4个字节的大小(这里+1的步长是sizeof(int*)=4字节),sizeof(&arr+1)=4
&arr[0]+1:取出第一个元素的地点,然后将地点向后移动4个字节的大小(这里+1的步长是sizeof(int)=4字节),sizeof(&arr)=4
内存的三种分配方式
1.静态内存分配(全局变量、静态变量、常量)
特点:
- 内存的分配和释放由编译器在编译阶段完成。
- 分配的内存在步伐整个生命周期内存在(直到步伐结束才释放)。
优点:
缺点:
- 内存固定,无法动态调整大小。
- 大概浪费内存(未使用的静态内存无法释放)。
2.栈内存分配(函数内的局部变量、函数参数)
特点:
- 内存的分配和释放由编译器自动管理(通过函数调用栈)。
- 分配的内存随函数调用结束自动释放(局部变量的生命周期)。
优点:
- 分配速度快(仅移动栈指针)。
- 无需手动管理,内存自动回收。
缺点:
- 内存大小固定(栈空间有限,默认几MB)。
- 大对象大概导致栈溢出(如大数组 int arr[1000000])。
3.堆内存分配(动态大小的数据结构(链表、数组)、需要长期存在或跨函数使用的数据)
特点:
- 内存的分配和释放由步伐员手动控制(通过 malloc, calloc, free 等函数)。
- 内存生命周期完全由代码逻辑决定。
优点:
缺点:
- 分配速度较慢(需查找可用内存块)。
- 需手动管理,易导致内存走漏(忘记 free)或野指针。
常用的动态内存分配函数:
- malloc:用于分配指定大小的内存块,返回指向该内存块起始地点的指针。如果分配失败,返回空指针(NULL)。
- calloc:与malloc类似,但它还会将分配的内存块初始化为零。函数原型:void* calloc(size_t num_elements, size_t element_size);。
- realloc:用于重新分配已经分配的内存块大小,可以扩大或缩小内存块。函数原型:void* realloc(void* ptr, size_t new_size);。
- free:用于释放动态分配的内存块,将该内存块返回给堆,以便其他步伐可以使用。函数原型:void free(void* ptr);。
函数 | 功能 | 初始化 | 特别性 | malloc | 分配未初始化内存 | 无 | 基础分配函数 | calloc | 分配并初始化为零 | 全零 | 适合数组初始化 | realloc | 调整已分配内存的大小 | 无 | 大概移动内存块 | free | 释放内存 | N/A | 必须与分配函数成对使用 |
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |