@

开始回顾C基础知识。C中使用指针是很危险的事情,一个不慎就会造成程序崩溃,因此对于传入函数的参数进行保护就是必须的了,特别是针对数组。

const关键字

const关键字用于将一个变量声明为只读,也就是常量,无法被修改。

const int constant = 10;//声明constant为常量的同时对它进行初始化赋值
int const constant = 10;//也可以将const放在int后面

const修饰数组

使用const来修饰数组声明了一个数组常量,是对数组里面数据的一种保护,当试图修改一个被const修饰的数组内容时,编译时会产生错误。

const int days[5] = {1,2,3,4,5};//int const days[5]一样
//想要把days[0]重新赋值为6,报错
days[0] = 6;
//Cannot assign to variable 'days' with const-qualified type 'const int [5]'

但是我们有一点要注意,是不是days里面的数据一定无法修改呢?我们做个试验:

 	const int days[5] = {1,2,3,4,5};
int * p = days;
*p = 6;
for (int i = 0; i < 5; ++i) {
printf("%d\n",*p++);
}

结果:

6
2
3
4
5

所以虽然数组days被声明为只读的,但是如果通过指针去访问数组,还是可以改变数组元素的,这也就是指针的强大与易错。

const修饰指针

const修饰指针创建了一个指针常量,但是const的位置会导致这个指针常量有不同的含义。

	int days[5] = {1,2,3,4,5};
const int *p1;//const修饰的是int,表示p1指向的变量值不可改变,指针本身可以改变
//p1指向的值为常量
p1 = days;
*p1 = 6;//报错,不允许修改指针指向的值。Read-only variable is not assignable
p1[1] = 7;//报错,不允许修改
days[0] = 6;//允许,days不是常量
p1++;//合法,p1这个指针本身是可以修改的,这里让其指向days的第二个元素 int * const p2 = days;//const修饰的是p2,表示p2这个指针本身是无法修改的,但是其指向的值是可以修改的
//这里p2本身是常量,因此声明p2的时候就要初始化,否则后面无法对p2进行初始化
*p2 = 10;//合法,p2指向的值可以修改
p2 = &days[1];//不合法,报错,p2是常量,因此想要修改指针的值使其指向days[1]不合法。
//Cannot assign to variable 'p2' with const-qualified type 'int *const'

上面就说明了两种const修饰的指针常量的区别。这里有以下几点需要注意:

  • 将常量或非常量数据的地址赋值给指向常量的的指针是合法的。但是非常量数据的地址可以赋值给普通指针,而常量数据的地址就不可以赋值给普通指针。这样做只会提示不合法,却仍然可以这样操作,但最好不要这样做,数据既然数据已经被声明为常量,那么就不要试图去修改,因此指针不要这样赋值,以免修改了倡廉打个值,就像上面const修饰数组里面说的。
	double un_locked[3] = {1.2,2.3,3.1};
const double locked[3] = {1.0,2.0,3.0};
const double * p3 = locked;//合法
p3 = un_locked;//合法
p3 = &un_locked[1];//合法
double *p4;
p4 = un_locked;//合法
p4 = locked;//非法,但是程序可以运行,
  • const用来修饰形式参量。C语言的传参特性这里不提,如果函数并不想修改本来的数据,一般会把相应的形式参量修饰为const的,告诉编译器这里要把传进来的指针地址当做常量来对待,不允许修改,当函数体内部想要做修改时,编译器会报错。需要注意的是并不要求传进来的参数是常量,而是编译器这样做保证函数执行过程中对源数据不会修改而已。
void foo(const int *bar);
//foo接受一个指针,并把这个指针当做常量对待
void foo1(int *bar);
//foo1声明接受一个普通指针
int main() {
int test1[2] = {1,2};
const int test2[2] = {3,4}; foo(test1);//合法
foo(test2);//合法
foo1(test1);//合法
foo1(test2);//不合法,不提倡这样做。Passing 'const int [2]' to parameter of type 'int *' discards qualifiers
} void foo(const int *bar){
}
void foo1(int *bar){
}

用两个const修饰指针

用两个const修饰符修饰指针会使得这个指针本身既不可以更改所指向的地址,也无法修改所指向的数据。

 	int days[3] = {1,2,3};
const int * const p = days; p = &days[2];//不合法
*p = 6;//不合法

const修饰函数本身我还没用过,碰到了再来补上。

