这是我在知乎回答的一个问题.

这个问题是C中的一个深坑,首先说结论:

char ** 和 const char ** 是两个不相容(incompatible)的类型,能够理解为不能直接赋值

在C11的6.5.2.2 Function calls中有例如以下内容

Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter.

翻译:每一个实參都应该具有自己的类型,这样它的值就能够赋给相应非全然限定版本号形參类型的对象

也就是说:參数传递的过程和赋值是类似的.

再看6.5.16.1 Simple assignment中的约束条件

Constraints

1 One of the following shall hold:112)

(......省略......)

-- the left operand has atomic, qualified, or unqualified pointer type, and (considering

the type the left operand would have after lvalue conversion) both operands are

pointers to qualified or unqualified versions of compatible types, and the type pointed

to by the left has all the qualifiers of the type pointed to by the right;

(......省略......)

简单来说就是两个操作数都是指向有限定符或无限定符的相容的类型的指针,左边的指针必须有右边指针指向类型的所有限定符时赋值合法

正是由于这条约束的存在,所以能将实參char* 赋给const char*,比方以下这段用于解说的代码:

char *cp;
const char *ccp;
ccp = cp;

左操作数cpp是指向有const限定符的char的指针

右操作数cp是指向无const限定符的char的指针

char和char是相容的类型,左指针具有右指针指向类型的所有限定符(右指针指向的类型没有限定符)

因此这个赋值是合法的.

注意反过来就不行了.

6.5.16.1 Simple assignment中其它约束条件都不能说明char** 赋值给const char ** 是合法的.最有可能证明其合法的是上面写的那个约束条件.

然而这个"最有可能证明"的约束条件并不能证明该赋值是合法的.

首先看6.2.5 Types中的样例

29 EXAMPLE 1 The type designated as ''float *'' has type ''pointer to float''. Its type category is pointer, not a floating type. The const-qualified version of this type is designated as ''float * const'' whereas the type designated as ''const float *'' is
not a qualified type -- its type is ''pointer to const-qualified float'' and is a pointer to a qualified type.

这个样例是说const float * 类型并非一个有限定符的类型,它是一个没有限定符的指针,指向的是有const限定符的float类型数据.也就是说const修饰的是指向的float而不是指针本身.

类似的,char ** 和const char **都是没有限定符的指针.

char ** 指向的是没有限定修饰符的指针char *

const char ** 指向的是没有限定修饰符的指针const char *

可是char * 和const char * 是不相容的,约束条件要求被指向的类型,不管有没有限定符,可是必须是相容的,显然char * 和const char *是两种不同的指针.

虽然char * 和const char * 所指向的类型是相容的,并且能够把前一个指针的值赋给后一个指针,可是这并不能说明这两个指针类型是相容的.

总之,char * 和const char * 不相容,这和那个"最有可能证明"的约束条件相违背,所以没有不论什么约束条件能证明能够把char **的值赋给const char **.

所以编译器会显示那个警告.由于这两个指针根本不是同一类型的指针.

