设置char*const后如何更改其内容(C)

设置char*const后如何更改其内容(C),c,pointers,C,Pointers,我们正在处理一个常量指针, 所以它持有的地址不能改变。 但是引用的内存地址的内容应该是可变的 尽管如此,在尝试这样做时,我还是会遇到编译/分段错误 #include <stdio.h> #include <stdlib.h> int main(void) { char * const c_ptr = "firstValue"; // now c_ptr is a const ptr to an immutable string literal,

我们正在处理一个常量指针, 所以它持有的地址不能改变。 但是引用的内存地址的内容应该是可变的

尽管如此,在尝试这样做时,我还是会遇到编译/分段错误

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    char * const c_ptr = "firstValue"; // now c_ptr is a const ptr to an immutable string literal, 
                                     //we can't change it unless we declare char [] instead 
    printf("%s",c_ptr);

    *c_ptr="hsdsdsd"; // better to use strcpy(c_ptr, "hsdsdsd");   

    printf("%s",c_ptr);
    return 0;
}
main.c:在函数“main”中: main.c:8:8:警告:赋值从指针生成整数而不进行强制转换[默认情况下启用] *c_ptr=hsdsd

分段故障堆芯


首先,C字符串是以null结尾的字符数组,不能分配数组,必须更改数组中的每个元素

此外,通常编译器会将字符串文本(如firstValue)放入只读内存部分,因此您无法更改它,您必须使用字符数组来初始化字符串

char s[] = "firstValue";
const char*const ptr = s;
ptr[0] = 'z';  // change contents pointed by ptr, or:
strncpy(ptr, "abc", 3);

首先,C字符串是以null结尾的字符数组,不能分配数组,必须更改数组中的每个元素

此外,通常编译器会将字符串文本(如firstValue)放入只读内存部分,因此您无法更改它,您必须使用字符数组来初始化字符串

char s[] = "firstValue";
const char*const ptr = s;
ptr[0] = 'z';  // change contents pointed by ptr, or:
strncpy(ptr, "abc", 3);

指针指向的数据可以更改为常量指针,但在使用字符串文字初始化它时不会更改。它们有一个相当奇怪的特性,即具有char*类型,但无法更改

因此,您可以:

char data[10] = "foobar";
char * const ptr = data;

printf("%s\n", ptr);  // prints foobar
*ptr = 'z';
printf("%s\n", ptr);  // prints zoobar

指针指向的数据可以更改为常量指针,但在使用字符串文字初始化它时不会更改。它们有一个相当奇怪的特性,即具有char*类型,但无法更改

因此,您可以:

char data[10] = "foobar";
char * const ptr = data;

printf("%s\n", ptr);  // prints foobar
*ptr = 'z';
printf("%s\n", ptr);  // prints zoobar
char*const c_ptr表示指向常量数据的非常量指针。这意味着您将指针变量本身设置为只读,而不是指向数据的指针变量

如果您执行*c_ptr='a',那么编译器不会阻止它,因为您告诉它指向的数据是读/写的。这在本例中不是真的,它是一个字符串文本,写入它将导致未定义的行为,这就是为什么会发生崩溃

C116.4.5/7

如果程序试图修改这样的数组,则该行为是 未定义

通过将声明更改为const char*c_ptr来修复代码。 或者,const char*const c_ptr

事实证明,这是不可变的,因为如果您现在尝试strcpyc_ptr,str,您将得到无效的指针转换,因为函数需要一个char*

*c_ptr=hsdsd;是无意义的,不会在兼容的C编译器上编译,因为您试图将地址分配给单个char变量,这是不允许的。违反简单赋值规则的约束。

char*const c_ptr表示指向const数据的非const指针。这意味着您将指针变量本身设置为只读,而不是指向数据的指针变量

如果您执行*c_ptr='a',那么编译器不会阻止它,因为您告诉它指向的数据是读/写的。这在本例中不是真的,它是一个字符串文本,写入它将导致未定义的行为,这就是为什么会发生崩溃

C116.4.5/7

如果程序试图修改这样的数组,则该行为是 未定义

通过将声明更改为const char*c_ptr来修复代码。 或者,const char*const c_ptr

事实证明,这是不可变的,因为如果您现在尝试strcpyc_ptr,str,您将得到无效的指针转换,因为函数需要一个char*


