我正在做一个作业,该作业读取一个文本文件,并在每行的开头添加行号。
我对编码还很陌生,所以如果这是一个简单的任务,对不起。我编写的代码将为我提供输出,告诉我文件中有多少行,但是我无法弄清楚如何实际地对行进行编号并将其显示给我。
//lineNumber = 1;
//Open the file
//While ((c = read a character) is not EOF)
// If (c is \n)
// Print "lineNumber", then increment it
// Print c
//End while
//Close the file
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main() {
int ln = 1;
char c;
FILE *fp = fopen("text.txt", "r");
while((c=getc(fp))!=EOF) {
if (c=='\n'){
ln++;
}
}
printf("lines num: %d",c);
fclose(fp);
//return 0;
}
示例输入:
This is a text file
This text file has words in it.
示例输出:
000001 This is a text file
000002 This text file has words in it.
答案 0 :(得分:3)
您有一个程序可以计算文件中的行数,您需要更改它,以便无需在末尾显示计数 回显文件内容
(例如,在每个getc()之后使用putchar(c);
)和
每次您看到\n
(以及文件的开头)
您需要打印一个带有前导零的数字,然后打印一个空格。
printf("%06d ",ln) ;
可能就是您想要的。
答案 1 :(得分:1)
您有很多小问题要解决。首先,除非您使用的是不合格的编译器,否则main
的合格声明为int main (void)
和int main (int argc, char **argv)
(将看到用等效的char *argv[]
编写)。请参阅:C11 Standard §5.1.2.2.1 Program startup p1 (draft n1570)。另请参阅:What should main() return in C and C++?
接下来,c
必须为int
类型,而不是char
以匹配EOF
,例如
int c, last = 0; /* c must be type int, not char to match EOF */
不要硬编码文件名或使用魔术数字。将文件名作为参数传递给main()
或在程序中提示输入文件名。您可以方便地使用三元运算符通过stdin
来获取文件名以从default
打开或读取,如下所示:
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
最后,对于代码,由于要为每行添加行号前缀 ,因此必须输出第一行的行号之前,为该行输出字符该行(每个后续行都相同)。您可以简单地通过首先输出数字来做到这一点(使用带有修饰符"%06zu "
的{{1}}转换说明符输出前导零,并将 field-width '0'
输出到前导零。匹配显示的格式)。还要注意,6
计数器的类型已从ln
更改为int
,这是C语言中推荐的计数器类型(行数不能为负)。
将其与size_t
字符一起使用以允许在输出字符之前检查last
,可以执行以下操作:
'\n'
(注意:退出循环后对#include <stdio.h>
int main (int argc, char **argv) {
int c, last = 0; /* c must be type int, not char to match EOF */
size_t ln = 1; /* use size_t for counters */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
printf ("%06zu ", ln++); /* output line 1 number */
while ((c = getc(fp)) != EOF) { /* read each character */
if (last) /* test if last set */
putchar (last); /* output all characters */
if (last == '\n') /* test if last is newline */
printf ("%06zu ", ln++); /* output next line number */
last = c; /* set last to c */
}
putchar (last); /* output final character */
if (last != '\n') /* check POSIX eof */
putchar('\n'); /* tidy up with newline */
if (fp != stdin) /* close file if not stdin */
fclose (fp);
return 0;
}
的检查将检查是否存在以最后一行结尾的POSIX行,如果没有,则应手动输出{{ 1}},以便您的程序符合POSIX)
示例输入文件
if (last != '\n')
使用/输出示例
'\n'
仔细检查一下,如果还有其他问题,请告诉我。
(也请注意::如果您的编译器不支持$ cat ../dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
的{{1}}转换说明符,请删除$ ./bin/linenos ../dat/captnjack_noeol.txt
000001 This is a tale
000002 Of Captain Jack Sparrow
000003 A Pirate So Brave
000004 On the Seven Seas.
并输出为无符号值-VS10或更早的版本不支持zu
)
答案 2 :(得分:0)
要对此行进行编号或更改文件的任何部分,最好将文件作为字符串加载到内存中,操纵该字符串(在这种情况下,添加行号),然后创建一个空白新文件。将修改后的字符串复制到新文件中,然后将其重命名为旧文件的路径,以将其覆盖。
/* fp: File whose lines are to be numbered
pathOld: Its path */
void giveLineNos(FILE *fp, const char *pathOld)
{
char line[MAXLINE]; /* line that is read in */
char numbered[MAXLINE + 8]; /* line that will include its number */
int i;
char tempName[L_tmpnam];
tmpnam(tempName); /* generate filename guaranteed to be unique */
FILE *fpNumbered = fopen(tempName, "w"); /* create temporary file onto
which we will write; error checking omitted */
for (i = 0; fgets(line, MAXLINE, fp) != NULL; ++i) {
/* write out the line number followed by its contents */
snprintf(numbered, MAXLINE + 8, "%d: ", i + 1);
strcat(numbered, line);
fputs(numbered, fpNumbered); /* save line to file */
}
rename(tempName, pathOld); /* rename the temporary file to that of
the old one, thereby overwriting it */
fclose(fpNumbered);
fclose(fp);
}
如果您只想打印编号的行而甚至不触摸文件,则可以用对fputs
的调用来替换上面代码中的printf
语句:
/* fputs(numbered, fpNumbered); */ printf("%s", numbered);
(在%s
之后放置换行是错误的,因为fgets
已经在line
缓冲区中放入了换行,然后将其转移到numbered
中。)
还要注意,您的main
是非标准的。使用int
作为返回类型,而不是void
。
答案 3 :(得分:0)
我建议不要在每个'\n'
处增加行数,而每次在'\n'
之后读取一个字符时都应增加行数。这也是代码应打印行号的时候
unsigned long ln = 0;
int prev = '\n';
int c; // Use int here, not char
while((c=getc(fp))!=EOF) {
if (prev == '\n'){
printf("%06lu ", ++ln);
}
putchar(c);
prev = c;
}
if (prev != '\n') {
putchar('\n'); // print a \n for input that lacks a final \n
}
printf("lines num: %lu\n", ln);
请注意,当行数为0(无数据)且输入不以'\n'
结尾时,上述方法效果很好。
使用fgets()
的常见缺点是1)当行长超过输入缓冲区时,需要特殊处理2)当输入意外包含 null字符时,会冒犯热带字符串处理。 getchar()
没有这些问题。