c - 从管道保存到字符串

标签 c scanf popen

我这里有运行 /bin/ls -l 的代码,然后将输出打印到终端,我在这里要做的是将输出保存到字符串中以供以后使用。我不知道如何去做,但根据我的猜测,它看起来像这样

int main (){
    FILE *fp;
    int status;
    char path[100];
    char *s;
    fp = popen("/bin/ls -l", "r");
    if (fp == NULL){
        printf("fp error");
    }
    while(fgets(path,100,fp)!= NULL){
        printf("%s\n", path );
        scanf(path, s);
    }
    status = pclose(fp);
    if (status==-1){
        printf("pclose error");
    }else{
        printf("else on pclose\n");
    }
    return 0;
}

while 循环打印出我的目录结果没有问题,但我在最后遇到了段错误:11。解决这个问题的正确方法是什么?

最佳答案

首先是while(fgets(path,100,fp)!= NULL){已存储第一个 99path 中的管道读取的字符。没有必要scanf其他任何东西。

100是一个严重不足的神奇数字,无法包含在代码中以获得最大路径长度。更好用PATH_MAX定义于 limits.h 。 (通常 4096 ,但由实现定义)。这就引出了另一点,不要在代码中使用魔数(Magic Number),如果你需要系统没有提供的常量,那么 #define之一,或使用全局 enum来定义它。

使用fgets阅读时,您必须检查并删除(或以其他方式说明) '\n'将包含在 fgets 填充的缓冲区中(和 POSIX getline )。这还可以验证您确实读取了完整的数据行。否则,如果读取的行长度为 PATH_MAX - 1并且没有'\n'最后,该行对于缓冲区来说太长,并且该行的字符在输入流中仍未读取。简单调用strlen (path)然后检查 if/else if语句提供验证并允许您覆盖尾随 '\n'带有nul终止字符。

要处理“我需要提供多少个文件?”的问题,您可以简单地使用指向字符的指针并动态分配指向每一行的指针, realloc根据需要提供额外的指针。您将分配用于存储每一行​​的每个内存块的地址分配给您分配的各个指针。保留行数(用于指针计数)和 realloc当您达到限制时更多指针(这适用于以相同的方式从文本文件中读取)不要忘记在完成后释放您分配的内存。

将所有部分放在一起,您可以执行如下操作:

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

#define NFILES 16

int main (){

    size_t i, n = 0,            /* number of files in listing    */
        nfiles = NFILES;        /* number of allocated pointers  */
    char path[PATH_MAX] = "",   /* buffer (PATH_MAX in limits.h) */
        **files = NULL;         /* pointer to pointer to file    */
    FILE *fp = popen("/bin/ls -l", "r");

    if (fp == NULL) {           /* validate pipe open for reading */
        perror ("popen");
        return 1;
    }

    /* allocate/validate initial number of pointers */
    if (!(files = malloc (nfiles * sizeof *files))) {
        perror ("malloc - files");
        return 1;
    }

    while (fgets (path, PATH_MAX, fp)) {    /* read each line */

        size_t len = strlen (path);         /* get length     */
        if (len && path[len - 1] == '\n')   /* validate '\n'  */
            path[--len] = 0;                /* trim '\n'      */
        else if (len + 1 == PATH_MAX) {     /* check path too long */
            fprintf (stderr, "error: path too long.\n");
            /* handle remaining chars in fp */
        }

        /* allocate/validate storage for line */
        if (!(files[n] = malloc (len + 1))) {
            perror ("malloc - files[n]");
            break;
        }

        strcpy (files[n++], path);          /* copy path */

        if (n == nfiles) {  /* realloc pointers as required */
            void *tmp = realloc (files, nfiles * 2 * sizeof *files);
            if (!tmp) {
                perror ("realloc");
                break;
            }
            files = tmp;
            nfiles *= 2;        /* increment current allocation */
        }
    }


    if (pclose (fp) == -1)      /* validate close */
        perror ("pclose");

    /* print and free the allocated strings */
    for (i = 0; i < n; i++) {
        printf ("%s\n", files[i]);    
        free (files[i]);        /* free individual file storage */
    }
    free (files);               /* free pointers */

    return 0;
}

示例使用/输出

$ ./bin/popen_ls_files > dat/filelist.txt

$ wc -l dat/filelist.txt
1768 dat/filelist.txt

$ cat dat/filelist.txt
total 9332
-rw-r--r--  1 david david     376 Sep 23  2014 3darrayaddr.c
-rw-r--r--  1 david david     466 Sep 30 20:13 3darrayalloc.c
-rw-r--r--  1 david david     802 Jan 25 02:55 3darrayfill.c
-rw-r--r--  1 david david     192 Jun 27  2015 BoggleData.txt
-rw-r--r--  1 david david    3565 Jun 26  2014 DoubleLinkedList-old.c
-rw-r--r--  1 david david    3699 Jun 26  2014 DoubleLinkedList.c
-rw-r--r--  1 david david    3041 Jun 26  2014 DoubleLinkedList.diff
<snip>
-rw-r--r--  1 david david    4946 May  7  2015 workers.c
-rw-r--r--  1 david david     206 Jul 11  2017 wshadow.c
-rw-r--r--  1 david david    1283 May 18  2015 wsininput.c
-rw-r--r--  1 david david    5519 Oct 13  2015 xpathfname.c
-rw-r--r--  1 david david     785 Sep 30 02:49 xrealloc2_macro.c
-rw-r--r--  1 david david    2090 Sep  6 02:29 xrealloc_tst.c
-rw-r--r--  1 david david    1527 Sep  6 03:22 xrealloc_tst_str.c
-rwxr-xr--  1 david david     153 Aug  5  2014 xsplit.sh

内存使用/错误检查

在您编写的动态分配内存的任何代码中,对于分配的任何内存块,您都有两个责任:(1) 始终保留指向起始地址的指针内存块,因此,(2) 当不再需要它时可以释放

对于 Linux valgrind是正常的选择。每个平台都有类似的内存检查器。它们使用起来都很简单,只需通过它运行您的程序即可。

$ valgrind ./bin/popen_ls_files > /dev/null
==7453== Memcheck, a memory error detector
==7453== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==7453== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==7453== Command: ./bin/popen_ls_files
==7453==
==7453==
==7453== HEAP SUMMARY:
==7453==     in use at exit: 0 bytes in 0 blocks
==7453==   total heap usage: 1,777 allocs, 1,777 frees, 148,929 bytes allocated
==7453==
==7453== All heap blocks were freed -- no leaks are possible
==7453==
==7453== For counts of detected and suppressed errors, rerun with: -v
==7453== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放分配的所有内存并且不存在内存错误。

仔细检查一下,如果您还有其他问题,请告诉我。

关于c - 从管道保存到字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48480629/

相关文章:

c - 如何在C中动态地从文件流填充数组

c - 如何在C中以十六进制、十进制和八进制形式打印常量

C: 由 popen() 函数执行的 Linux 命令不显示结果

python - 没有从失败的 subprocess.Popen 获得任何错误消息

c - 双向链表错误

objective-c - 在回调期间可以做任何事情吗?一个基本的 objective-c 问题

c - 反转字符串变量,或反转打印字符数组

c - 扫描整数的第 2 位数字

c - 在c中的文件中搜索

ruby - 使用 Ruby popen 和 PostgreSQL createuser