如果空行重复,也应删除空行。如果line有转义序列(如\t
),则它与空行不同。下面的代码是删除太多行,或者有时会留下重复的行。如何解决这个问题?
#include <stdio.h>
#include <stdlib.h>
int main()
{
char a[6000];
char b[6000];
int test = 0;
fgets(a, 6000, stdin);
while (fgets(b, 6000, stdin) != NULL) {
for (int i = 0; i < 6000; i++) {
if (a[i] != b[i]) {
test = 1;
}
}
if (test == 0) {
fgets(b, 6000, stdin);
} else {
printf("%s", a);
}
int j = 0;
while (j < 6000) {
a[j] = b[j];
j++;
}
test = 0;
}
return 0;
}
答案 0 :(得分:2)
你的逻辑主要是合理的。你的思路是正确的:
previous
(a
)中读取一行。current
(b
)。previous
和current
具有相同的内容,请转到步骤2. previous
。current
移至previous
。然而,这仍有一些问题。
首先,请考虑以下代码:
while(fgets(b,6000,stdin)!=NULL) {
...
if(test==0) {
fgets(b,6000,stdin);
}
else {
printf("%s",a);
}
...
}
如果a
和b
具有相同的内容(test==0
),则使用未经检查的fgets
再次读取一行,除非您再次阅读 < / strong>评估循环条件fgets(b,6000,stdin)!=NULL
时。问题是你大多忽略了刚读过的那一行,这意味着你正在将一条未知的行从b
移动到a
。由于循环已经读取另一行并正确检查失败,只需让循环读取该行,并反转if
语句的相等性测试以打印a
test!=0
。
您的逻辑也不会打印最后一行。考虑一行1行。你读它,然后循环条件中的fgets
尝试读取另一行,因为你在文件的末尾失败了。循环外没有打印语句,因此您永远不会打印该行。
那么有两行不同的文件呢?你读第一行,然后是最后一行,看它们是不同的,然后打印第一行。然后用最后一行覆盖第一行的缓冲区。你没有读到另一行,因为没有了,最后一行也没有打印出来。
您可以将第一个(未经检查的)fgets
替换为a[0] = 0
来解决此问题。这使得a
的第一个字节成为空字节,这意味着字符串的结尾。它不会与您阅读的行进行比较,因此会打印test==1
,意味着a
。由于a
中没有要打印的字符串,因此不会打印任何内容。事情继续正常进行,b
的内容被移入a
,另一行被读取。
这留下了一个问题:如果不是重复,则不会打印最后一行。要解决此问题,只需打印b
而不是a
。
0
分配给previous
(a[0]
)的第一个字节。current
(b
)中读取一行。previous
和current
具有相同的内容,请转到步骤2. current
。current
移至previous
。正如您所看到的,它与您现有的逻辑没有太大区别;只有步骤1和4不同。它还确保检查所有fgets
个调用。如果文件中没有行,则不打印任何内容。如果文件中只有一行,则打印出来。如果2行不同,则都打印。如果2行相同,则打印第一行。
fgets
将自动添加一个以标记字符串的结尾。break
循环的if
语句中添加for
语句。如果单个字节不匹配,则整行不重复,因此如果只有字节10在两个1000字节行中不同,则可以更快地停止比较!答案 1 :(得分:1)
#include <stdio.h>
#include <string.h>
int main(void)
{
char buff[2][6000];
unsigned count=0;
char *prev=NULL
, *this= buff[count%2]
;
while( fgets(this, sizeof buff[0] , stdin)) {
if(!prev || strcmp(prev, this) ) { // first or different
fputs(this, stdout);
prev=this;
count++;
this=buff[count%2];
}
}
fprintf(stderr, "Number of lines witten: %u\n", count);
return 0;
}
答案 2 :(得分:0)
您的代码中存在一些问题,例如:
for(int i=0; i<6000; i++) {
if(a[i]!=b[i]) {
test=1;
}
}
在这个循环中,每次整个缓冲区将逐个字符进行比较,即使它找到if(a[i]!=b[i])
的某个值i
。可能你应该在test=1
之后打破循环。
由于您没有在循环外打印行,因此您的逻辑也不适用于只有1行的文件。
另一个问题是大小为6000字符的固定长度缓冲区。
您可以使用getline
来解决问题。你可以做 -
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char * line = NULL;
char * comparewith = NULL;
int notduplicate;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, stdin)) != -1) {
((comparewith == NULL ) || (strcmp (line, comparewith) != 0)) ? (notduplicate = 1) : (notduplicate = 0);
if (notduplicate) {
printf ("%s\n", line);
if (comparewith != NULL)
free(comparewith);
comparewith = line;
line = NULL;
}
}
if (line)
free (line);
if (comparewith)
free (comparewith);
return 0;
}
需要注意的重点:
getline()
不在C标准库中。 getline()
最初是GNU扩展,standardized in POSIX.1-2008。因此,此代码可能无法移植。为了使其可移植,您需要推送自己的getline()
this之类的内容。
答案 3 :(得分:0)
这是一个更简单的解决方案,对行长度没有限制:
Activity 3
代码会跳过超过2个连续换行符的序列,因此会删除重复的空行。