这个问题已在这里得到解决.
建议的副本和当前给出的答案没有解决为什么首先给出的示例没有问题.主要是为什么没有推理:
" 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]
}
Run Code Online (Sandbox Code Playgroud)
被广泛接受的答案是这样的:
int**与const int**不同,你无法安全地投射它
我的问题是为什么功能突然关注?
它没有抱怨这int不是int const:
int a = 7;
f_a(a);
Run Code Online (Sandbox Code Playgroud)
它没有在这里抱怨,因为int *既不是int const *也不是int * const:
int * ptr_a = &a;
f_ptr_a_type1(&a);
f_ptr_a_type2(&a);
Run Code Online (Sandbox Code Playgroud)
但突然间,它开始在双指针案件中抱怨.
使用这个术语和示例寻找解释?
为什么函数突然开始担心对她的范围之外的东西的写权限?
小智 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!
}
Run Code Online (Sandbox Code Playgroud)
如果转换char **到const char **调用时foo()是隐式的,那么你将有一种隐含的转换方法const.
\n\n\n为什么该函数突然开始担心超出其作用范围的内容的写入权限?
\n
并不是说抱怨是从函数参数的角度出发的。该参数将在函数作用域内按预期运行,并且不会受到变量在进入函数作用域之前发生的情况的影响。
\n\nvoid f_ptr_ptr_a (int const ** ptr_ptr_a){\n /*\n * Can\'t do:\n * ** ptr_ptr_a = 3; //error: assignment of read-only parameter \xe2\x80\x98**ptr_a\xe2\x80\x99\n */\n}\nRun Code Online (Sandbox Code Playgroud)\n\nint 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\nf_ptr_ptr_a(ptr_ptr_x);\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n\n正在寻找使用此术语和示例的解释?
\n
现在让我们将示例剥离到最基本的内容。
\n\nint main()\n{\nint a = 3;\nint * ptr_a = &a;\nint ** ptr_ptr_a = &ptr_a; // I promise here **ptr_ptr_a will always be the same\n\n\nint const b = 5;\nint const * ptr_b = &b;\nint const ** ptr_ptr_b = &ptr_b;\n\nptr_ptr_b = ptr_ptr_a; // Warning here: -Wincompatible-pointer-types-discards-qualifiers\nprintf("%d\\n", ** ptr_ptr_b); // Look at me, I\'ve just changed the value of const ** int.\n\n** ptr_ptr_a = 15;\nprintf("%d\\n", ** ptr_ptr_b); // I did it again.\n\n}\nRun Code Online (Sandbox Code Playgroud)\n\n由于隐式转换,编译器警告我们。
\n\nint main()\n{\n int const a = 3;\n int const * ptr_a = &a;\n int const ** ptr_ptr_a = &ptr_a; // I promise here **ptr_ptr_a will always be the same\n\n int const b = 5;\n int const * ptr_b = &b;\n int const ** ptr_ptr_b = &ptr_b;\n\n ptr_ptr_b = ptr_ptr_a;\n printf("%d\\n", ** ptr_ptr_b); // Look at me, I\'ve just changed the value of const ** int.\n // And there were no warnings at all. Har har har har!\n}\nRun Code Online (Sandbox Code Playgroud)\n\n我可以从这个问题中得出一个结论,从目前的角度来看,它带来了不必要的复杂性。
\n\n请始终记住,通过取消引用进行访问与直接访问不同。
\n\n我们在这里看到了。限定符const实际上正在做它应该做的事情,阻止我们** ptr_ptr_b通过解除引用机制进行更改。\n当然,我们显然已经成功地改变了只读值,但这只是因为我们对穷人的要求太多了const。
sheu 的回答的另一个例子来自这里
\n\nconst char c = \'A\';\nchar* ptr;\nconst char** const_ptr = &ptr; // <-- ILLEGAL, but what if this were legal?\n*const_ptr = &c;\n*ptr = \'B\'; // <- you just assigned to "const char c" above.\n\nprintf("%c \\n", c);\nprintf("%c \\n", *ptr);\nRun Code Online (Sandbox Code Playgroud)\n\n当你说you just assigned to "const char c" above这不是真的时,这只是引用抽象失控了。