【问题标题】:Segmentation fault while system() in CC中的system()时出现分段错误
【发布时间】:2019-05-19 01:53:28
【问题描述】:

我想使用linux的“base64”脚本对数据进行编码并用C语言获取。 当我尝试编译时

char a[200];
strcpy(a, "Hello");
printf("%s", a);

我得到了输出

Hello

现在每当我尝试代码时

char a[200];
strcpy(a, system("echo Hello | base64"));
printf("%s", a);

我得到了输出

aGVsbG8K
Segmentation fault

即使我删除“printf”语句,我也得到相同的结果

aGVsbG8K
Segmentation fault

我想保存输出的值

system("echo Hello | base64")

在“a”中而不显示它。请帮忙

【问题讨论】:

  • 帮自己一个忙:阅读man gcc,尤其是关于警告的部分。如果你打开了这些,编译器会告诉你system() 的返回值和strcpy() 的输入之间有一些可疑的地方。

标签: c terminal segmentation-fault


【解决方案1】:

如果您阅读 system 的文档,您会发现它没有返回字符串 - 它被定义为:

int system(const char *command);

返回值是命令的返回状态,如果有错误,返回-1。您无法使用 system 获得输出 - 您运行的命令的输出将直接进入标准输出。

要从另一个命令获取输出,您可以使用 popen 之类的内容。

FILE *myfile;
char buffer[1024];

myfile=popen("echo Hello | base64","r");
if(myfile)
  {
  while(fgets(buffer,1024,myfile))
    {
    printf("%s",buffer);
    }

  pclose(myfile);
  }

【讨论】:

    【解决方案2】:

    这里

    strcpy(a, system("echo Hello | base64"));
    

    system() 不会将其结果存储到数组 a 中,因为 system() 工作是执行参数中提供的 command 并在控制台上打印它,即 stdout 缓冲区。来自system的手册页

    system() 通过调用执行command 中指定的命令 /bin/sh -c 命令,并在命令完成后返回。

    有一种方法可以解决该问题,即您可以将其输出重定向到文件然后从文件中读取,而不是在stdout 上打印system() 输出> & 打印。例如

    int main(void) {
            close(1); /* stdout file descriptor is avilable now */
            /* create the file if doesn't exist, if exist truncate the content to 0 length */
            int fd = open("data.txt",O_CREAT|O_TRUNC|O_RDWR,0664); /* fd gets assigned with lowest 
                                                      available fd i.e 1 i.e nowonwards stdout output 
                                                      gets rediredcted to file */
            if(fd == -1) {
                    /* @TODO error handling */
                    return 0;
            }
            system("echo Hello | base64"); /* system output gets stored in file */
            int max_char = lseek(fd,0,2);/* make fd to point to end, get the max no of char */
            char *a = malloc(max_char + 1); /* to avoid buffer overflow or 
                    underflow, allocate memory only equal to the max no of char in file */
            if(a == NULL) {
                    /* @TODO error handling if malloc fails */
                    return 0;
            }
            lseek(fd,0,0);/* from beginning of file */
            int ret = read(fd,a,max_char);/* now read out put of system() from
                                              file as array and print it */
            if(ret == -1) {
                    /* @TODO error handling */
                    return 0;
            }
            a[ret] = '\0';/* \0 terminated array */
            dup2(0,fd);/*fd 0 duplicated to file descriptor where fd points i.e */
            printf("output : %s \n", a);
            /* to avoid memory leak, free the dynamic memory */
            free(a);
            return 0;
    }
    

    我的上述建议是一个临时修复,我不会推荐这个,而是按照@chris Turner (http://man7.org/linux/man-pages/man3/popen.3.html) 的建议使用 [popen],它说

    popen() 函数通过创建管道、分叉、 和 调用外壳。由于管道根据定义是单向的,因此 type 参数只能指定 readingwriting,不能同时指定两者;这 结果流相应地是只读或只写的。

    例如

    int main(void) {
            char buf[1024];
            FILE *fp = popen("echo Hello | base64","r");
            printf("%s\n",fgets(buf,sizeof(buf),fp));
            return 0;
    }
    

    【讨论】:

    • 如果您关闭了标准输出,如何使用printf 写入输出?
    • open("data.txt",O_RDWR|0664);??!?!如果文件不存在,则不会创建该文件。您将 flags 参数误用为 open() 并缺少 mode 参数。请参阅pubs.opengroup.org/onlinepubs/9699919799/functions/open.html 然后,您假设调用dup2(0,fd) 以尝试恢复stdout 是安全的,但不知道stdin 可以安全写入。您最好将dup() stdin 文件号 关闭以保存它。第三,如果您的 read() 调用填满了 a 缓冲区,您将面临缓冲区溢出的风险。
    • 我已经编辑了@AndrewHenle 你能重新检查一下吗?据我了解,dup2(0,fd); 不会打扰其他常规 fd,例如 stdinstdoutstderr
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-01
    • 2020-09-30
    • 1970-01-01
    • 2011-02-27
    • 2020-05-29
    • 2015-01-03
    • 1970-01-01
    相关资源
    最近更新 更多