const导致不兼容的指针类型。为什么只有双指针?

时间:2017-07-10 12:24:56

标签: c pointers const

此问题已得到解决here

建议的duplicate和当前给出的答案没有说明为什么首先给出的示例没有问题。主要是为什么没有推理:

const int ** is a pointer to const int *int*

不同

也适用于:

const int * is a pointer to const intint

不同

我从不同的角度接近它,希望得到另一种解释。

带有示例的代码。

#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);

但突然间,它开始在双指针案件中抱怨。

  • 使用此术语和示例寻找解释?

  • 为什么函数突然开始担心写入 超出范围的事物的权限?

4 个答案:

答案 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 **是指向不同内容的指针。