C语言中为什么不能把char**赋给const char**的更多相关文章

  1. const char and static const char

    部分内容摘自:https://blog.csdn.net/ranhui_xia/article/details/32696669 The version with const char * will ...

  2. VS2017中遇到不存在从string到const char*的转换函数的解决方法

    使用c_str()函数 c_str函数的返回值是const char*. c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同. 这是为了与c语言兼容,在c语言中没有stri ...

  3. c语言检测文件是否存在int __cdecl access(const char *, int);

    最近写代码,遇到很多地方需要判断文件是否存在的.网上的方法也是千奇百怪,“百家争鸣”. fopen方式打开的比较多见,也有其他各种方式判断文件是否存在的,由于其他方法与本文无关,所以不打算提及. 笔者 ...

  4. sqlite学习笔记7:C语言中使用sqlite之打开数据库

    数据库的基本内容前面都已经说得差点儿相同了.接下看看如何在C语言中使用sqlite. 一 接口 sqlite3_open(const char *filename, sqlite3 **ppDb) 打 ...

  5. C语言中的指针数组

    C语言中的指针数组是什么,像 char *a[]={"ddd","dsidd","lll"}; 这里讲一下注意如果我们使用了a也就是首元素的 ...

  6. C语言中的数组和指针以及字符串

    数组名同时也是该数组首元素的地址,而指针提供了一种用来使用地址的符号方法,因此指针能够很有效地处理数组. 将一个整数加给指针,这个整数会和指针所指类型的字节数相乘,然后所得的结果会加到初始地址上 da ...

  7. C语言中复数运算及调用blas,lapack中复数函数进行科学计算

    C语言中常用的数据类型主要int, float ,double ,char 等,但在科学运算中复数扮演着重要角色.这里讲下C语言中的复数运算以及如何调用blas,lapack库中的复数函数来进行科学计 ...

  8. C语言中数据类型的取值范围

    C语言中数据类型的取值范围如下:char -128 ~ +127 (1 Byte)short -32767 ~ + 32768 (2 Bytes)unsigned short 0 ~ 65536 (2 ...

  9. C语言和go语言之间的交互 - C语言中使用go语言,使用的go语言又使用了c语言

    一.go语言中使用C语言 go代码中使用C代码,在go语言的函数块中,以注释的方式写入C代码,然后紧跟import “C” 即可在go代码中使用C函数 代码示例: go代码:testC.go 1 pa ...

随机推荐

  1. c语言_常见图片格式判断

    c语言_常见图片格式判断 我想尽各种思路.今天,终于把图片判断搞定了. 在此,我写一下我的思路.希望对那些不想看代码的朋友们有帮助. 常风的的图片格式有:bmp,png,jpg,gif等图片格式. 我 ...

  2. javascript数据类型、初始化

    Javascript数据类型有6种: 数值型数据类型(Number): 字符串(String): 布尔型数据(Boolean): 对象数据(Object): 空(Null): 未定义(Undefine ...

  3. word2vec 入门基础(一)

    一.基本概念 word2vec是Google在2013年开源的一个工具,核心思想是将词表征映 射为对应的实数向量. 目前采用的模型有一下两种 CBOW(Continuous Bag-Of-Words, ...

  4. OC中如何把字典中的数据拼接成url字符串

    在使用objective-c语言开发iOS应用中,会向服务器通过URL请求一些数据,因此对URL的拼接肯定少不了.而在iOS中,我们一般是通过将字典中的数据拼接成我们要请求的URL字符串,那这个是怎么 ...

  5. JSP指令 include 和forward

     包括指令:include     静态包括         <%@include file="要包括的文件路径" %>                 先将所包括 ...

  6. CSS备忘-1

    CSS 可以通过以下方式添加到HTML中: 内联样式- 在HTML元素中使用"style" 属性 内部样式表 -在HTML文档头部 <head> 区域使用<sty ...

  7. IBM WebSphere MQ的C#工具类以及源码(net)

    简单的介绍一下MQ常用的对象 Queue Manager 队列管理器 主要负责管理队列.通道等,类似与Oracle中的Oracle实例的概念,在一台服务器中可以定义多个Queue Manager. Q ...

  8. Mvc5+Entity Framework6 之二----在MVC中用Entity Framework实现基本的CRUD

    目标:创建控制器和视图的代码,实现CRUD(创建,读取,更新,删除)功能 创建一个详细信息页 控制器为Students的Index页生成的代码排除Enrollments属性在外,因为该属性中关联着一个 ...

  9. C/S ASP.NET页面传值汇总

    一. QueryString是一种非常简单的传值方式,他可以将传送的值显示在浏览器的地址栏中.如果是传递一个或多个安全性要求不高或是结构简单的数值时,可以使用这个方法.但是对于传递数组或对象的话,就不 ...

  10. 搜索+剪枝——运筹帷幄 (road.cpp)

    运筹帷幄 (road.cpp) [题目描述] 刘邦军行至迷糊林,见其中瘴气围绕,又有青狼猛虎之兽,难于前行. 已知迷糊林是一个共有n个结点的图,点与点之间共有m条道路相连接,每条路有参数t,c,分别表 ...