C语言中的const和free用法详解

注意:C语言中的const和C++中的const是有区别的,而且在使用VS编译测试的时候。如果是C的话,请一定要建立一个后缀为C的文件,不要是CPP的文件。因为,两个编译器会有差别的。

一、C语言中的const比较常见的用法,const做常量

#include<stdio.h>
#include<malloc.h>
#include<string.h>
/*
C中的const用法(使用VS测试的时候,要注意建立一个C后缀的文件,因为C的编译器和C++的编译器还是有区别的)
*/
//const用作常量,int const a和const int a是一个意思都是表示常量,可以通过指针来改变常量的值
void test1(){
  const int a = 10;
  int* p = &a;
  *p = 20;
  printf("p:%d\n",*p);
  printf("a:%d\n",a);
} 

通过上面的例子,我们可以发现在C语言中,当使用const作为常量的时候,其实我们是可以通过指针,进行间接赋值从而改变常量的值。如果,上面的例子是在C++编译器中,int* p = &a,这句话会在编译的时候报错,当然你可以通过强转int* p = (int*)&a,强转之后指针p还是无法间接改变常量的值,这一点我也觉得很奇怪,明明指针p指向的是常量a,但是却无法改变a的值,打印的时候会出现两个不同的值。有网友说,那是因为汇编代码中a就代表10,也就是说,在汇编代码中a是直接用10代替了。

二、C语言中的const作为指针使用的时候

//const用法作为指针,const char* a,表示a是一个指向常量的一个指针,即常量的内容不能改变,但是指针a(a的值并不是a指向的常量)可以改变
// char* const a就表示a是一个指针常量,即内容可以改变,但是指针a不能改变
void test2(){
  const char* a = NULL;
  a = "ABCD";//编译通过,运行不会报错,因为这里改变的是指针a,这里改变的并不是常量。这句代码会为字符串"ABCD"在全局区中开辟一块空间,
  //然后把字符串的首地址赋值给a
  //*a = 'a';//编译报错,因为内容是不可以修改的
  char* const b = NULL;
  *b = "abcde";//编译通过,因为内容可以修改
  //b = "aab";//编译报错,因为指针变量是一个常量,不能被修改
  const char* const c = "abcd";//内容和指针变量都不能被修改
} 

C语言中的细节是非常多的,所以一定要注意一下这些细节,如果想学好C语言一定要了解C语言的内存四区,考虑问题的时候从内存四区的角度去思考问题。

三、下面再介绍一个关于C语言中free函数的使用

/*
c语言中free
1、C语言中的free是用来释放内存空间的,释放的是指针所指向的内存空间,释放完之后记得将指针赋NULL,避免出现野指针
2、在C语言中使用free方法的时候要特别注意,如果没有释放好可能会导致宕机,原因是有的内存空间是不能被释放的,如常量区
*/
void testp1(){
  //给指针开辟空间的时候,要养成一个良好的习惯
  //声明指针的时候,记得赋NULL
  char* p1 = NULL;
  p1 = (char*)malloc(10);//p1中的内存是在堆中开辟的
  p1 = "abcdef";
  printf("p1:%s\n",p1);
  //释放内存的时候,先要判断是否为NULL,释放完之后记得给指针赋NULL,避免野指针
  if (p1 != NULL){
    free(p1);
    //如果,不赋NULL,释放之后不小心再使用p1的时候就会宕机
    //因为,指针p1所指向的内容已经被释放掉了,而p1并不为空,却指向了一个不能被这个程序使用的空间,所以导致了宕机,而p1就成了一个野指针
    printf("p1:%d",p1);//这代码会导致宕机
    p1 = NULL;
  }
}
//下面的程序也会导致宕机,因为,free不能释放常量区中的内存
void testp2(){
  char* p2 = "abcdef";//"abcdef"字符串是存放在常量区中的
  if (p2 != NULL){
    free(p2);
    p2 = NULL;
  }
} 

free函数不能释放全局区的内存,也不能释放数组的空间,如(char a[2]={'a'}),都会导致宕机。

四、最后再介绍一下C语言中的数组比较容易犯的错误

void main(){
  //编译报错,初始值设定项太多,因为,在c语言中编译器会自动添加\0表示结束符,所以实际上a的大小是6,但只定义了5个所以导致编译报错
  char a[5] = {'a','b','c','d','e'};
  //测试数组大小用sizeof(a)是表示数组的所占内存空间的大小5*sizeof(char)
} 

