代码之家  ›  专栏  ›  技术社区  ›  AFC

从管道保存到字符串

  •  0
  • AFC  · 技术社区  · 7 年前

    我这里有运行的代码 /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。解决这个问题的正确方法是什么?

    2 回复  |  直到 7 年前
        1
  •  1
  •   David C. Rankin    7 年前

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

    100 是一个严重不足的 幻数 以在代码中包含最大路径长度。更好地使用 PATH_MAX 定义于 limits.h . (一般情况下 4096 ,但定义了实现)。这就引出了另一个问题,不要使用 幻数 在代码中,如果需要系统不提供的常量,那么 #define 一个,或使用全局 enum 来定义它。

    阅读时使用 fgets ,您必须检查并删除(或以其他方式说明) '\n' 将包含在由填充的缓冲区中 fgets (和POSIX getline ). 这也验证了您确实读取了一整行数据。否则,如果读取的行长度为 PATH_MAX - 1 而且没有 “\n” 最后,行太长,缓冲区无法容纳该行,该行的字符在输入流中保持未读状态。一个简单的调用 strlen (path) 然后检查 if/else if 语句提供验证并允许您覆盖尾部 “\n” 用一个 nul终止 性格

    要处理“需要提供多少文件?”的问题,您只需使用 指向char的指针 并将指针动态分配给每一行 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
    

    内存使用/错误检查

    在任何动态分配内存的代码中,都有2个 责任 关于分配的任何内存块:(1) 始终保留指向起始地址的指针 对于内存块so,(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)
    

    始终确认已释放所有已分配的内存,并且没有内存错误。

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

        2
  •  0
  •   sg7 Krafty Coder    7 年前

    我假设您希望将目录保存到字符串数组中。在本例中,数组为 s[] 保留指向所有条目的指针。每个读条目都会为条目和字符串终止符分配内存 \0 .

    启动程序可能如下所示:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAX_NR_OF_ENTRIES 10000
    #define PATH_LEN    256
    
    int main (){
        FILE *fp;
        int status;
        char path[PATH_LEN];
        char *s[MAX_NR_OF_ENTRIES]; 
        int i,j = 0;
    
        fp = popen("/bin/ls -l", "r");
    
        if (fp == NULL){
            printf("fp error\n");
        }
    
        while(fgets(path,PATH_LEN,fp) != NULL){
    
            printf("%s\n", path );
    
            s[i] = malloc(strlen(path)+1);
            strcpy(s[i],path);
            i++;
    
            if(i>=MAX_NR_OF_ENTRIES) 
            {
                printf("MAX_NR_OF_ENTRIES reached!\n");     
                break;
            }
        }
    
    
        status = pclose(fp);
        if (status==-1){
            printf("pclose error");
        }else{
            printf("pclose was fine!\n");
        }
    
        // Print and free the allocated strings
        for(j=0; j< i; j++){
            printf("%s\n", s[j] );    
            free (s[j]);        
        }
    
        return 0;
    }
    

    这是可行的,但我们在堆栈上放置了10000个指针。但是,正如DavidC.Rankin所建议的,我们可以分配数组的数组 s 动态的。启动工作程序:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAX_NR_OF_ENTRIES 10
    #define PATH_LEN    256
    
    int main (){
        FILE *fp;
        int status;
        char path[PATH_LEN];
    
        int i,j = 0;
    
        size_t nr_of_elements = MAX_NR_OF_ENTRIES;
    
        char **old_arr;
        char **new_arr;
    
        char **s = calloc(nr_of_elements, sizeof(char*));
    
        fp = popen("/bin/ls -l", "r");
    
        if (fp == NULL){
            printf("fp error\n");
        }
    
        while(fgets(path,PATH_LEN,fp) != NULL){
    
            printf("%s\n", path );
    
            char *str = malloc(strlen(path)+1);
            strcpy(str, path);
            s[i] = str;
    
            i++;
    
            if(i>=nr_of_elements ) 
            {
                printf("resizing\n");     
                size_t old_size = nr_of_elements; 
                nr_of_elements = 4*nr_of_elements; // increase size for `s` 4 times (you can invent something else here)
                old_arr = s; 
    
                // allocating a bigger copy of the array s, copy it inside, and redefine the pointer:
    
                new_arr = calloc(nr_of_elements, sizeof(char*));
    
                if (!new_arr) 
                 {
                     perror("new calloc failed");
                     exit(EXIT_FAILURE);
                 }
    
                memcpy (new_arr, old_arr, sizeof(char*)*old_size);   // notice the use of `old_size` 
    
                free (old_arr);
                s = new_arr;
             }
        }
    
    
        status = pclose(fp);
        if (status==-1){
            printf("pclose error");
        }else{
            printf("pclose was fine!\n");
        }
    
        // Print and free the allocated strings
        for(j=0; j< i; j++){
            printf("%s\n", s[j] );    
            free (s[j]);        
        }
    
        free(s);
        return 0;
    }