此问题已得到解决here。
建议的duplicate和当前给出的答案没有说明为什么首先给出的示例没有问题。主要是为什么没有推理:
“const int ** is a pointer to const int *
与int*
”
也适用于:
“const int * is a pointer to const int
与int
”
我从不同的角度接近它,希望得到另一种解释。
带有示例的代码。
#include <stdio.h>
void f_a (int const a){
/*
* Can't do:
* a = 3; //error: assignment of read-only parameter ‘a’
*
* Explanation: I can't change the value of a in the scope of the function due to the const
*/
printf("%d\n", a);
}
void f_ptr_a_type1 (int const * ptr_a){
/*
* Can do this:
* ptr_a’ = 0x3;
* which make dereferencig to a impossible.
* printf("%d\n", * ptr_a’); -> segfault
* But const won't forbid it.
*
* Can't do:
* *ptr_a’ = 3; //error: assignment of read-only parameter ‘* ptr_a’
*
* Explanation: I can't change the value of a by pointer dereferencing and addignment due to the int const
*/
}
void f_ptr_a_type2 (int * const ptr_a){
/*
* Can do this:
* *a = 3;
*
* Can't do:
* ptr_a = 3; //error: assignment of read-only parameter ‘ptr_a’
*
* Explanation: I can't change the value because the const is protecting the value of the pointer in the funcion scope
*/
}
void f_ptr_ptr_a (int const ** ptr_ptr_a){
/*
* Can do this:
* ptr_ptr_a = 3;
* * ptr_ptr_a = 0x3;
*
* Can't do:
* ** ptr_ptr_a = 0x3; //error: assignment of read-only parameter ‘**ptr_a’
*
* Explanation: Makes sense. Just follows the pattern from previous functions.
*/
}
int main()
{
int a = 7;
f_a(a);
int * ptr_a = &a;
f_ptr_a_type1(&a);
f_ptr_a_type2(&a);
int ** ptr_ptr_a = &ptr_a;
f_ptr_ptr_a(ptr_ptr_a); //warning: passing argument 1 of ‘f_ptr_ptr_a’ from incompatible pointer type [-Wincompatible-pointer-types]
}
接受的广泛接受的答案是这样的:
int **与const int **不同,你无法安全地施展它
我的问题是为什么功能突然关注?
此处并未抱怨int
不是int const
:
int a = 7;
f_a(a);
此处没有抱怨,因为int *
既不是int const *
也不是int * const
:
int * ptr_a = &a;
f_ptr_a_type1(&a);
f_ptr_a_type2(&a);
但突然间,它开始在双指针案件中抱怨。
使用此术语和示例寻找解释?
为什么函数突然开始担心写入 超出范围的事物的权限?
答案 0 :(得分:8)
从例如转换char *
到const char *
始终是安全的。通过const char *
,无法修改指向的数据,就是这样。
另一方面,从char **
到const char **
的转换 不安全,因此不允许隐式转换。请考虑以下代码,而不是解释它:
void foo(const char **bar)
{
const char *str = "test string";
*bar = str; // perfectly legal
}
int main(void)
{
char *teststr[] = {0};
foo((const char **)teststr);
// now teststr points to a `const char *`!
*teststr[0] = 'x'; // <- attempt to modify read-only memory
// ok in this line, there's no const qualifier on teststr!
}
如果在调用char **
时从const char **
到foo()
的转换是隐含的,那么您将有一种隐含的方式将const
转换出去。
答案 1 :(得分:1)
该语言禁止不安全的转换,即将指针指向const
- 对象转换为指向非const
对象的指针。
它并不关心安全转换,即那些你应用更严格的const
资格而不是传递的东西。例如,如果对象真的可写,但是你将它传递给只需要读取它的函数,就没有任何抱怨的目的。
你的例子显示了后者:
f_ptr_a_type1(&a);
这表示&#39;对const
我认为非int
&#39;
const
视图
f_ptr_a_type2(&a);
这只是说&#39;这里是指向同一个非const int
的指针,你将获取该指针的副本,该指针将在const
内函数体(指针,而不是int
)&#39;
至于错误:
f_ptr_ptr_a(ptr_ptr_a);
这是由某些程序员家伙所说的:引用的类型是不同的,而C / C ++将允许将指针传递给 - const
,其中指针指向非 - const
是预期的,它不会级联&#39;通过多个指针级别的转换,因为这可能是不安全的,因为Felix Palmen已经说明了。
答案 2 :(得分:1)
为什么函数突然开始担心写权限 在她的范围之外的东西?
并非投诉来自功能参数的观点。该参数的行为与预期的一样 函数范围并不受变量在进入函数范围之前发生的事情的影响。
void f_ptr_ptr_a (int const ** ptr_ptr_a){
/*
* Can't do:
* ** ptr_ptr_a = 3; //error: assignment of read-only parameter ‘**ptr_a’
*/
}
int const ** ptr_ptr_a
进入按值复制的功能范围,不允许更改** ptr_ptr_a
。该错误与此无关
一旦它们被价值复制,变量是什么样的。
由于函数调用期间发生隐式转换而产生错误。解析我们得到的电话f_ptr_ptr_a(ptr_ptr_a);
:
int const ** ptr_ptr_x = ptr_ptr_a; //This line causes the warning
f_ptr_ptr_a(ptr_ptr_x);
使用此术语和示例寻找解释?
现在让我们将这个例子剥离为基础。
int main()
{
int a = 3;
int * ptr_a = &a;
int ** ptr_ptr_a = &ptr_a; // I promise here **ptr_ptr_a will always be the same
int const b = 5;
int const * ptr_b = &b;
int const ** ptr_ptr_b = &ptr_b;
ptr_ptr_b = ptr_ptr_a; // Warning here: -Wincompatible-pointer-types-discards-qualifiers
printf("%d\n", ** ptr_ptr_b); // Look at me, I've just changed the value of const ** int.
** ptr_ptr_a = 15;
printf("%d\n", ** ptr_ptr_b); // I did it again.
}
由于隐式转换,编译器警告我们。
int main()
{
int const a = 3;
int const * ptr_a = &a;
int const ** ptr_ptr_a = &ptr_a; // I promise here **ptr_ptr_a will always be the same
int const b = 5;
int const * ptr_b = &b;
int const ** ptr_ptr_b = &ptr_b;
ptr_ptr_b = ptr_ptr_a;
printf("%d\n", ** ptr_ptr_b); // Look at me, I've just changed the value of const ** int.
// And there were no warnings at all. Har har har har!
}
我可以从这个问题中得出一个结论,从目前的角度来看,它引入了不必要的复杂性。
请务必注意,通过取消引用进行访问与直接访问不同。
我们在这里看到了。 const
限定符实际上正在做它应该做的事情,阻止我们通过解除引用机制更改** ptr_ptr_b
。
当然,我们设法显然改变了只读值,但这只是因为我们要求穷人const
提供更多信息。
来自here
的sheu回答的另一个例子const char c = 'A';
char* ptr;
const char** const_ptr = &ptr; // <-- ILLEGAL, but what if this were legal?
*const_ptr = &c;
*ptr = 'B'; // <- you just assigned to "const char c" above.
printf("%c \n", c);
printf("%c \n", *ptr);
当你说you just assigned to "const char c" above
时,这不是真的,它只是参考抽象失控。
答案 3 :(得分:-1)
让我们把它分解一下:
const int **
是指向const int *
。
int **
是指向int *
。
换句话说,const int **
是指向一件事的指针,而int **
是指向不同内容的指针。