从stdin c中读取文件名

时间:2015-03-07 00:20:03

标签: c stdin fgets strtok stat

虽然这是一个非常基本的问题,应该很容易解决,但我还是无法弄明白。我试图读取一个字符串,其中包含由stdin的空格分隔的文件名。虽然它似乎正确读取所有文件名,但当我在文件名上使用stat()时,它总是在最后一个文件上失败。这些文件都存在,并且它总是在最后一个文件中失败,例如,如果stdin是“file.txt thisFile.txt thisFile.txt”,如果我要求它将输入打印到stdout,它将打印“file.txt thisFile。 txt thisFile.txt“,但是当我在文件上使用stat()时,它将适用于除最后一个文件之外的所有文件。我相信它与我在文件中阅读的方式有关,任何帮助都表示赞赏。附:如果我用空格“file.txt thisFile.txt thisFile.txt”结束输出,它将统计所有文件没有问题。但是由于程序的其他部分和其他文件需要通过管道来处理,额外的空格不是输入的有效格式。

char *input = 0;
char buffer[10];
size_t curMax = 0;
size_t curLen = 0;
fprintf(stderr, "accessed waiting for input\n");
while(fgets(buffer,sizeof(buffer),stdin)!=0)
{
    size_t bufLen = strlen(buffer);
    if(curLen+bufLen+1>curMax)
    {
        size_t newLen = curMax*2+1;
        if(bufLen+1>newLen)
            newLen=bufLen+1;
        char *extra = realloc(input, newLen);
        if (!extra)
            break;
        input = extra;
        curMax = newLen;
    }
    strcpy(input+curLen,buffer);
    curLen+=bufLen;
}

fprintf(stderr, "accessed input received: %s\n", input);
int i = 0;
int count = 1;
for (i = 0; i < strlen(input); i++){
    if (input[i] == ' ')
        count++;
}
char * fileNames[count];
char * pch = strtok(input, " \0FEOFfeof\n");
int j = 0;
for (j = 0; pch != NULL; j++){ //Read file names
    fileNames[j] = (char *)malloc(strlen(pch));
    strncpy(fileNames[j],pch, strlen(pch));
    pch = strtok(NULL, " \0FEOFfeof\n");
}

3 个答案:

答案 0 :(得分:3)

接受回答后

"\0"中的" \0FEOFfeof\n"(八进制转义序列)导致截断模式

char * pch = strtok(input, " \0FEOFfeof\n");
// same as 
char * pch = strtok(input, " ");

推荐一些

的变体
char * pch = strtok(input, " \n\r\t\v\f");

答案 1 :(得分:2)

fgets()'\n'留在读取字符串的末尾。

所以你只需要删除它,一个例子就是

while (fgets(buffer, sizeof(buffer), stdin) != NULL)
 {
    size_t length
    length = strlen(buffer);
    if (buffer[length - 1] == '\n')
        buffer[length - 1] = '\0';
    ...
 }

答案 2 :(得分:1)

您的代码存在许多问题,这是注释版本:

char *input = 0;

为清楚起见,您应该使用NULL代替0来获取空指针。

char buffer[10];
size_t curMax = 0;
size_t curLen = 0;
fprintf(stderr, "accessed waiting for input\n");

while(fgets(buffer,sizeof(buffer),stdin)!=0)

与上述相同,!= NULL代替!=0,或者您可以删除 完全测试并写下:while (fgets(buffer, sizeof(buffer), stdin)),这是C中公认的习语。

{
    size_t bufLen = strlen(buffer);
    if(curLen+bufLen+1>curMax)
    {
        size_t newLen = curMax*2+1;
        if(bufLen+1>newLen)
            newLen=bufLen+1;

在某些情况下,测试无法分配足够的内存:如果是第一个 line有1个字节,分配2个字节的缓冲区并设置curMax 2。如果第二行有4个字节,则input将被重新分配给 5个字节,1个字节太短,无法容纳1 + 4 + 1个字节的内容加上尾随'\0'。 您应该将测试更改为if(curLen+bufLen+1>newLen) newLen=curLen+bufLen+1;

        char *extra = realloc(input, newLen);
        if (!extra)
            break;
        input = extra;
        curMax = newLen;
    }
    strcpy(input+curLen,buffer);
    curLen+=bufLen;
}

fprintf(stderr, "accessed input received: %s\n", input);
int i = 0;
int count = 1;
for (i = 0; i < strlen(input); i++){

不要为循环的每次迭代重新计算strlen(输入)!不要 依赖于编译器的聪明才能优化这段代码,在很多情况下,它 不会。

    if (input[i] == ' ')
        count++;
}
char * fileNames[count];
char * pch = strtok(input, " \0FEOFfeof\n");

正如chux指出的那样,模式中的嵌入式\0实际上结束了它。 此外,您无法以这种方式测试EOFEOF是一个特殊值 由getc返回,表示未能从中读取字符 stream,is不是可以存储在字符串中的实际字符。 如果您更改模式以处理其他间距字符,您 还必须更改计算文件名数量的循环 相应

int j = 0;
for (j = 0; pch != NULL; j++){ //Read file names
    fileNames[j] = (char *)malloc(strlen(pch));

完全分配strlen(pch)是一个经典的错误。你需要分配 在字符串末尾存储'\0'的至少一个额外字节。如果 您的系统上可以使用strdup,它可以满足您的需求。一世 不明白为什么这个有用的BSD功能从未进入过 标准。

    strncpy(fileNames[j],pch, strlen(pch));

请勿使用 strncpy。这是非常容易出错的,不会对你做什么 期望。在这种情况下,memcpy会做你的意思,复制 没有结尾'\0'的文件名。但我怀疑这不是你的意思 真的意味着。您可以使用fileNames[j] = strdup(pch);

替换这两行
    pch = strtok(NULL, " \0FEOFfeof\n");
}

strtok也容易出错,因为它使用静态隐藏变量来保存 上下文。如果你在调用之间做了更复杂的事情 strtok,此上下文可能会被覆盖,您的代码将展示 奇怪的行为,你可能会在这样的错误上失去很长时间。使用 strtok_rstrsep,如果您的系统可用。

关于strdup:如果它不可用,请自行定义:

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

char *strdup(const char *ptr) {
    char *newptr;
    if ((newptr = malloc(strlen(ptr) + 1)) != NULL) {
        strcpy(newptr, ptr);
    }
    return newptr;
}