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语言中const的作用很强大,它可以修饰变量、数组、指针、函数参数等。
#include<stdio.h>
int main()
{
	const int num = 100;
	num = 20;
	printf("%d\n", num);
}

发现const 修饰的变量,随后试图修改num的值,结果出现红色波浪线,编译器提醒我们:表达式必须是可修改的左值。

所以我们得出结论:const修饰的变量,不能被修改。

const修饰的变量就一定不能被修改吗???

	const int num = 100;
	int *p = &num;
	*p= 20;
	printf("%d\n", num);

运行结果

通过上图我们发现num的值被修改了,通过指针可以间接的修改const修饰的变量。

但是运行时会出现警告:warning C4090: “初始化”: 不同的“const”限定符。

是因为num类型是const修饰,但是p是整型指针变量 ,

类型不同。所以通过下面强转就没警告了。

改进后的代码

    const int num = 100;
	int *p = (int*)&num;
	*p= 20;
	printf("%d\n", num);

总结:const修饰的变量不能被直接修改

1.2 const修饰数组

#include<stdio.h>
int main()
{
	const int array[5] = { 0,1,2,3,4 };
	array[0] = 100;
}

表示const修饰的数组也不能被修改。

通过上面1.1const修饰变量的分析,同理也联想到:指针是否可以修改数组的内容。结果如下:

#include<stdio.h>
int main()
{
	const int array[5] = { 0,1,2,3,4 };
	//array[0] = 100;
	int *p = array;
	*p = 100;
	printf("%d\n", array[0]);
}

不难发现,指针可以修改。和1.1节出现结果一样,同样运行时程序出现了警告:warning C4090: “初始化”: 不同的“const”限定符,同样的警告出现了。

经过强转后:

#include<stdio.h>
int main()
{
	const int array[5] = { 0,1,2,3,4 };
	//array[0] = 100;
	int *p = (int *)array;//array原本的数据类型为const int[5]
	*p = 100;
	printf("%d\n", array[0]);
}

总结:const修饰数组时,其值不能被直接修改

1.3 const修饰指针

此部分分为两种情况去分析:

#include<stdio.h>
int main()
{
	int a = 100;
	const int *p = &a;
	*p = 1000;
	printf("%d\n", a);
}

此时,通过上图容易发现const修饰指针指向的内容一旦修改,就会自动报错,所以*p(指针指向的内容不能被修改),但指针变量p本身是可以被修改的。

#include<stdio.h>
int main()
{
	int a = 100;
	int* const p = &a;//p的数据类型为int *const
	*p = 1000;
	printf("%d\n", a);
}

此时,const修饰的是指针p本身,所以指针本身不能被修改,但是指针所指向的内容*p可被修改

1.4 const修饰函数参数

#include<stdio.h>
int myFunc(const int* p)
{
	*p = *p + 1;
	return *p;
}

const修饰函数参数,对参数起到限定的作用, 通过发现指针也能修改其值。

总结:const修饰函数参数,本质上和修饰变量和指针一样。表示其值不能被直接修改。

2 const对程序的影响

可以发现,在*p下面出现了红色波浪线,让上述的错误提前出现,避免程序在运行时出错。

总结:编译器可以对const修饰的变量进行合理性检查,让错误提前出现。

3 总结

通过这篇博客,我对const修饰变量、数组、指着和函数参数进行了归纳总结。总体来说有几个点需要注意:

const修饰变量,不能被直接修改
const修饰指针指向的内容时(const int * p=&a),指针指向内容(*p)不能被修改,但指针本身(p)可以被修改。
const修饰指针本身时(int * const p =&a),指针指向的内容(*p)可以被修改,但是指针本身(p)不能被修改。
const 修饰字符串 (const *p=“abcd”;)和(const p[]=“abcd”;)这两种情况的分析,前者字符串不能修改,后者字符串可以修改。这    是由C语言使用存储器的方式决定的。

补充内容

char *cards = “JQK”; 的情况下计算机操作的步骤:

计算机做的步骤:

计算机加载字符串字面值:
当计算机把程序载入存储器时,会把所有常数值(如字符串常量"JQK")放到常量存储区,这部分存储器是只读的。

