字符数组和字符指针在这段代码中的区别

软件和网站开发以及相关技术探讨
回复
noreasona
帖子: 26
注册时间: 2010-04-01 17:23

字符数组和字符指针在这段代码中的区别

#1

帖子 noreasona » 2010-10-14 13:10

#include <stdio.h>
#include <string.h>

int main()
{
char s[] = "hello! let us study c.";
//char * s = "hello! let us study c.";
memset(s, 'G', 6);
printf("%s\n", s);

return 0;
}

如代码所示,若采用注释掉的那一句char * s,则运行的时候会出现 段错误。而采用char s[]则运行无误,请问这两者有什么区别呢?

memset的原型如下:
#include<string.h>
void * memset(void *s, int c, size_t n);

谢谢!
头像
linjiework
帖子: 240
注册时间: 2009-07-07 19:52

Re: 字符数组和字符指针在这段代码中的区别

#2

帖子 linjiework » 2010-10-14 19:54

我的水平有限,尝试着解释一下这个问题,如果有错误,欢迎大家指正。

char * s = "hello! let us study c.";
这时,s 是一个指针,它指向的是一个静态数据。
一个可执行程序,它是包含数据段和代码段的。对于程序里用到的静态数据(如:char * s = "hello! let us study c.";),在编译后,会把数据存储在数据段里,而这个数据是不可更改的。

char s[] = "hello! let us study c.";
这时,s 是一个数组。程序在内存分配一个数组空间,并将数据存进去,这时,你可以把它当做一个数组来使用。所以用 memset 是不会崩溃的。
阿呆 : 天下第一呆!
头像
Kandu
帖子: 108
注册时间: 2008-12-24 12:02
系统: Gentoo
联系:

Re: 字符数组和字符指针在这段代码中的区别

#3

帖子 Kandu » 2010-10-15 16:03

c 語言標準就是如此。通過聲明指針是初始化的數據和通過聲明數組初始化的數據是放在兩個不同屬性的段中的。通過聲明數組初始化的數據放入可寫段,而通過聲明指針的初始化數據放入不可寫的段。你去寫,cpu就異常,然後就報段保護錯誤。
另外,就數組和指針本身來說,本來就是兩回事麼。:-)
noreasona
帖子: 26
注册时间: 2010-04-01 17:23

Re: 字符数组和字符指针在这段代码中的区别

#4

帖子 noreasona » 2010-10-15 21:22

Kandu 写了:c 語言標準就是如此。通過聲明指針是初始化的數據和通過聲明數組初始化的數據是放在兩個不同屬性的段中的。通過聲明數組初始化的數據放入可寫段,而通過聲明指針的初始化數據放入不可寫的段。你去寫,cpu就異常,然後就報段保護錯誤。
另外,就數組和指針本身來說,本來就是兩回事麼。:-)

嗯,你说的有道理。不过不清楚具体是怎么分配内存的。
头像
Kandu
帖子: 108
注册时间: 2008-12-24 12:02
系统: Gentoo
联系:

Re: 字符数组和字符指针在这段代码中的区别

#5

帖子 Kandu » 2010-10-16 12:32

分配方式如下,例如:

代码: 全选

char *str_a="show";
char str_b[]="me";

int main(void)
{
  char *str_c= "the";
  char str_d[]= "money";
  return 0;
}
執行
gcc -S test.c
得到

代码: 全选

    .file    "test.c"
.globl str_a
    .section    .rodata        /*使得下面的數據存入只讀數據段*/
.LC0:
    .string    "show"            /*於是 "show" 就被存入只讀段了*/
    .data                /*使得下面的數據存入普通數據段*/
    .align 4
    .type    str_a, @object
    .size    str_a, 4
str_a:
    .long    .LC0
.globl str_b
    .type    str_b, @object
    .size    str_b, 3
str_b:
    .string    "me"            /*於是 "me" 就被存入普通數據段了*/
    .section    .rodata        /*使得下面的數據存入只讀數據段*/
.LC1:
    .string    "the"            /*於是 "the" 就被存入只讀數據段*/
    .text
.globl main
    .type    main, @function
main:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $16, %esp
    movl    $.LC1, -4(%ebp)
    movl    $1701736301, -10(%ebp)    /* "money" 去哪裡了?“錢沒了呀”。因為它在函數內部聲明,所以被分配到棧,因為棧頂部的具體位置是在函數被調用後才能得知(通過 esp),所以需要通過指令來初始化這個數據。從上面的 movl %esp, %ebp 可知,此時 %ebp指向棧,所以直接通過 %ebp 向棧寫入 money 的數值。*/
    /*$1701736301 的值就是 "mone",去對照下 ascii 表*/
    movw    $121, -6(%ebp)        /*然後寫入 'y' 加上一個0,因為使用 movw,為雙字節,$121 的高字節部分就是0,所以字符串寫入完成。一個正常的操作系統在給棧段的屬性都是可寫的。*/
    movl    $0, %eax
    leave
    ret
    .size    main, .-main
    .ident    "GCC: (GNU) 4.5.1"
    .section    .note.GNU-stack,"",@progbits

/*另外的說明,為何 "the" 這個字符串不存入棧?它是通過聲明指針初始化的,所以得存入只讀數據段*/
上次由 Kandu 在 2011-11-06 10:04,总共编辑 2 次。
头像
Crazier
帖子: 1051
注册时间: 2007-09-23 17:06
联系:

Re: 字符数组和字符指针在这段代码中的区别

#6

帖子 Crazier » 2010-10-17 17:29

好强悍,回来研究研究。。。。。。。。。。
回复