LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
楼主: macarthor

write()出现段错误

[复制链接]
发表于 2005-7-11 16:49:57 | 显示全部楼层

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <fcntl.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <errno.h>
  7. #include <unistd.h>
  8. #include <dirent.h>
  9. #include <string.h>

  10. int main(void) {
  11.         int fd;
  12.         char *temp;

  13.         fd = open("tttt.txt", O_CREAT | O_WRONLY | O_APPEND);

  14.         temp = "\nhehe\n";
  15.         write(fd, temp, strlen(temp));
  16.         close(fd);
  17.         return 0;
  18. }

复制代码

$ gcc -v
Reading specs from D:/work/program/MinGW/bin/../lib/gcc/mingw32/3.4.2/specs
Configured with: ../gcc/configure --with-gcc --with-gnu-ld --with-gnu-as --host=mingw32 --target=mingw32 --prefix=/mingw --enable-threads --disable-nls --enable-languages=c,c++,f77,ada,objc,java --disable-win32-registry --disable-shared --enable-sjlj-exceptions --enable-libgcj --disable-java-awt --without-x --enable-java-gc=boehm --disable-libgcj-debug --enable-interpreter --enable-hash-synchronization --enable-libstdcxx-debug
Thread model: win32
gcc version 3.4.2 (mingw-special)

$ cat -A tttt.txt
^M$
hehe^M$

没有问题.
回复 支持 反对

使用道具 举报

发表于 2005-7-11 16:58:42 | 显示全部楼层
Post by macarthor
虽然"we are champion\n"是常量,但是它在等号右边啊

而且下边改变的char *temp不是const型的啊


kj501说的对, temp虽然可以修改,但是temp指向的内存不能修改。
回复 支持 反对

使用道具 举报

发表于 2005-7-11 17:43:57 | 显示全部楼层
Post by macarthor
问题所在找到了

  1. char *temp;
  2. temp = "we are champion\n";
  3. memset(temp, 0, strlen(temp));
复制代码

就是段错误

而改为下边的就过去了

  1. char temp[100];
  2. temp = "we are champion\n";
  3. memset(temp, 0, strlen(char) * 256);
复制代码


为什么呢?

我觉得char* temp = "something"得到的内存区性质类型和char temp[100]的是不一样的。
第二个例子中, char temp[100]得到的是一块地址,temp = "we are champion\n";是在运行时赋值。
而char* temp = "something"是在编译时就赋值,有点像汇编的立即数寻址(数据就在代码段里了)。
个人之见,不是很确定,高人订正。
回复 支持 反对

使用道具 举报

发表于 2005-7-11 19:21:57 | 显示全部楼层
char *temp = "abcde",这个字符串"abcde"是放在代码段里的,temp只是一个指针指向这个地址。代码段一般被设为只读属性(除非自己改操作系统),不可以修改,一旦对其中数据进行修改,CPU会产生一个异常(至少x86的CPU会产生这个异常)——非法内存访问,被操作系统捕捉后就给了你这个Segmentation Fault,算是严重错误。
char temp[100] = "abcde",这个字符串是放在数据段(堆栈、全局堆或somewhere else)里的,数据段是可写的,当然可以随便改。这里的temp是个符号地址,不是个指针变量。
建议看看x86的保护模式的原理和简单的汇编知识,一般了解就可以了。
回复 支持 反对

使用道具 举报

发表于 2005-7-11 19:44:42 | 显示全部楼层
c语言中的变量,归根结底可以分为以下几种:
存放在堆栈中的自动变量和函数参数;
来源于自由堆的动态分配(使用malloc,free对)以及静态分配的比如说一些常量.如果你研究过win32的PE格式文件的话,就可以知道程序从逻辑上分为初始化的数据段,未初始化的数据段,代码段,堆栈段.定义在函数内部的变量为局部变量,一般在堆栈上分配;而全局变量和常量则在自由堆中分配.
char *temp;
temp = "we are champion\n";
memset(temp, 0, strlen(temp));
如果将上一段代码放在一个函数内的话,在程序的全局数据段中有一个长度若干的连续存储区存放了字符串"we are champion\n",而char* tem则定义了在堆栈中通过调整堆栈顶部指针ESP的值来分配了一个四字节的存放地址的变量,赋值语句temp="we are cha.."调用的结果是将temp指向了一个常量存储区,当调用memset修改temp所指向存储区时,就会发生溢出错误.
第二段应该改成
char temp[100]  = "we are champion\n";
或者是
char temp[100];
strcpy(temp, "we are champion\n");

memset(temp, 0, strlen(char) * 256);
第二部分,当char temp[100]是定义为全局字符数组时,内存的布局就是存在长度是100个字节未初始化的数据区,还有为"we are cha..."分配的初始化的数据区,而memset(temp, 0, strlen(char)*256)这部分我认为是错误的,编程时不应该对不是由你分配的存储空间进行写入操作,因此应该改成memset(temp, 0, strlen(temp) * size_of(char))来讲一片存储区全部初始化成0,使用256的话可能出现段异常.
可执行程序的逻辑结构可以通过编译器将c代码转换成汇编语言文件来理解.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-7-11 22:14:40 | 显示全部楼层
没想到一个看似简单的问题也有很大学问啊

真是学了不少东西,谢谢大家

more ideas are welcome~~~~~~~~~

另外,我有若干数据需要分批写入test.txt。原来想使用char *temp赋值,用完再memset为0供下次写入做临时变量。有什么好想法吗?
回复 支持 反对

使用道具 举报

发表于 2005-7-11 22:19:42 | 显示全部楼层
Post by macarthor
没想到一个看似简单的问题也有很大学问啊

真是学了不少东西,谢谢大家

more ideas are welcome~~~~~~~~~

另外,我有若干数据需要分批写入test.txt。原来想使用char *temp赋值,用完再memset为0供下次写入做临时变量。有什么好想法吗?

用char temp[INDEX] 作缓冲,我觉得。
回复 支持 反对

使用道具 举报

发表于 2005-7-11 22:43:09 | 显示全部楼层
呵呵,看来大家的发言都挺积极!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-7-11 23:07:28 | 显示全部楼层
每次写入的数据都不等长。虽然可以设置INDEX足够大,也不好吧

一方面,万一出现数据多于INDEX个,还是不够用

另一方面,多数情况会造成内存浪费
回复 支持 反对

使用道具 举报

发表于 2005-7-12 09:39:25 | 显示全部楼层
用堆内存不行吗?
char *temp = (char *)malloc(size);
/*use it*/
free(temp);

也可以配置 realloc使用.堆内存要比 char temp[N] 这种栈内存空间大得多.
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表