以上所述是小编给大家分享的C语言中的const和free用法详解,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的,在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • C语言编程技巧 关于const和#define的区别心得

    #define ASPECT_RATIO 1.653 编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号列表中.如果涉及到这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的是1.653,而不是ASPECT_RATIO.如果ASPECT_RATIO不是在你自己写的头文件中定义的,你就会奇怪1.653是从哪里来的,甚至会花时间跟踪下去.这个问题也会出现在符号调试器中,因为同样地,你所写的符号名不

  • 总结C语言中const关键字的使用

    什么是const? 常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的.(当然,我们可以偷梁换柱进行更新:) 为什么引入const? const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点. const关键字使用非常的灵活,这一点和php差别很大,php中const用来在类中定义一个常量,而在c中,const因位置不同有不同的作用,因情景不同有不同的角色,使用起来也是非常的灵活. (1):const用来修饰普通的变量(指针变量除外)的时

  • C语言在头文件中定义const变量详解

    C语言在头文件中定义const变量详解 在头文件中定义const不会有多变量的警告或错误,如果该头文件被大量包含会造成rom空间的浪费. 通过查看*.i文件的展开呢,可以发现每个.i文件都会有相应的变量展开. 查看*.map文件,能查看到该变量的多个地址分配. 在预编译的时候如果在头文件定义了const变量,每一个包含该头文件的c文件都会将其展开,而在编译的时候不会报错,因为这符合语法规则,每一个包含这个头文件的*.c文件都会编译一次这个变量,分配一个新的地址,然后在链接的时候也不会报错,因为每

  • C语言中auto,register,static,const,volatile的区别详细解析

    1)auto这个关键字用于声明变量的生存期为自动,即将不在任何类.结构.枚举.联合和函数中定义的变量视为全局变量,而在函数中定义的变量视为局部变量.这个关键字不怎么多写,因为所有的变量默认就是auto的. (2)register这个关键字命令编译器尽可能的将变量存在CPU内部寄存器中而不是通过内存寻址访问以提高效率. (3)static常见的两种用途:1>统计函数被调用的次数; 2>减少局部数组建立和赋值的开销.变量的建立和赋值是需要一定的处理器开销的,特别是数组等含有较多元素的存储类型.在一

  • C语言中const,volatile,restrict的用法总结

    1. const 变量声明中带有关键词const,意味着不能通过赋值,增量或减量来修改该变量的值,这是显而易见的一点.指针使用const则要稍微复杂点,因为不得不把让指针本身成为const和指针指向的值成为const区别开来.下面的声明表示pf指向的值必须是不变的 constfloat *pf:而pf则是可变的,它可以指向另外一个const或非const值:相反,下面的声明说明pf是不能改变的,而pf所指向的值则是可以改变的: float* const pf: 最后,当然可以有既不能改变指针的值

  • 详解C语言中const关键字的用法

    关键字const用来定义常量,如果一个变量被const修饰,那么它的值就不能再被改变,我想一定有人有这样的疑问,C语言中不是有#define吗,干嘛还要用const呢,我想事物的存在一定有它自己的道理,所以说const的存在一定有它的合理性,与预编译指令相比,const修饰符有以下的优点: 1.预编译指令只是对值进行简单的替换,不能进行类型检查 2.可以保护被修饰的东西,防止意外修改,增强程序的健壮性 3.编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编

  • C语言 volatile与const同时使用应注意的问题

    const和volatile放在一起的意义在于: (1)本程序段中不能对a作修改,任何修改都是非法的,或者至少是粗心,编译器应该报错,防止这种粗心: (2)另一个程序段则完全有可能修改,因此编译器最好不要做太激进的优化. "const"含义是"请做为常量使用",而并非"放心吧,那肯定是个常量"."volatile"的含义是"请不要做没谱的优化,这个值可能变掉的",而并非"你可以修改这个值"

  • C语言基础知识点解析(extern,static,typedef,const)

    一.extern的使用方法 下面是<C语言程序设计>中的关于extern的解释: 在一个源程序的所有源文件中,一个外部变量只能在某个文件中定义一次,而其他文件可以通过extern声明来访问它(定义外部变量的源文件中也可以包含对该外部变量的extern声明).外部变量的定义中必须指定数组的长度,但extern声明不一定指定数组的长度. 外部变量的初始化只能出现在其定义中. 假设函数push与pop定义在一个文件中,而变量val与sp在另一个文件中定义本那个被初始化(通常不太可能这样组织程序),则

  • C语言中的const和free用法详解

    注意:C语言中的const和C++中的const是有区别的,而且在使用VS编译测试的时候.如果是C的话,请一定要建立一个后缀为C的文件,不要是CPP的文件.因为,两个编译器会有差别的. 一.C语言中的const比较常见的用法,const做常量 #include<stdio.h> #include<malloc.h> #include<string.h> /* C中的const用法(使用VS测试的时候,要注意建立一个C后缀的文件,因为C的编译器和C++的编译器还是有区别的

  • C语言const关键字的用法详解

    目录 1 介绍 1.1 const修饰变量 1.2 const修饰数组 1.3 const修饰指针 1.4 const修饰函数参数 2 const对程序的影响 3 总结 1 介绍 const关键字是constant的缩写,翻译为常量.常数.在C语言中const的作用很强大,它可以修饰变量.数组.指针.函数参数等. 1.1 const修饰变量 const修饰变量,表示希望此变量具有只读性,防止被直接直接修改. //const关键字是constant的缩写,翻译为常量.常数. //在C语言中cons

  • 在C#和Java语言中for和foreach的区别详解

    for循环和foreach循环的区别 首先在这里声明一点,C#和Java这两种语言很相似,尤其是初学的数据类型那一部分,所以这里写的for和foreach的区别在C#和Java中都适用. 我会在下面分别列出两种语言的for和foreach分别循环打印一个数组,大家可以看看区别 话不多说,直接上代码: //c# //先创建一个数组 int[] arr = new int[3] {99, 11, 22}; //利用for循环打印(可以创建一个变量 i;判断这个i是否小于数组的长度;每次循环i自增1)

  • Java 语言中Object 类和System 类详解

    Object是java所有类的基类,是整个类继承结构的顶端,也是最抽象的一个类.大家天天都在使用toString().equals().hashCode().waite().notify().getClass()等方法,或许都没有意识到是Object的方法,也没有去看Object还有哪些方法以及思考为什么这些方法要放到Object中. 一.Java Object类简介-所有类的超类 Object 是 Java 类库中的一个特殊类,也是所有类的父类.也就是说,J ava 允许把任何类型的对象赋给

  • C语言中printf()缓冲问题详解

    前言 缓冲区又称为缓存,它是内存空间的一部分.也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区. 缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区. 为什么要引入缓冲区 比如我们从磁盘里取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度. 又比如,

  • C语言中sizeof()与strlen()的区别详解

    前言 sizeof()和strlen()经常会被初学者混淆,但其中有有很大区别: sizeof() 1. sizeof()[操作数所占空间的字节数大小]是一种c中的基本运算符. 可以以类型.指针.数组和函数等作为参数. 头文件类型为unsigned int. 运算值在编译的时候就出结果,所以可以用来定义数组维数. char a[5]="123"; int b=sizeof(a);//b=5 int c=strlen(a);//c=3 sizeof()是一种单目操作符,是用来计算你所使用

  • golang语言中wasm 环境搭建的过程详解

    golang 安装 通过官方地址 下载.MacOS 也可通过 brew 快速安装: $ brew install golang $ go version go version go1.17.2 darwin/arm64 golang 环境测试 新建文件 main.go ,写入: package main import "fmt" func main() { fmt.Println("Hello World!") } 执行 go run main.go ,将输出: $

  • Go语言中io包核心接口示例详解

    目录 前言 Reader Writer Closer Seeker 组合接口 总结 前言 IO 操作是我们在编程中不可避免会遇到的,例如读写文件,Go语言的 io 包中提供了相关的接口,定义了相应的规范,不同的数据类型可以根据规范去实现相应的方法,提供更加丰富的功能. Go 语言提倡小接口 + 接口组合的方式,来扩展程序的行为以及增加程序的灵活性.io代码包恰恰就可以作为这样的一个标杆,它可以成为我们运用这种技巧时的一个参考标准.io包中包含了大量接口,本篇文章我们就先来学习四个核心接口以及对应

  • C语言中static的使用方法实例详解

    目录 前言 一.static修饰变量 1.修饰局部变量 2.修饰全局变量 二.static修饰函数 补充:static的好处是什么? 总结 前言 static关键字不仅可以用来修饰变量,还可以用来修饰函数.在使用static关键字修饰变量时,我们称此变量为静态变量.静态变量的存储方式与全局变量一样,都是静态存储方式.静态变量属于静态存储方式,属于静态存储方式的变量却不一定就是静态变量. 一.static修饰变量 1.修饰局部变量 先看段代码: #include <stdio.h> void t

  • Go语言中map使用和并发安全详解

    目录 1 map使用 1.1 map定义 1.2 map的使用和概念 1.3 map的容量 1.4 map的使用 1.4.1 map的遍历 1.4.2 map的删除和断言 1.5 map的坑 2 并发安全 2.1 不安全原因 2.2 解决方案 总结 1 map使用 1.1 map定义 map是一种无序的集合,对应的key (索引)会对应一个value(值),所以这个结构也称为关联数组或字典. map在其他语言中hash.hash table等 var mapname map[keytype]va

随机推荐