程序在栈上创建cards变量
栈是存储器中计算机用来保存局部变量的部分,局部变量也就是位于函数内部的变量,cards变量就在这个地方。

cards变量设为"JQK"的地址
cards变量将会保存字符串字面值"JQK"的地址。为了防止修改,字符串字面值通常保存在只读存储器中。

计算机试图修改字符串
程序试图修改cards变量指向的字符串中的内容时就会失败,因为字符串是只读的。

char cards[] = “JQK”;的情况下计算机操作的步骤:

计算机加载字符串字面值:
当计算机把程序载入存储器时,会把所有常数值(如字符串常量"JQK")放到常量存储区,这部分存储器是只读的。

程序在栈上新建了一个数组
我们声明了数组,所以程序会创建一个足够大的数组来保存字符串"JQK"

程序初始化数组
除了为数组分配空间,程序还会把字符串字面值"JQK"的内容复制到栈上。

补充内容

char *cards = “JQK”; 的情况下计算机操作的步骤:

计算机做的步骤:

计算机加载字符串字面值:
当计算机把程序载入存储器时,会把所有常数值(如字符串常量"JQK")放到常量存储区,这部分存储器是只读的。

程序在栈上创建cards变量
栈是存储器中计算机用来保存局部变量的部分,局部变量也就是位于函数内部的变量,cards变量就在这个地方。

cards变量设为"JQK"的地址
cards变量将会保存字符串字面值"JQK"的地址。为了防止修改,字符串字面值通常保存在只读存储器中。

计算机试图修改字符串
程序试图修改cards变量指向的字符串中的内容时就会失败,因为字符串是只读的。

char cards[] = “JQK”;的情况下计算机操作的步骤:

计算机加载字符串字面值:
当计算机把程序载入存储器时,会把所有常数值(如字符串常量"JQK")放到常量存储区,这部分存储器是只读的。

程序在栈上新建了一个数组
我们声明了数组,所以程序会创建一个足够大的数组来保存字符串"JQK"

程序初始化数组
除了为数组分配空间,程序还会把字符串字面值"JQK"的内容复制到栈上。

区别:

原来的代码使用了指向只读字符串字面值的指针;而在第二段代码中,用字符串字面值初始化了一个数组,从而得到了这些字母的副本,这样就可以随意修改他们了。

