使用read()和write()进行分段错误(Core Dumped)

Kyl*_*e J 1 c

我已经退出了C近两年的编程,并且最近在学校使用write()和read()获得了一项任务.

代码中的某个地方我收到了Segmentation Fault错误,可能在filecopy函数上是我付钱的地方.我正在尝试GDB,但我没有使用过,因为上次我用C语言编程所以我转到这里.

代码.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char *argv[]) {

void filecopy(int infd, int outfd);

int fd = -1;
char *prog = argv[0];
if(argc == 1) 
    filecopy(STDIN_FILENO, STDOUT_FILENO);
else 
    while(--argc > 0) {
        if((fd = open(*++argv, O_RDONLY, "rb")) == -1) {
            // we don't have fprintf... but we have sprintf =]
            char tmp[30];
            sprintf(tmp, "%s: can't open %s\0", prog, *argv);
            write(STDOUT_FILENO, &tmp, sizeof(tmp));    
            exit(-1);
        } else {
            filecopy(fd, STDOUT_FILENO); 
            close(fd);  
        }
    }
exit(0);

}

void filecopy(int infd, int outfd) {
    // char *buf[1]; <-- causes unreadable characters outputted by write
    char *buf;
    while(read(infd, buf, 1) != -1) 
        write(outfd, buf, sizeof(buf));
}
Run Code Online (Sandbox Code Playgroud)

输入/输出 在此输入图像描述

谢谢!

Pab*_*blo 5

char *buf; 是一个未初始化的指针,通过该指针写入数据是未定义的行为.

char buf[1024];

ssize_t len;

while((len = read(infd, buf, sizeof buf)) != -1)
    write(outfd, buf, len);
Run Code Online (Sandbox Code Playgroud)

会是对的.

请注意,这char *buf[1];是一个数组(维度为1)pointers,与chars 数组不同.使用你需要做的 read(infd, buf[0], somelength),但这里再次buf[0]是一个未初始化的指针,你会遇到同样的问题.这就是为什么声明一个char1024 的数组(你可以选择另一个大小)是正确的做法.

也在主要使用strlen(tmp)而不是sizeof(tmp)

char tmp[30];
sprintf(tmp, "%s: can't open %s\0", prog, *argv);
write(STDOUT_FILENO, &tmp, strlen(tmp));
Run Code Online (Sandbox Code Playgroud)

strlen返回字符串的长度,可能小于29,如果你使用,sizeof(tmp)你可能会在字符串末尾写垃圾.另请注意,对于整个字符串,0可能太小,我会使用更大的数字或使用snprintf以下内容构造字符串:

snprintf(tmp, sizeof tmp, "%s: can't open %s\0", prog, *argv);
Run Code Online (Sandbox Code Playgroud)

会更安全.

最后一件事:

while(--argc > 0)
    if((fd = open(*++argv, O_RDONLY, "rb")) == -1) {
        ...
Run Code Online (Sandbox Code Playgroud)

虽然这是正确的,但我觉得这段代码很难阅读.如果您这样做,那么读起来会简单得多:

for(int i = 1; i < argc; ++i)
    if((fd = open(argv[i], O_RDONLY, "rb")) == -1) {
        ...
Run Code Online (Sandbox Code Playgroud)

我从来没有见过open被称为"rb"模式.我的手册页说:

男人2开

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags, mode_t mode);
Run Code Online (Sandbox Code Playgroud)

[...]

mode参数指定在创建新文件时应用的文件模式位.该参数必须在供给 O_CREATO_TMPFILE在指定flags; 如果既未指定也O_CREATO_TMPFILE指定,则忽略模式.过程umask以通常的方式修改有效模式:在没有默认值的情况下ACL,创建文件的模式为 (mode & ~umask).请注意,此模式仅适用于将来访问新创建的文件; open()创建只读文件的调用可能会返回读/写文件描述符.

为模式提供以下符号常量:

S_IRWXU 00700 user(文件所有者)具有读,写和执行权限

S_IRUSR 00400 用户具有读取权限

S_IWUSR 00200 用户具有写入权限

S_IXUSR 00100 用户具有执行权限

[...]

因为你既不使用O_CREATnor O_TMPFILE,所以这个参数将被忽略,你传递的char*是一个mode_t本质上是整数的.因此你的电话应该是:

    if((fd = open(argv[i], O_RDONLY, 0)) == -1) {
        ...
Run Code Online (Sandbox Code Playgroud)