const关键字与数组、指针的更多相关文章

  1. C++ 二级指针与 const 关键字

    可用七种不同的方式将 const 关键字用于二级指针,如下所示: //方式一:所指一级指针指向的数据为常量,以下几种为等效表示 const int ** pptc; //方式一 int const * ...

  2. const关键字到底该怎么用

    原文地址:https://www.yanbinghu.com/2019/01/28/7442.html 前言 我们都知道使用const关键字限定一个变量为只读,但它是真正意义上的只读吗?实际中又该如何 ...

  3. C语言学习及应用笔记之三:C语言const关键字及其使用

    在C语言程序中,const关键字也是经常会用到的一个关键字,那么使用const关键字的目的是什么呢?事实上,在程序中使用const关键字的主要目的就是为了向使用者传递设计者的一些意图. 事实上,无论我 ...

  4. [C++ Primer Plus] 第7章、函数(一)程序清单——递归,指针和const,指针数组和数组指针,函数和二维数组

    程序清单7.6 #include<iostream> using namespace std; ; int sum_arr(int arr[], int n);//函数声明 void ma ...

  5. 数组/指针/const/字符串常量的使用传值问题

    #include<stdio.h> #include<string.h> int main() { ] = "abcd"; //常指针a指向字符串常量&qu ...

  6. int main (int argc, const char * argv[0]) 中参数的含义;指针数组和数组指针

    恩,有的编译器初始化时候会产生这样的参数 argc是命令行总的参数个数,argv[]是argc个参数,其中第0个参数是程序的全名 1. 几种C++ 常见的参数种类 int main(void); in ...

  7. 实习第一个月总结(const关键字、条件编译、volatile关键字、#和##的作用、函数指针)

    C语言中const关键字的作用: 修饰局部变量或者全局变量,表示变量n的值不能被改变了 修饰指针,分为常量指针与指针常量,也可以两者结合 常量指针指向的值不能改变,但是这并不是意味着指针本身不能改变, ...

  8. C++中const关键字的使用总结

    C++中使用const关键字来修饰常量,下面从两个方面总结:变量和成员函数. 变量:const可以修饰普通变量.指针(数组)和结构体. 1.const修饰普通变量是最简单的情形.这样的用法多为在程序中 ...

  9. (转) C/C++中const关键字详解

    文章转自  http://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777416.html 为什么使用const?采用符号常量写出的代码更容易维 ...

随机推荐

  1. 易百教程人工智能python修正-人工智能监督学习(分类)

    分类技术或模型试图从观测值中得出一些结论. 在分类问题中,我们有分类输出,如“黑色”或“白色”或“教学”和“非教学”. 在构建分类模型时,需要有包含数据点和相应标签的训练数据集. 例如,如果想检查图像 ...

  2. js 的七大原则--单一原则、开闭原则、替换原则(一)

    一.前言: js 的七大设计原则: 1.单一原则 2.开闭原则 3.里氏替换原则 4.依赖倒转原则 5.接口隔离原则 6.合成复用原则 7.迪米尔法则 二.单一原则 1.定义:单一原则就是一个对象或者 ...

  3. React Native 开发豆瓣评分(四)集中管理 fetch 数据请求

    豆瓣评分的API接口 接口是从网上查找的,看样子应该是微信小程序里面扣出来的(ua 里面有 wechatdevtools) 接口都需要设置apiKey(054022eaeae0b00e0fc068c0 ...

  4. 造成thrift 编译构建项目失败的原因之一:thrift环境变量没设置

    由于重装了系统和IDEA工具,打开原项目时使用install 构建使用thrift 协议的项目时失败.下面是说说我遇到的问题 看下图,就是构建时控制台输出的日志,因为是乱码,当时没重视,就先去检查po ...

  5. 【JUC】4.Synchronized与ReentrantLock对比

    与synchronized相同,ReentrantLock也是一种互斥锁: synchronized与ReentrantLock的对比: 都是可重入锁 可以再次获取自己的内部锁,即:一个线程获取某对象 ...

  6. 实现Feign请求拦截器,对请求header等参数进行转发

    参考:Feign传递请求头信息(Finchley版本) 问题:通过Feign远程调用服务,无法传递header参数. 解决方式:实现RequestInterceptor接口(对所有的Feign请求进行 ...

  7. 解决通过vue-router打开tab页,下次进入还是上次history缓存的界面状态的问题

    一.问题描述: 1. 跳转模式:界面A-->界面B(界面A中通过 this.$router.push({name:'组件B名称', params: {参数}}) 通过打开新tab页的方式打开界面 ...

  8. python面试总结2(函数常考题和异常处理)

    python函数常考题 可变类型为参数 不能类型为参数 python如何传递参数 传递值还是引用呢?都不是.唯一支持的参数传递是共享穿参 Call by Object(Call by Object R ...

  9. 虚拟机搭建IKUAI软路由

    1.登录爱快软路由的官网下载镜像(支持ISO ,GHO),这里采用iso安装 2.选择好后开机(选择数字编号1,回车) 3.输入“y”回车,程序自动安装 4.安装成功后如图 5.设置IP 6.绑定网卡 ...

  10. MySQL 5.7主从复制实战篇

    MySQL 5.7主从复制实战篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.安装MySQL数据库并启动 1>.在MySQL官方下载相应的安装包(https://dev ...