【问题标题】:What is the difference of these array declarations? [duplicate]这些数组声明有什么区别? [复制]
【发布时间】:2013-09-02 21:32:35
【问题描述】:
#include <stdio.h>
#include <string.h>

int main(void){

char s1[30]="abcdefghijklmnopqrstuvwxyz";

printf("%s\n",s1);

printf("%s",memset(s1,'b',7));

getch();

return 0;
}

上面的代码有效,但是当我像这样创建 s1 数组时,

char *s1="abcdefghijklmnopqrstuvwxyz";

它在编译时没有给出任何错误,但在运行时运行失败。

我正在使用 Visual Studio 2012。

你知道为什么吗?

我发现memset的原型是:

 void *memset( void *s, int c, size_t n );

【问题讨论】:

  • 失败??错误是什么?没有打印输出吗?垃圾打印?
  • C_Son38.exe 中 0x0F251CF5 (msvcr110d.dll) 处未处理的异常:0xC0000005:访问冲突写入位置 0x00D15858。 (中断、继续、忽略按钮)
  • 您正在写入内存的只读段。正如答案中已经解释的那样

标签: c memset


【解决方案1】:

char s1[30] 分配一个可写的内存段来存储数组的内容,char *s1="Sisi is an enemy of Egypt."; 没有 - 后者只设置一个指向字符串常量地址的指针,编译器通常会将其放在 read-只是目标代码的一部分。

【讨论】:

  • 是的,如果你添加 const char *s1 = "blah";比指针的描述更相关,如果您传递常量 char 指针而不是 char 指针,它将添加编译错误。
【解决方案2】:

String literals 在“只读数据”部分中获取空间,该部分以只读方式映射到进程空间(因此您无法更改它)。

【讨论】:

    【解决方案3】:
    char s1[30]="abcdefghijklmnopqrstuvwxyz";
    

    这将s1 声明为char 类型的数组,并对其进行初始化。

    char *s1="abcdefghijklmnopqrstuvwxyz";
    

    "abcdefghijklmnopqrstuvwxyz" 放置在内存的只读部分并创建一个指向它的指针。

    但是,通过 memset 修改 s1 会产生 undefined behavior

    【讨论】:

      【解决方案4】:

      一个很好的问题!

      如果你让gcc输出这个程序集,对比一下输出,你就知道答案了,原因如下:

      • char s1[30]="abcdef";
        • 在函数中定义时,会定义一个char数组,s1是数组名。程序将在堆栈中分配内存。
        • 全局定义时,会在程序中定义一个对象,该对象不是只读数据。
      • char* s2 = "abcdef";只定义了一个char点,指向.rodata中存储的一个const char,即程序中的只读数据。

      为使程序高效运行并轻松管理进度,编译器将为给定代码生成不同的部分。常量字符,如char* s2 = "abcdef";printf 格式字符串将存储在.section rodata 部分。被操作系统的加载器加载到主存后,该部分将被标记为只读。这就是为什么当你使用memset修改s2指向的内存时,它会报错Segment fault

      这里有一个解释:Difference between char* and char[]

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-14
        • 2016-05-08
        • 2014-04-10
        • 2020-07-22
        • 1970-01-01
        • 2010-09-18
        • 1970-01-01
        相关资源
        最近更新 更多