目录

C语言:指针4(常量指针和指针常量及动态内存分配)

常量指针与指针常量

常量:分为字面量和只读常量,字面量就是我们平时直接操作的量:

printf("%d\n",12);/printf("%s\n","hello");只读常量使用关键字 const 修饰,凡是被这个关键字修饰 的变量,一旦赋值,值就不能改变。

语法:

复制代码
// 字面量
printf("%d\n",12);
// 只读常量
const int a = 10;
a = 21;// 编译错误,因为此时这个变量是只读常量,所以不可更改其值

常量指针

定义:常量的指针,本质是一个指针,指针指向的数据不能改变。

定义格式:

复制代码
const 数据类型 *变量名;

举例:

复制代码
const int *p;// p就是常量指针

结论

  1. 常量指针指向的数据不能被改变(不能解引用间接修改数据)

  2. 常量指针的地址可以改变(指向是可以改变)。

应用场景:作为形式参数,实际参数需要给一个常量。

复制代码
void foreach(const int *array,const int len){..}

案例:

复制代码
#include <stdio.h>
int main(int argc,char *argv[])
{
    // 定义变量
    int a = 10;
    // 定义常量指针
    const int *p = &a;
    //*p = 100;// 编译报错,常量的值不能被改变
    printf("%d\n",*p);// 10
    // 定义变量
    int b = 20;
    p = &b;    // 编译通过,常量的地址可以被改变
    printf("%d\n",*p);// 20
    return 0;
}

指针常量

定义:指针的常量,指针的指向不能改变

定义格式:

复制代码
数据类型* const 变量名;

举例:

复制代码
int* const p;// 指针常量

结论:

  1. 指针常量的指向不能改变(不能给指针变量重新赋地址值)

  2. 指针常量的指向的数据可以改变。

注意:指针常量在定义时就要赋值;不能先定义后赋值,否则编译报错

案例:

复制代码
#include <stdio.h>
int main(int argc,char *argv[])
{
    // 定义变量
    int a = 10;
    // 定义指针常量
    int* const p = &a;
    *p = 100;// 编译通过,常量的值可以被改变
    printf("%d\n",*p);// 100
    // 定义变量
    int b = 20;
    //p = &b;   // 编译报错,常量的地址不可被改变
    printf("%d\n",*p);// 100
    return 0;
}

常量指针常量

定义语法:

复制代码
const 数据类型* const 变量名;

举例:

复制代码
const int* const p;

作用:p的指向不能被改变(地址不可更改),p指向的数据不能改变(地址对应的数据不可更改)

动态内存分配

我们要想实现动态内存分配,就需要学习标准C提供的函数库(API):

  1. 函数所属的库文件

  2. 函数的原型-函数的声明

函数名

形参

返回值类型

  1. 函数功能

注意:内存分配函数在申请内存时,建议用多少申请多少,可以有少量的预留量;但不能越界访问

(虽然编译和运行不报错,但是数据不安全(野指针))

常用函数

malloc

头文件: #include <stdlib.h>

函数功能:C库函数 void* malloc(size_t size); 分配所需的内容空间,并返回一个指向它的

指针。

函数原型:

函数名:malloc

形式参数:size_t size:需要申请的内存块的大小,以字节为单位。本质上是一个 unsigned

long int

返回值类型:void*(万能指针):该函数返回一个指针,指向已分配大小的内存,如果请

求失败,返回NULL(0x000000000000对应的一块不可访问的区域)

举例:

复制代码
int* p = (int*)malloc(sizeof(int));
// 清零,这里不是释放内存,只是将内存中的随机值清理掉
bzero(p,sizeof(int));
// 使用空间...
// 释放空间
free(p);

说明:

malloc函数分配的内存没有默认值,内存中的数据是随机值(大概率是0),使用前需要借

助于bzero()清零。

malloc函数申请的内存空间连续

calloc

头文件: #include <stdlib.h>

函数功能:C库函数 void* calloc(size_t nitems,size_t size) 分配所需的内存空间,并返回

一个指向它的指针。

malloc和calloc之间的区别:malloc不会设置内存为零,需要使用bzero()清零,而calloc会设置内

存为零。

函数原型:

