C语言中为什么不能把char**赋给const char**

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

这个问题是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 **.

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

时间: 2024-11-09 06:45:45

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

char*,string和const char*间的转换

//1.char*转string char* c ="abc"; string s(c); //2.const char*转string const char* c_s ="abc"; string s(c_s); //3.string转const char* string s ="abc"; const char* c_s = s.c_str(); //4.string转char* string s="abcde"; con

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

使用c_str()函数 c_str函数的返回值是const char*. c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同. 这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式. 举个栗子: String st = "insert into chuang values ('" + vos[0] + "', '" + vos[1] + &qu

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

最近写代码,遇到很多地方需要判断文件是否存在的.网上的方法也是千奇百怪,“百家争鸣”. fopen方式打开的比较多见,也有其他各种方式判断文件是否存在的,由于其他方法与本文无关,所以不打算提及. 笔者近来使用winapi比较多,于是顺便搜索了msdn,找到了一个函数:PathFileExists BOOL PathFileExists( _In_ LPCTSTR pszPath ); 以下是笔者最初的方法,windows api原则上提供的函数应该是最合理高效的,起码这个方法在windows平台

const char and static const char

The version with const char * will copy data from a read-only location to a variable on the stack. The version with static const char * references the data in the read-only location (no copy is performed). 在函数内部.const char *每次调用函数时,都须要在stack上分配内存,然后将

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

数据库的基本内容前面都已经说得差点儿相同了.接下看看如何在C语言中使用sqlite. 一 接口 sqlite3_open(const char *filename, sqlite3 **ppDb) 打开数据库,假设数据库不存在则新建一个数据库,并打开 sqlite3_close(sqlite3*) 关闭数据库.假设关闭之前还存在没有运行完的语句,将会返回SQLITE_BUSY 二 实例 1 文件夹结构 Projects{ main.c// 代码所在文件 sqlite{// 官网下载下来的sqli

sqlite学习笔记10:C语言中使用sqlite之查询和更新数据

前面说到的 sqlite_exec() 中的第三个参数, SQLite 将为 sql 参数内执行的每个 SELECT 语句中处理的每个记录调用这个回调函数. 本节添加了两个函数,selectFromTable和updateTable. 实例程序如下: #include <stdio.h> #include <stdlib.h> #include "sqlite/sqlite3.h" #define DB_NANE "sqlite/test.db&quo

sqlite学习笔记11:C语言中使用sqlite之删除记录

最后一节,这里记录下如何删除数据. 前面所有的代码都继承在这里了,在Ubuntu14.04和Mac10.9上亲测通过. #include <stdio.h> #include <stdlib.h> #include "sqlite/sqlite3.h" #define DB_NANE "sqlite/test.db" sqlite3 *db = NULL; char* sql = NULL; char *zErrMsg = NULL; con

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

C语言中常用的数据类型主要int, float ,double ,char 等,但在科学运算中复数扮演着重要角色.这里讲下C语言中的复数运算以及如何调用blas,lapack库中的复数函数来进行科学计算. 1.C语言中的复数运算. C语言中若要用的复数,需要包含头文件complex.h,下面看看一些基本的例子 #include <stdio.h> #include"complex.h" int main() { complex a, b, c, d, f; a = 1 +

C语言中容易被忽略的细节(第二篇)

前言:本文的目的是记录C语言中那些容易被忽略的细节.我打算每天抽出一点时间看书整理,坚持下去,今天是第一篇,也许下个月的今天是第二篇,明年的今天又是第几篇呢?--我坚信,好记性不如烂笔头. 第一篇链接:C语言中容易被忽略的细节(第一篇) 1.C语言中只有一维数组,而且数组的大小必须在编译期就作为一个常数确定下来.C语言中数组元素可以是任何对象,也可以是另外一个数组,即数组的数组. 2.C语言允许初始化列表出现多余的逗号.例如:int days[] = {1,2,3,};作用:方便自动化生成代码.