C 从管道保存到字符串
我这里有运行/bin/ls-l的代码,然后将输出输出输出到终端,我想在这里做的是将输出保存到字符串中供以后使用。我不知道该怎么做,但我猜它看起来会像这样C 从管道保存到字符串,c,scanf,popen,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"); } whi
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。解决此问题的正确方法是什么?我假设您希望将目录保存到字符串数组中。在本例中,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;
}
首先是whilefetspath,100,fp!=NULL{已在路径中存储从管道读取的前99个字符。无需扫描任何其他内容
100是一个非常不足以在代码中包含最大路径长度的幻数。最好使用limits中定义的path_MAX。h.通常为4096,但是实现定义的。这就引出了另一点,不要在代码中使用幻数,如果需要系统不提供的常量,请定义一个,或使用全局枚举来定义它
使用fgets读取时,必须检查并删除或以其他方式说明将包含在fgets和POSIX getline填充的缓冲区中的“\n”。这也验证了您确实读取了完整的数据行。否则,如果读取的行长度为PATH_MAX-1,并且末尾没有“\n”,则该行将被删除缓冲区太长,该行的字符在输入流中保持未读状态。只需调用strlen path,然后使用if/else if语句进行检查即可提供验证,并允许您使用nul终止字符覆盖尾随“\n”
为了解决我需要提供多少文件的问题,您可以简单地使用指向char的指针,并根据需要动态地将指针分配给每一行和realloc其他指针。您可以将分配用于存储每一行的每个内存块的地址分配给分配的各个指针。记下e行表示指针计数,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;
}
始终确认已释放所有已分配的内存,并且没有内存错误
仔细检查一下,如果您还有其他问题,请告诉我。您希望它能做什么?scanfpath,s;我希望它能将路径中的文本发送到字符串s中,但我意识到这不起作用。您可能会考虑使用sscanf。但是有更好的选项-例如strncpy。s也是未初始化的-它不会指向任何allocated内存。您必须处理分配和重新分配。您能否澄清一下,您是否试图将ls的所有输出保存为以后使用,或者作为每行一个字符串的数组,或者作为单个多行字符串?这是可行的,但是如果您要在堆栈上放置10000个指针,您最好先分配dyna指针Micaly也是如此。否则,您的目录中有4个文件,您的分配太多了。@DavidC.Rankin您完全正确!我在程序的第二个版本中添加了一个使用该方法的解决方案。这是一个更好的方法,虽然有点不标准,但仍然更好。请查看另一个答案,看看您是否可以这样做wn您正在使用的指向char的指针的声明指针的数量。这不是一件正确或错误的事情,更多的是一个细化问题。减少使用memcpy,realloc可以做到这一点。如果您想将新指针归零,您可以随时调用memset:memcpy new_arr、old_arr、sizeofchar**nr_元素;在您已经完成nr_元素之后再进行计算nts=4*nr_元素;?这不是超出了旧元素的界限吗?valgrind是你的朋友here@DavidC.Rankin再次感谢!是的,这太过分了!回答得很好,解释得很清楚,演示得很清楚如何使用realloc!@sg7,这几乎是标准的肉土豆方法。如果你想设置你的新p在realloc之后将指针设置为零,然后在分配file=tmp;之后,您可以在nfiles*=2;之前执行memset files+nfiles,0,nfiles*sizeof*files。这将允许您迭代填充指针,例如i=0;而文件[i]{do stuff;i++;}
#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
$ 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)