我正在编写一个程序,该程序必须反转文件的一半。
例如:
输入:abcdefgh
输出:abcdhgfe
因此,这里我的程序来自用户输入,并存储在文件中。使用fseek
得到输入的长度,并创建一个该长度加1的字符数组。在另一个数组中,我以相反的顺序存储输入的后一半。问题是,程序将一些奇怪的字符写入文件。打开文件后,出现错误提示:There was a problem opening the file “filename”. The file you opened has some invalid characters.
。我怎么解决这个问题?
#include <stdio.h>
#include <string.h>
int main() {
int fsize;
char fname[15];
char data[fsize+1];
printf("Enter the name of file you want to create: ");
scanf("%s", fname);
FILE *fp;
fp = fopen(fname, "w+");
printf("Enter data for that file: ");
scanf("%s", data);
fprintf(fp, "%s", data);
fseek(fp, 0L, SEEK_END); // get length of file
fsize = ftell(fp);
fseek(fp, 0L, SEEK_SET); // go back to the beginning of file
int j = 0, m = (fsize / 2) + 1;
char data2[m];
for (int k = fsize - 1; j < k; j++, k--) {
data2[j] = data[k];
}
for (int i = 0; i < fsize / 2; i++) {
printf("%c", data2[i]);
}
printf("\n");
fprintf(fp, "%s", data2);
fclose(fp);
return 0;
}
答案 0 :(得分:4)
第一个错误是char data[fsize+1]
行,因为fsize
尚未初始化。另外,在编译时还不知道数组的大小,因此您应按照in this post所述使用malloc
/ calloc
。对于char data2[m]
行也是如此。
另外,您通常应避免使用scanf
,因为输入的文件名长度超过14个字符会导致缓冲区fname
溢出并导致错误的行为,请参见this post。
答案 1 :(得分:2)
卢卡斯·科斯特勒(Lukas Koestler)在回答中说的话:
在
char data[fsize+1];
fsize 是未知的,因此行为是不确定的,请像对 fname 那样使用固定大小。
始终保护(f)scanf,以限制读取的长度以保留在缓冲区中
而且:
检查打开结果。
避免使用变量数组维,实际上,您不需要 data2 。
坦率地说,我不明白为什么您要在文件中写入以了解输入数据的大小,它是一个字符串,只需使用 strlen
您错过了将数据的前半部分写入文件的操作,并且 data2 不是以空字符结尾的,因此fprintf(fp,"%s",data2);
的行为未定义
您不能正确管理只有1个字符的空数据。
您的程序可以是:
#include <stdio.h>
#include <string.h>
int main()
{
char fname[15];
char data[100];
printf("Enter the name of file you want to create: ");
scanf("%14s", fname);
printf("Enter data for that file: ");
scanf("%99s", data);
size_t sz = strlen(data);
if (sz < 2) {
puts("data too small");
return -1;
}
FILE *fp = fopen(fname, "w+");
if (fp == NULL) {
printf("cannot open %s\n", fname);
return -1;
}
size_t m = sz/2;
size_t i;
for (i = 0; i != m; ++i) {
putchar(data[i]);
fputc(data[i], fp);
}
for (i = sz - 1; i >= m; --i) {
putchar(data[i]);
fputc(data[i], fp);
}
putchar('\n');
fputc('\n', fp);
fclose(fp);
return 0;
}
编译和执行:
pi@raspberrypi:~ $ gcc -g -pedantic -Wextra f.c
pi@raspberrypi:~ $ ./a.out
Enter the name of file you want to create: aze
Enter data for that file: a
data too small
pi@raspberrypi:~ $ ./a.out
Enter the name of file you want to create: aze
Enter data for that file: az
az
pi@raspberrypi:~ $ cat aze
az
pi@raspberrypi:~ $ ./a.out
Enter the name of file you want to create: aze
Enter data for that file: aze
aez
pi@raspberrypi:~ $ cat aze
aez
pi@raspberrypi:~ $ ./a.out
Enter the name of file you want to create: aze
Enter data for that file: azerty
azeytr
pi@raspberrypi:~ $ cat aze
azeytr
pi@raspberrypi:~ $ ./a.out
Enter the name of file you want to create: aze
Enter data for that file: abcdefgh
abcdhgfe
pi@raspberrypi:~ $ cat aze
abcdhgfe
在 valgrind 下执行,请始终使用它
pi@raspberrypi:~ $ valgrind ./a.out
==5321== Memcheck, a memory error detector
==5321== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5321== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5321== Command: ./a.out
==5321==
Enter the name of file you want to create: aze
Enter data for that file: az
az
==5321==
==5321== HEAP SUMMARY:
==5321== in use at exit: 0 bytes in 0 blocks
==5321== total heap usage: 4 allocs, 4 frees, 6,496 bytes allocated
==5321==
==5321== All heap blocks were freed -- no leaks are possible
==5321==
==5321== For counts of detected and suppressed errors, rerun with: -v
==5321== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
pi@raspberrypi:~ $ valgrind ./a.out
==5322== Memcheck, a memory error detector
==5322== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5322== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5322== Command: ./a.out
==5322==
Enter the name of file you want to create: aze
Enter data for that file: azertyu
azeuytr
==5322==
==5322== HEAP SUMMARY:
==5322== in use at exit: 0 bytes in 0 blocks
==5322== total heap usage: 4 allocs, 4 frees, 6,496 bytes allocated
==5322==
==5322== All heap blocks were freed -- no leaks are possible
==5322==
==5322== For counts of detected and suppressed errors, rerun with: -v
==5322== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
pi@raspberrypi:~ $