我已经退出了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)
谢谢!
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开
Run Code Online (Sandbox Code Playgroud)#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags, mode_t mode);[...]
mode参数指定在创建新文件时应用的文件模式位.该参数必须在供给
O_CREAT或O_TMPFILE在指定flags; 如果既未指定也O_CREAT未O_TMPFILE指定,则忽略模式.过程umask以通常的方式修改有效模式:在没有默认值的情况下ACL,创建文件的模式为(mode & ~umask).请注意,此模式仅适用于将来访问新创建的文件;open()创建只读文件的调用可能会返回读/写文件描述符.为模式提供以下符号常量:
S_IRWXU00700user(文件所有者)具有读,写和执行权限
S_IRUSR00400用户具有读取权限
S_IWUSR00200用户具有写入权限
S_IXUSR00100用户具有执行权限[...]
因为你既不使用O_CREATnor O_TMPFILE,所以这个参数将被忽略,你传递的char*是一个mode_t本质上是整数的.因此你的电话应该是:
if((fd = open(argv[i], O_RDONLY, 0)) == -1) {
...
Run Code Online (Sandbox Code Playgroud)