指向const int但仍然修改数据的指针

时间:2016-01-13 08:33:31

标签: c pointers malloc const

#include<stdio.h>
#include<stdlib.h>
int *func(int *);
int main(void)
{
        int i,size;
        const int *arr=func(&size);
        for(i=0;i<size;i++)
        {
                printf("Enter a[%d] : ",i);
                scanf("%d",&arr[i]);
        }

        for(i=0;i<size;i++)
        {
                printf("%d\t",arr[i]);
        }
        return 0;
}
int *func(int *psize)
{
        int *p;
        printf("Enter the size: ");
        scanf("%d",psize);

        p=(int *)malloc(*psize *sizeof(int));
        return p;
}
  

输入尺寸:3

     

输入[0]:1

     

输入[1]:2

     

输入[2]:3

     

1 2 3

  • 这里,在这段代码中,我使用const关键字来修改由&#39; arr&#39;指向的数据。指针。
  • 如果我使用const关键字,为什么它会给我输出?

2 个答案:

答案 0 :(得分:7)

你刚遇到许多案例中的一个,C允许你射击你的脚 - 无论好坏。

关于您的假设的一些一般性评论:const给予编译器的保证。所以必须确保不违反合同。 C没有真正的常数[1]。语义const是一个限定符,它允许编译器进行额外的错误检查。但是这需要编译器知道参数的类型。这对于具有正确原型的函数来说是正确的,但是(通常[2])不适用于具有可变数量的参数(&#34;可变参数函数&#34;)的函数,因为它们的类型不是在编译时给出(并且在运行时没有明确提供)。

scanf("%d",&arr[i]);

您实际上将有问题的(见下文)指针类型传递给scanf。函数本身不检查,但只是期望正确的类型。它不能,因为C在运行时不提供对象的类型。

现代编译器应警告printfscanf的参数类型不匹配。始终启用警告(对于gcc至少使用-Wall -Wextra -Wconversions)并注意它们。

编辑:经过激烈的讨论,我不得不改变主意。由于最初给出的原因,它似乎是未定义的行为[3]:将const int *传递给期望scanf的{​​{1}}。

这是因为int *中的对象malloc在第一次写入(6.5p6)之前没有有效类型。使用funcscanf中发生这种情况。因此,对象的类型为int * - 无int。但是,您通过const进一步访问是有效的。 6.7.3p6只使另一方向的行为不明确(有充分理由)。

只有可变函数才能通过未检测到,因为没有关于函数声明中可用的预期类型的​​信息。像这样的东西:

const int *

这里编译器会生成一个警告。变量函数属于C无法检查限定符正确性的情况(这也包括例如void f(int *p) { *p = 0; } int main(void) { const int *p = ...; f(p); } )。还有更多,有些非常微妙。

此处唯一未定义行为的情况是传递一个不兼容的不同限定指针(6.7.6.1p2)。

Recomendation:启用警告,但不要依赖编译器检测所有缺陷(不仅仅是const-correctness)。如果您需要更加安全,C语言不是正确的语言。有很好的理由存在像Python,Java等高级语言(C ++介于两者之间)。 OTOH在C语言中的开放式结尾允许在需要时在这些语言中很难完成(如果有的话)。总之:了解你的工具。

注意:您不应该投射volatile&amp;的结果。 C中的朋友。malloc没用。它由标准定义为sizeof(char)

[1]由于违反合同是未定义的行为,编译器实际上可以将这些数据存储在只读存储器中。例如,这对于运行代码并直接从ROM读取一些数据的微控制器至关重要。

[2]现代编译器可以为参数类型解析1printf系列的格式字符串,并警告错配。但是,这需要此字符串为字符串文字(不是变量)。这是编译器编写的一种礼节,这些函数被广泛使用。

[3]基本上未定义的行为意味着任何事情都可能发生 - 您的计算机可能会逃跑,可能会出现鼻守护进程,或者它可能会起作用。但所有都不能保证可靠或确定性。所以下次你开始其他事情可能会发生。

答案 1 :(得分:1)

很明显,您已关闭所有编译器警告。

您的程序通过将返回int的函数的结果赋值给const int *来调用未定义的行为。编译器应该告诉你,也许你忽略了它,但从那时起所有的几率都没有了。

将const int *传递给scanf。同样,编译器应该已经警告过你,也许你会忽略它,但是所有的可能性都是关闭的。

const int *不会使对象指向不可修改。它告诉编译器不要让你通过那个指针修改任何东西,这就是全部。 malloc返回的存储区域永远不可修改。