*c_ptr=hsdsd;是无意义的,不会在兼容的C编译器上编译,因为您试图将地址分配给单个char变量,这是不允许的。违反简单赋值规则的约束。

请阅读基本的C语言书*c_ptr!=首先,请阅读警告。它正在投射指针->整型->字符。为什么我要改变它指向的位置?这是一个常量指针…如果指针中的地址不能更改,因为指针是常量,并且所说的地址指向只读数据,而您首先使用只读字符串文字,那么您将不会合法地更改任何内容。所以答案是,你不能从这里到达那里。所以你想更改内容,例如*c_ptr='h';,或strcpyc_ptr,hsdsd;。在本例中,这也是非法的,因为c_ptr当前指向字符串文本,并且字符串文本的存储是不可变的。您可以这样做:char c[]=firstvalue;字符*常数c_ptr=c;strcpyc_ptr,hsdsd;。请读一本基本的C语言书*c_ptr!=首先,请阅读警告。它正在投射指针->整型->字符。为什么我要改变它指向的位置?这是一个常量指针…如果指针中的地址不能更改,因为指针是常量,并且所说的地址指向只读数据,而您首先使用只读字符串文字,那么您将不会合法地更改任何内容。所以答案是,你不能从这里到达那里。所以你想更改内容,例如*c_ptr='h';,或strcpyc_ptr,hsdsd;。
在本例中,这也是非法的,因为c_ptr当前指向字符串文本,并且字符串文本的存储是不可变的。您可以这样做:char c[]=firstvalue;字符*常数c_ptr=c;strcpyc_ptr,hsdsd;。仅仅是因为遗留代码的原因,标准没有被更改为const char*类型吗?@AjayBrahmakshatriya不,我不这么认为。@AjayBrahmakshatriya大多数情况下没有更改,因为C委员会非常保守,不愿改进语言。C++改变了它很久以前,它甚至没有遗留问题,甚至遗留代码。这是因为旧的烂遗留代码将使用旧的烂遗留编译器进行编译,而不是使用最新和最符合标准的编译器。因此,标准中的更改对旧代码的影响并不像他们担心的那样大。@Lundin这种更改会级联到其他需要的更改中吗?有什么特别的例子吗?@AjayBrahmakshatriya没有。标准库已经在使用const correction。这将意味着像void print char*str{puts str;}这样草率编写的代码。。。你好;必须重写,因为它不正确。还有一些旧的烂代码,它实际上滥用了字符串文本在MS DOS等旧系统上是可写的这一事实。但是C标准从来没有声称字符串文字是可写的,所以这对C来说应该没有关系。是否仅仅出于遗留代码的原因,该标准没有被更改为使字符串文字为const char*类型?@AjayBrahmakshatriya no,我不这么认为。@AjayBrahmakshatriya大多数情况下没有改变,因为C委员会非常保守,不愿改进语言。C++改变了它很久以前,它甚至没有遗留问题,甚至遗留代码。这是因为旧的烂遗留代码将使用旧的烂遗留编译器进行编译,而不是使用最新和最符合标准的编译器。因此,标准中的更改对旧代码的影响并不像他们担心的那样大。@Lundin这种更改会级联到其他需要的更改中吗?有什么特别的例子吗?@AjayBrahmakshatriya没有。标准库已经在使用const correction。这将意味着像void print char*str{puts str;}这样草率编写的代码。。。你好;必须重写,因为它不正确。还有一些旧的烂代码,它实际上滥用了字符串文本在MS DOS等旧系统上是可写的这一事实。但是C标准从来没有声称字符串文本是可写的,所以这对C来说应该没有关系。只读内存部分是堆栈的一部分吗?。当我们离开不可变字符串文字声明的范围时,它占用的内存是否会再次变成可重用的静态分配内存,或者所有只读数据仅在编译时/编译开始时设置execution@IdanBananiC不需要堆栈概念。字符串文字有静态存储,它们不超出范围。@IdanBanani它不是堆栈的一部分。当函数返回时,它不会弹出,但指针本身在堆栈上并弹出。只读内存部分是堆栈的一部分吗?。当我们离开不可变字符串文字声明的范围时,它占用的内存是否会再次变成可重用的静态分配内存,或者所有只读数据仅在编译时/编译开始时设置execution@IdanBananiC不需要堆栈概念。字符串文字有静态存储,它们不超出范围。@IdanBanani它不是堆栈的一部分。当函数返回时,它不会弹出,但指针本身在堆栈上并弹出。