从 stdin c 读取文件名
Reading in filenames from stdin c
虽然这是一个非常基本的问题,应该很容易解决,但我一直没弄明白。我试图读入一个字符串,其中包含由标准输入中的空格分隔的文件名。虽然它似乎正确读取了所有文件名,但当我在文件名上使用 stat() 时,它总是在最后一个文件上失败。所有文件都存在,但最后一个文件总是失败,例如,如果标准输入是 "file.txt thisFile.txt thisFile.txt",如果我要求它将输入打印到标准输出,它将打印 "file.txt thisFile.txt thisFile.txt",但是当我使用 stat( ) 在文件上它将适用于除最后一个文件之外的所有文件。我相信这与我阅读文件的方式有关,我们将不胜感激。 P.S。如果我以空格 "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, " [=10=]FEOFfeof\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, " [=10=]FEOFfeof\n");
}
fgets()
在读取字符串的末尾留下 '\n'
。
所以你只需要删除它,一个例子是
while (fgets(buffer, sizeof(buffer), stdin) != NULL)
{
size_t length
length = strlen(buffer);
if (buffer[length - 1] == '\n')
buffer[length - 1] = '[=10=]';
...
}
接受答案后
" [=13=]FEOFfeof\n"
中的 "[=12=]"
(八进制转义序列)导致截断模式
char * pch = strtok(input, " [=10=]FEOFfeof\n");
// same as
char * pch = strtok(input, " ");
推荐
的一些变体
char * pch = strtok(input, " \n\r\t\v\f");
你的代码有很多问题,这里是注释版本:
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 个字节的内容加上结尾 '[=27=]'
。
您应该将测试更改为 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(input)!不要
依靠编译器的聪明才智来优化这段代码,在很多情况下,它
不会的。
if (input[i] == ' ')
count++;
}
char * fileNames[count];
char * pch = strtok(input, " [=14=]FEOFfeof\n");
正如 chux 指出的那样,模式中嵌入的 [=29=]
实际上结束了它。
此外,您不能以这种方式测试 EOF
。 EOF
是一个特殊值
getc
返回表示未能从
流,不是可以存储在字符串中的实际字符。
如果您更改模式以处理其他间距字符,您
还必须更改计算文件名数量的循环
因此。
int j = 0;
for (j = 0; pch != NULL; j++){ //Read file names
fileNames[j] = (char *)malloc(strlen(pch));
精确分配 strlen(pch)
是一个典型的错误。你需要分配在
至少一个额外的字节来存储字符串末尾的 '[=27=]'
。如果
strdup
在你的系统上可用,它会做你想做的事。我
不明白为什么这个有用的 BSD 函数从未进入
标准。
strncpy(fileNames[j],pch, strlen(pch));
请勿使用strncpy
。它很容易出错,并且不会做你想做的事
预计。在这种情况下,memcpy
会执行您的意思,复制
没有结尾 '[=27=]'
的文件名。但我怀疑这不是你
真的意思。您可以将这两行替换为 fileNames[j] = strdup(pch);
pch = strtok(NULL, " [=17=]FEOFfeof\n");
}
strtok
也容易出错,因为它使用静态隐藏变量来保存
上下文。如果你在调用之间做更复杂的事情
strtok
,此上下文可能会被覆盖,您的代码将显示
奇怪的行为,你可能会因为这样的错误而浪费很长时间。采用
strtok_r
或 strsep
如果您的系统可用。
关于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;
}
虽然这是一个非常基本的问题,应该很容易解决,但我一直没弄明白。我试图读入一个字符串,其中包含由标准输入中的空格分隔的文件名。虽然它似乎正确读取了所有文件名,但当我在文件名上使用 stat() 时,它总是在最后一个文件上失败。所有文件都存在,但最后一个文件总是失败,例如,如果标准输入是 "file.txt thisFile.txt thisFile.txt",如果我要求它将输入打印到标准输出,它将打印 "file.txt thisFile.txt thisFile.txt",但是当我使用 stat( ) 在文件上它将适用于除最后一个文件之外的所有文件。我相信这与我阅读文件的方式有关,我们将不胜感激。 P.S。如果我以空格 "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, " [=10=]FEOFfeof\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, " [=10=]FEOFfeof\n");
}
fgets()
在读取字符串的末尾留下 '\n'
。
所以你只需要删除它,一个例子是
while (fgets(buffer, sizeof(buffer), stdin) != NULL)
{
size_t length
length = strlen(buffer);
if (buffer[length - 1] == '\n')
buffer[length - 1] = '[=10=]';
...
}
接受答案后
" [=13=]FEOFfeof\n"
中的 "[=12=]"
(八进制转义序列)导致截断模式
char * pch = strtok(input, " [=10=]FEOFfeof\n");
// same as
char * pch = strtok(input, " ");
推荐
的一些变体char * pch = strtok(input, " \n\r\t\v\f");
你的代码有很多问题,这里是注释版本:
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 个字节的内容加上结尾 '[=27=]'
。
您应该将测试更改为 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(input)!不要 依靠编译器的聪明才智来优化这段代码,在很多情况下,它 不会的。
if (input[i] == ' ')
count++;
}
char * fileNames[count];
char * pch = strtok(input, " [=14=]FEOFfeof\n");
正如 chux 指出的那样,模式中嵌入的 [=29=]
实际上结束了它。
此外,您不能以这种方式测试 EOF
。 EOF
是一个特殊值
getc
返回表示未能从
流,不是可以存储在字符串中的实际字符。
如果您更改模式以处理其他间距字符,您
还必须更改计算文件名数量的循环
因此。
int j = 0;
for (j = 0; pch != NULL; j++){ //Read file names
fileNames[j] = (char *)malloc(strlen(pch));
精确分配 strlen(pch)
是一个典型的错误。你需要分配在
至少一个额外的字节来存储字符串末尾的 '[=27=]'
。如果
strdup
在你的系统上可用,它会做你想做的事。我
不明白为什么这个有用的 BSD 函数从未进入
标准。
strncpy(fileNames[j],pch, strlen(pch));
请勿使用strncpy
。它很容易出错,并且不会做你想做的事
预计。在这种情况下,memcpy
会执行您的意思,复制
没有结尾 '[=27=]'
的文件名。但我怀疑这不是你
真的意思。您可以将这两行替换为 fileNames[j] = strdup(pch);
pch = strtok(NULL, " [=17=]FEOFfeof\n");
}
strtok
也容易出错,因为它使用静态隐藏变量来保存
上下文。如果你在调用之间做更复杂的事情
strtok
,此上下文可能会被覆盖,您的代码将显示
奇怪的行为,你可能会因为这样的错误而浪费很长时间。采用
strtok_r
或 strsep
如果您的系统可用。
关于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;
}