到此这篇关于C语言const关键字的用法详解的文章就介绍到这了,更多相关C语言const内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 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关键字的用法

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

  • C语言详细分析讲解关键字const与volatile的用法

    目录 一.const 只读变量 二.const 全局变量的分歧 三.const 的本质 四.const 修饰函数参数和返回值 五.volatile 解析 六.小结 一.const 只读变量 const 修饰的变量是只读的,本质还是变量 const 修饰的局部变量在栈上分配空间 const 修饰的全局变量在全局数据区分配空间 const 只在编译期有用,在运行期无用 const 修饰的变量不是真的常量,它只是告诉编译器该变量不能出现在赋值符号的左边. 二.const 全局变量的分歧 在现代C语言编

  • C语言与C++中const的用法对比

    目录 一.C语言中的const 二.C++中的const 三.进一步比较C和C++中的const 四.const与宏的区别 五.小结 一.C语言中的const const修饰的变量是只读的,本质还是变量 const 修饰的局部变量在栈上分配空间 const修饰的全局变量在只读存储区分配空间 const只在编译期有用,在运行期无用 C语言中的const使得变量具有只读属性 const将具有全局生命周期的变量存储于只读存储区 const修饰的变量不是真的常量,它只是告诉编译器该变量不能出现在赋值符号

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

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

  • 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语言之strtol函数用法详解

    strtol 函数用法 strtol是一个C语言函数,作用就是将一个字符串转换为长整型long,其函数原型为: long int strtol (const char* str, char** endptr, int base); 下面我们来看下每个参数的意义: str是要转换的字符 enptr是指向第一个不可转换的字符位置的指针 base的基数,表示转换成为几进制的数 两点注意: 当 base 的值为 0 时,默认采用 10 进制转换,但如果遇到 '0x' / '0X' 前置字符则会使用 16

  • MySQL中ESCAPE关键字的用法详解

    MySQL转义 转义即表示转义字符原来的语义,一个转义字符的目的是开始一个字符序列,使得转义字符开头的该字符序列具有不同于该字符序列单独出现时的语义. MySQL中,转义字符以"\"开头,编程中常见的转义字符,在MySQL均是有效的,在此不做赘述和讨论.在此,主要通过"%" 和 "_"来对ESCAPE关键字的作用进行说明. %:匹配任意多个字符. _:匹配单一字符. 如果我们要匹配"%"或者"_"时,就必须

  • C语言 array数组的用法详解

    目录 一维数组的创建与初始化 程序一: 程序二: 程序三 程序四(二维数组 - 二维数组 的 列 绝对不能 省略 ) 二维数组在内存中的存储 程序一 数组作为函数参数,怎么作? 实例:冒泡排序 数组名: 一维数组的创建与初始化 数组是一种相同类型元素的集合 程序一: #include<stdio.h> #include<string.h> int main() { 创建一个数组 int arr1[10];// [常量] 初始化 int arr[10]={1,2,3};不完全初始化,

  • Java super关键字的用法详解

    目录 super关键字的三种用法: 1. super.成员变量 2. super.成员方法 3. super():调用父类中的构造方法 3.1.1 隐式调用父类无参数构造方法super() 3.1.2 显式调用父类有参数构造方法super(id) super关键字作用:在子类内部调用父类对象 基础语法: 1.在类的继承中,当子类继承了父类, 在构造子类的时候,一定要先帮助父类进行构造: 2. 调用super()必须写在子类构造方法的第一行,以保证在执行任何动作前,对象已经完成了初始化,否则编译不

  • Go语言学习之WaitGroup用法详解

    目录 前言 小试牛刀 总览 底层实现 结构体 Add Done Wait 易错点 总结 前言 在前面的文章中,我们使用过 WaitGroup 进行任务编排,Go语言中的 WaitGroup 和 Java 中的 CyclicBarrier.CountDownLatch 非常类似.比如我们有一个主任务在执行,执行到某一点时需要并行执行三个子任务,并且需要等到三个子任务都执行完后,再继续执行主任务.那我们就需要设置一个检查点,使主任务一直阻塞在这,等三个子任务执行完后再放行. 说明:本文中的示例,均是

  • Go语言的type func()用法详解

    目录 一.前置基础 1. go 函数基础 2. 函数签名 二.Go语言的type func()用法 | type func() 自定义函数类型 1. golang通过type定义函数类型 一.前置基础 1. go 函数基础 在Go语言中,函数的基本组成为:关键字func.函数名.参数列表.返回值.函数体和返回语句. func 函数名(参数列表) 返回值类型 {函数体内部} Go语言是强数据类型的语言,参数是要指定类型的不然就报错.func 是函数的声明关键字. 1) 返回值返回值的定义,是可以给

  • python global关键字的用法详解

    最近刚好有朋友遇到个global相关的问题,这里简单学习一下global关键字的用法. 想要更好的了解global关键字,首先要熟悉python的全局变量与局部变量的概念.global关键字的作用是可以申明一个局部变量为全局变量,下面看一下实例 一.变量作用域的说明 这里简单提一下变量作用域的概念,有兴趣的小伙伴,可以查一下相关的博客 1.局部变量 def a(): ## 菊部变量 - ,- local = 1 print(local) ## 全局无法使用,只有自己可用 print(lobal)

  • C语言 while语句的用法详解

    在C语言中,共有三大常用的程序结构: 顺序结构:代码从前往后执行,没有任何"拐弯抹角": 选择结构:也叫分支结构,重点要掌握 if else.switch 以及条件运算符: 循环结构:重复执行同一段代码. 前面讲解了顺序结构和选择结构,本节开始讲解循环结构.所谓循环(Loop),就是重复地执行同一段代码,例如要计算 1+2+3+--+99+100 的值,就要重复进行99次加法运算. while循环 while循环的一般形式为:     while(表达式){         语句块  

随机推荐