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

 更新时间:2022年08月18日 11:08:30   作者:Love coldplay  
今天探讨const,首先来说是将变量常量化。为什么要将变量常量化,原因有诸多好处有诸多。比如可以使数据更加安全不会被修改

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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • c++ qsort 与sort 对结构体排序实例代码

    c++ qsort 与sort 对结构体排序实例代码

    这篇文章主要介绍了c++ qsort 与sort 对结构体排序实例代码,帮助大家更好的理解和学习c++,感兴趣的朋友可以了解下
    2020-11-11
  • C++实现路口交通灯模拟系统

    C++实现路口交通灯模拟系统

    这篇文章主要为大家详细介绍了C++实现路口交通灯模拟系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • 基于C语言实现简单的走迷宫游戏

    基于C语言实现简单的走迷宫游戏

    这篇文章主要介绍了基于C语言实现简单的走迷宫游戏,用到双向队列,方便在运行完毕后输出经过的点,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-04-04
  • 简单掌握Linux系统中fork()函数创建子进程的用法

    简单掌握Linux系统中fork()函数创建子进程的用法

    fork()函数只能在类Unix系统下使用,因为需要引入unistd头文件,这里我们就来简单掌握Linux系统中fork()函数创建子进程的用法,需要的朋友可以参考下
    2016-06-06
  • C++ find函数及用法小结

    C++ find函数及用法小结

    string类的find()函数用于在字符串中查找字符或子串,返回第一个匹配的位置,C++中的find()函数有多种用法,本文通过实例代码给大家详细讲解,感兴趣的朋友一起看看吧
    2023-12-12
  • C语言中static的使用方法实例详解

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

    static一般用于修饰局部变量,全局变量,函数,下面这篇文章主要给大家介绍了关于C语言中static用法的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • C语言printf详细解析

    C语言printf详细解析

    C中格式字符串printf()的一般形式为: %[标志][输出最小宽度][.精度][长度]类型, 其中方括号[]中的项为可选项。各项的意义介绍如下
    2013-09-09
  • C++实现LeetCode(24.成对交换节点)

    C++实现LeetCode(24.成对交换节点)

    这篇文章主要介绍了C++实现LeetCode(24.成对交换节点),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • 深入理解QT多线程编程

    深入理解QT多线程编程

    本文主要介绍了QT多线程编程的深入理解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-06-06
  • C语言大小端字节序存储模式深入解读

    C语言大小端字节序存储模式深入解读

    我们知道,当编译器执行 “创建变量” 这一代码时,会在内存中开辟空间相应的空间来存储变量值。而对于整型变量而言,变量值又是以二进制补码的形式存放的
    2022-09-09

最新评论