我正在尝试创建一个将文件路径作为命令行参数的C程序。我的程序然后逐行读取该文件,删除结束字符并将其添加到字符串,所以最后字符串是输入文件,但只在一行。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char **argv){
FILE *input = fopen(argv[1], "r");
char *line = NULL;
char buffer[100];
char temp[200];
line = fgets(buffer, 100 *sizeof(char), input);
while(line != NULL){
line[strlen(line)-1] = '\0';
strcat(temp, line);
line = fgets(buffer, 100 *sizeof(char), input);
}
printf("%s\n", temp);
fclose(input);
}
我输入了一个包含数据的文件:
This is Line 1
line 2
line 3
and this is line 4
并期望字符串
This is Line 1line 2line 3and this is line 4
但确实如此
and this is line 1
感谢任何帮助!
答案 0 :(得分:0)
以下程序适合我。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char **argv){
FILE *input = fopen(argv[1], "r");
char *line = NULL;
char buffer[100]={0};
char temp[200]={0};
line = fgets(buffer, 100 *sizeof(char), input);
while(line != NULL){
strcat(temp, line);
temp[strlen(temp)-1] = '\0';
line = fgets(buffer, 100 *sizeof(char), input);
}
printf("%s\n", temp);
fclose(input);
}
答案 1 :(得分:0)
您冒着未定义行为的风险(1)无法验证input
实际上是为阅读打开的有效文件流,以及(2)未能跟踪存储的最大字符数temp
允许存储的字符多于你有空间(你会因未能检查参数计数大于1
而调用未定义的行为,但是参数向量(fopen
)末尾的 sentinel NULL
只会导致argv
失败 - - 但是因为你没有检查......)。
在查看可能的修复之前,让我们看看一些常规编码点。请勿在代码中使用幻数,例如fopen
,100
,
200
通过在每个源文件的开头定义常量,如果你需要随着时间的推移调整它们,你就不必去挑选每个声明,循环变量,测试子句等等。以确保你做了所有必要的修改。
在使用命令行参数之前,验证您的参数计数(/* if use need constants, #define them or use an enum */
enum { BUFSZ = 100, TMPSZ = 200 };
int main (int argc, char **argv){
char buffer[BUFSZ] = "", /* read buffer */
temp[TMPSZ] = ""; /* buffer for combined lines */
):
argc
在从您打开的任何文件中读取之前:
if (argc < 2 ) { /* validate at least 1 argument given */
fprintf (stderr, "error: insufficient input, usage: %s file\n", argv[0]);
return 1;
}
使用 if (!input) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
阅读时,除非您放弃第一行,否则在输入fgets
循环以读取文件之前无需单独的fgets
,
while
验证 while (fgets(buffer, BUFSZ, input)) { /* read each line */
...
}
中读取的最后一个字符是否为buffer
个字符:
'\n'
现在要防止 Undefined Behavior 。您只有 size_t len = strlen (buffer); /* get length */
if (len && buffer[len - 1] == '\n') /* check if last is '\n' */
buffer[--len] = 0; /* overwrite with nul-char */
个字符可用,如果您打算将TMPSZ
用作字符串,则必须确保为 nul-terminatedating 字符{{1}留出空间}作为最后一个角色。 (temp
相当于'\0'
(零))。因此,检查长度,到目前为止存储的字符数,最多写入一个 '\0'
中剩余的字符数,
0
如果你在上面的测试中没有到达temp
的末尾,那么 if (TMPSZ <= nchr + len + 1) { /* room to fit in buffer? */
strncat (temp, buffer, TMPSZ - nchr - 1); /* only what fits */
nchr = TMPSZ - 1; /* nchr is max (+1 for nul-char) */
temp[nchr] = 0; /* affirmatively nul-terminate */
break; /* bail - all full */
}
将适合temp
,所以只需复制它并更新总字符数:
buffer
那就是它。完全放在一起,您可以从作为第一个参数给出的文件中读取(或者如果没有给出参数,则默认来自temp
)并将所有行组合成一行直到 strcat (temp, buffer); /* copy buffer to temp */
nchr += len; /* update nchr */
}
个字符,例如< / p>
stdin
示例使用/输出
TMPSZ - 1
TMPSZ = 20
的示例让我们进行测试。我们设置#include <stdio.h>
#include <string.h>
/* if use need constants, #define them or use an enum */
enum { BUFSZ = 100, TMPSZ = 200 };
int main (int argc, char **argv){
char buffer[BUFSZ] = "", /* read buffer */
temp[TMPSZ] = ""; /* buffer for combined lines */
size_t nchr = 0; /* total character count */
FILE *input = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!input) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets(buffer, BUFSZ, input)) { /* read each line */
size_t len = strlen (buffer); /* get length */
if (len && buffer[len - 1] == '\n') /* check if last is '\n' */
buffer[--len] = 0; /* overwrite with nul-char */
if (TMPSZ <= nchr + len + 1) { /* room to fit in buffer? */
strncat (temp, buffer, TMPSZ - nchr - 1); /* only what fits */
nchr = TMPSZ - 1; /* nchr is max (+1 for nul-char) */
temp[nchr] = 0; /* affirmatively nul-terminate */
break; /* bail - all full */
}
strcat (temp, buffer); /* copy buffer to temp */
nchr += len; /* update nchr */
}
if (input != stdin) fclose (input); /* close file if not stdin */
printf ("'%s'\n(%zu chars)\n", temp, nchr); /* output temp */
return 0;
}
并验证我们的代码是否能够正确防止在$ ./bin/cmblines <dat/cmblines.txt
'This is Line 1line 2line 3and this is line 4'
(44 chars)
结束后写作,
TMPSZ = 20
仔细看看,如果您有其他问题,请告诉我。