这些数组声明有什么区别?

时间:2013-09-02 12:42:24

标签: c memset

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

4 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:4)

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

答案 2 :(得分:2)

char s1[30]="abcdefghijklmnopqrstuvwxyz";

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

char *s1="abcdefghijklmnopqrstuvwxyz";

“abcdefghijklmnopqrstuvwxyz”放在内存的只读部分并指向该内容。

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

答案 3 :(得分:0)

一个非常好的问题!

如果你让gcc输出汇编,并比较输出,你可以找到答案,以下是原因:

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

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

以下是解释:Difference between char* and char[]