函数名:calloc

形式参数:

size_t nitems:申请多少个

size_t size:一个占几个内存单元(1个内存单元=1个字节)

返回值类型:void*:该函数返回一个指针,指向已分配大小的内存,如果请求失败,返回

NULL

举例:

复制代码
int *p = (int*)calloc(1,sizeof(int));  
// 使用空间...
// 释放空间
free(p);

说明:

calloc函数分配的内存有默认值,每个内存单元都是0

calloc函数申请的内存空间连续

calloc大多时候为数组中的元素申请内存

案例:

复制代码
#include <stdio.h>
#include <stdlib.h>
/**
 * 需求:转存栈中数组中的数据
 */ 
int main(int argc,char *argv[])
{
    // 在栈区创建一个数组
    int arr[3] = {11,22,33};
    // 在堆区申请内存
    int *p = (int*)calloc(3,sizeof(int));
    // 转存
    for(int i = 0; i < 3; i++)
        p[i] = arr[i];
    // 遍历堆中数据
    for(int i = 0; i < 3; i++)
        printf("%-4d",p[i]);
    
    printf("\n");
 // 在堆中申请空间,使用完毕一定要记得释放
    free(p);
    p = NULL;
    printf("p=%p\n",p);
    return 0;
}

realloc

头文件: #include <stdlib.h>

函数功能:尝试重新调整之前调用malloc或calloc所分配的ptr所指向的内存块的大小。

函数原型: void *realloc(void *ptr,size_t size)

函数名:realloc

形式参数:

void *ptr:是malloc或者calloc的返回值

size_t size:重新分配后的内存大小

返回值:void*:该函数返回一个指针,指向已分配大小的内存。如果请求失败,返回

NULL。

案例:

复制代码
 int *p = (int*)malloc(4);
 int *w = (int*)realloc(p,20);
 // int *q = (int*)realloc(p,0); // 等效于free(p)

说明:

  1. realloc以原来malloc返回的内存地址开始,分配总共20个字节的内存空间

  2. 如果原来的内存空间后有20个连续空间,就扩容20-4 =16个内存单元,返回原来旧的内存首

地址。

  1. 如果原来的内存空间后不够20个连续内存空间,就重新找一个内存地址开始,申请20个内

存单元。并将原来的数据拷贝到新的内存中,回收旧的内存单元,并返回新的内存首地址。

free

头文件: #include <stdlib.h>

函数功能:释放之前调用 malloc、calloc、realloc所分配的内存空间,是访问完记得使用NULL

置空。

函数原型: void free(void *ptr)

函数名:free

形式参数:

void *ptr:calloc,malloc.realloc的返回值

返回值类型:void:没有返回值

注意:

  1. 堆内存中的指针才需要回收,栈中系统会自动回收

  2. 堆内存不能重复回收,运行会报错

说明:

  1. 堆的内存空间相比较栈要大很多

  2. 内存分配函数返回的指针变量可以参与运算(只读),但不能被修改(p++或者p+=i 是错误

的)

本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
牵牛老人8 分钟前
Qt 元对象系统探秘:从 Q_OBJECT 到反射编程的魔法之旅
开发语言·qt
一只小闪闪8 分钟前
langchain4j搭建失物招领系统(六)---实现失物查询功能-RAG使用
java·人工智能·后端
用户114818678948411 分钟前
大文件下载、断点续传功能
前端·nestjs
顾林海12 分钟前
Flutter 文本组件深度剖析:从基础到高级应用
android·前端·flutter
eason_fan13 分钟前
在 Windows 环境下使用 Linux 命令行:Cygwin 的安装与配置
前端·命令行
HHW13 分钟前
NVM:node版本管理工具
前端
阿炸14 分钟前
Promise及其API源码的实现思考过程
前端·javascript
雷渊16 分钟前
RocketMQ生产者的消息被消费后会永久放在磁盘里吗?
java·后端·面试
2401_8906661323 分钟前
免费送源码:Java+ssm+MySQL 校园二手书销售平台设计与实现 计算机毕业设计原创定制
java·spring boot·python·mysql·小程序·php·课程设计
酒茶白开水23 分钟前
React十案例下
前端·react.js·前端框架