我有一个包含以下内容的简单文本文件:
dog
bear
panda
fish
elephant
但是,我希望他们所有人都有10个字符。
因此,我希望用' x'填充剩下的部分。像:
dogxxxxxxx
bearxxxxxx
pandaxxxxx
fishxxxxxx
elephantxx
到目前为止我所拥有的是:
int filterWords(){
FILE *ptr_file;
FILE *ptr_file2;
char buf[1000];
int i = 0;
int numberSpaces;
ptr_file =fopen("animals.txt","r");
if (!ptr_file)
return 1;
while (fgets(buf,1000, ptr_file)!=NULL){
if(strlen(buf) < 10){
numberSpaces = 10 - strlen(buf)-1;
memset(buf, 'x', numberSpaces);
buf[strlen(buf)+numberSpaces] = '\0';
ptr_file2 = fopen("newAnimal.txt", "a");
fputs(buf, ptr_file2);
fclose(ptr_file2);
}
}
fclose(ptr_file);
return 0;
}
但是,当我尝试打开newAnimal.txt
时,我得到了类似的内容:
dog
xxxbxxxear
pandaxxxf
ishxxxxxx
....
所有人都错了。我的代码出了什么问题?
答案 0 :(得分:2)
首先,
memset(buf, 'x', numberSpaces);
应该是
memset(&buf[strlen(buf)], 'x', numberSpaces);
另外,你正在计算numberSpaces错误。而不是:
numberSpaces = 10 - strlen(buf)-1;
应该是:
numberSpaces = 10 - strlen(buf);
更正后,您需要将\ 0放在正确的位置。而不是:
buf[strlen(buf)+numberSpaces] = '\0';
变成:
buf[strlen(buf)] = '\0';
你的while循环现在看起来像:
while (fgets(buf,1000, ptr_file)!=NULL){
if(strlen(buf) < 10){
numberSpaces = 10 - strlen(buf);
memset(&buf[strlen(buf), 'x', numberSpaces);
buf[strlen(buf)] = '\0';
ptr_file2 = fopen("newAnimal.txt", "a");
fputs(buf, ptr_file2);
fclose(ptr_file2);
}
}
答案 1 :(得分:2)
您的问题是一些与您密谋合作的一对一和类似的逻辑错误。让我们看一下主循环中的if
语句,看看有什么问题:
if(strlen(buf) < 10){
numberSpaces = 10 - strlen(buf)-1;
memset(buf, 'x', numberSpaces);
buf[strlen(buf)+numberSpaces] = '\0';
ptr_file2 = fopen("newAnimal.txt", "a");
fputs(buf, ptr_file2);
fclose(ptr_file2);
}
首先要记住fgets会存储换行符,因此buf会有一个额外的换行符。这将增加长度(从strlen)到1.所以我们必须调整:
if (strlen(buf) < 11) {
numberSpaces = 10 - (strlen(buf)-1); // otherwise - is done from the total, not from strlen
memset(buf, 'x', numberSpaces); // still wrong...
buf[strlen(buf)+numberSpaces] = '\0'; // still wrong...
// fopen/fclose EVERY loop is terribly inefficient, but not wrong per se
ptr_file2 = fopen("newAnimal.txt", "a");
fputs(buf, ptr_file2);
fclose(ptr_file2);
}
现在我们需要修复memset bufset问题,因为我们不想用'x'来设置字符串的开头,而是结束。同样地,我们不想以'\ 0'结束,我们想要'\ n \ 0'。我们也想在最后立即抛出,而不是在额外的数字空间等待之后......
if (strlen(buf) < 11) {
numberSpaces = 10 - (strlen(buf)-1);
memset(buf + (strlen(buf)-1), 'x', numberSpaces); // now it will start from the correct spot
buf[10] = '\n'; // we know how long we want our string to be ;)
buf[11] = '\0';
// fopen/fputs/fclose here (or outside the loop if you can)
}
最后要注意的一点是:在开始使用缓冲区之前,应确保缓冲区已填充为0 ...只需将char buf[1000];
行转换为char buf[1000] = {0};
即可。
另一个更优雅的解决方案是,仅在适用时通过buf[strcspn(buf, "\n")] = '\0';
使用strcspn删除换行符。 strcspn
不是一个众所周知的函数,但它会搜索所提供的字符并返回第一次出现的索引。它还会考虑'\ 0',所以如果它什么也找不到,它将返回字符串的长度。在校正换行符之后,您不再需要从所有strlen调用中减去1。
答案 2 :(得分:2)
还有第三个产品......请注意这里的内容,但选择其中一个作为接受的答案。
#include <stdio.h>
#include <string.h>
static int filterWords(const char *ifile, const char *ofile)
{
FILE *ptr_file1 = fopen(ifile, "r");
if (!ptr_file1)
{
fprintf(stderr, "Failed to open file %s for reading\n", ifile);
return 1;
}
FILE *ptr_file2 = fopen(ofile, "w");
if (!ptr_file2)
{
fprintf(stderr, "Failed to open file %s for writing\n", ofile);
fclose(ptr_file1);
return 1;
}
char buf[1000];
while (fgets(buf, sizeof(buf), ptr_file1) != NULL)
{
buf[strcspn(buf, "\n")] = '\0';
int len = strlen(buf);
if (len < 10)
{
memset(buf + len, 'x', 10 - len);
buf[10] = '\0';
}
fprintf(ptr_file2, "%s\n", buf);
}
fclose(ptr_file1);
fclose(ptr_file2);
return 0;
}
int main(void)
{
printf("Status: %d\n", filterWords("animals.txt", "newAnimal.txt"));
return 0;
}
注意:
ptr_file
和ptr_file2
之间的(常见)不对称令人讨厌;我使用ptr_file
作为一个,但在我需要这两个名字时使用ptr_file1
和ptr_file2
。实际上,对于文件指针,我通常使用fp1
和fp2
或ifp
和ofp
,但这次我更接近原始代码。buf[strcspn(buf, "\n")] = '\0';
表示法来安全地删除缓冲区中的第一个(也是唯一的)换行符。memset()
将尾随部分设置为x
并添加一个空字节。三次重复的10
应该是一个命名常量,例如:
enum { PAD_LENGTH = 10 };
代码打开辅助文件一次,并将所有名称(即使那些不需要填充的名称)写入文件。
ferror()
来检测输入上的错误。getline()
来读取该行。一个很大的优点是它返回行中的字符数,因此您不必以相同的方式搜索换行符(尽管需要担心没有尾随换行符的文件的最后一行)。 / LI>
输入:
dog
bear
panda
fish
elephant
alligator
rhinoceros
hippopotamus
East African Lion
输出:
dogxxxxxxx
bearxxxxxx
pandaxxxxx
fishxxxxxx
elephantxx
alligatorx
rhinoceros
hippopotamus
East African Lion
答案 3 :(得分:0)
下面的代码将解决您的问题:
int filterWords(void)
{
FILE *ptr_file;
FILE *ptr_file2;
char buf[1000];
int strLen = 0;
int numberSpaces;
ptr_file = fopen("animals.txt","r");
if (!ptr_file)
return 1;
while (fgets(buf, 1000, ptr_file)!=NULL)
{
strLen = strlen(buf) - 1;
if(strLen < 10){
numberSpaces = 10 - (strLen);
memset(&buf[strLen], 'x', numberSpaces);
buf[strLen + numberSpaces] = '\n';
buf[strLen + numberSpaces + 1] = '\0';
ptr_file2 = fopen("newAnimal.txt", "a");
fputs(buf, ptr_file2);
fclose(ptr_file2);
}
}
fclose(ptr_file);
return 0;
}