将用户输入字符串打印到最小的用户输入文件中
Print the user input strings into a least sized user input files
程序应该读取文件名列表,打开这些文件并将它们的句柄放在结构数组中,然后读取字符串并使用结构数组中包含的句柄将连续的字符串行打印到最小文件。
我的程序将所有行的数据仅放入一个文件,该文件最初是最小的,这是错误的,因为每次将数据打印到文件中时,它都应该是最小的文件。这是我的程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
struct file_t
{
FILE* f;
int size;
}t[5];
void close_file(struct file_t* f) {
if (f == NULL || f->f == NULL) {
}
else {
fclose(f->f);
}
}
int open_file(struct file_t* f, const char* filename) {
if (f == NULL || filename == NULL) {
return 1;
}
FILE* fp;
fp = fopen(filename, "ab");
if (fp == NULL) {
return 2;
}
long int res = ftell(fp);
fclose(fp);
f->size = res;
f->f = fopen(filename, "ab+");
if (fp == NULL) {
return 2;
}
return 0;
}
struct file_t* find_min(const struct file_t* files, int size) {
if (files == NULL || size <= 0) {
return NULL;
}
int x = (files + 0)->size, i = 0, index = 0;
for (i = 0; i < size; i++) {
if ((files + i)->size <= x) {
x = (files + i)->size;
index = i;
}
}
return (struct file_t*)(files + index);
}
int main() {
puts("Input files' names:");
char tab[100];
int num = 0;
while(1==1){
if(fgets(tab, 100, stdin)==NULL||*tab=='\n'){
if (num == 0) {
printf("Couldn't open file");
return 4;
}
break;
}
int index=strlen(tab);
*(tab+index-1)='\x0';
if (strlen(tab) > 30) {
*(tab + 30) = '\x0';
}
if (open_file((t + num), tab) > 0) {
}
else {
num++;
}
}
if (num == 0) {
printf("Couldn't open file");
return 4;
}
char str[1000];
printf("Input text:");
*str = '\x0';
while (fgets(str, 1000, stdin)==NULL||*str!='\n') {
int index=strlen(str);
*(str+index-1)='\x0';
struct file_t* p = find_min(t, num);
fwrite(str, sizeof(char), strlen(str), p->f);
}
for (int i = 0; i < num; i++) {
close_file(t + i);
}
printf("File saved");
return 0;
}
写入文件时,您在哪里更新 file_t-> 大小?
你正在调用这个:
fwrite(str, sizeof(char), strlen(str), p->f);
但是在那之后你应该做 p->size += strlen(str) 来更新它的大小,否则所有的文件大小都被设置为初始值,因此所有的字符串都被写入一个文件。
至于获取垃圾数据,请尝试在 while 循环中打印您正在从 scanf 读取的字符串。
您正在使用 scanf 读取 '\n' 之前的字符,但您没有读取 '\n' 本身。您还需要在该循环中使用 fseek(stdin, 0, SEEK_END);
。
最后,你为什么要使用这样的语法:
(files + i)->size
什么时候可以像这样更干净地调用它:
files[i].size
因此你的代码真的很难读。
您需要解决一些严重错误。
fseek(stdin, 0, SEEK_END)
-- fseek
通常只适用于磁盘文件,或相当类似的东西。请参考这个linkUsing fseek with a file pointer that points to stdin
事实上连fflush()
都不行。 fflush
是为刷新输出流而设计的东西,它对输入流的行为是依赖于实现的。详情请参考此linkstdinflush
scanf("%[^\n]s", tab)
如果您在循环中或多次使用它,只有第一次读取会成功。原因是,\n
字符从先前的输入中被遗漏了,并且如前所述,fflush()
可能无法成功删除 \n
。对 scanf()
的进一步调用将只是 return 而不会读取任何内容。
'[=26=]x'
如果您打算将其用作字符串终止符,则不是。它是一个具有整数值 120
的多字符常量。下面是一个模糊的测试运行
代码
#include <stdio.h>
int main()
{
if ('[=10=]' == '[=10=]x' )
printf("both are same\n");
printf("%d",'[=10=]x');
}
编译警告
test.c: In function ‘main’:
test.c:5:14: warning: multi-character character constant [-Wmultichar]
5 | if ('[=11=]' == '[=11=]x' )
| ^~~~~
test.c:8:14: warning: multi-character character constant [-Wmultichar]
8 | printf("%d",'[=11=]x');
| ^~~~~
输出
120
fseek(fp, 0, SEEK_END); ftell(fp);
-- 这不应用于确定文件大小。在二进制文件的情况下,fseek()
和 SEEK_END
的行为是不确定的。请参考这个linkDo not use fseek() and ftell() to compute the size of a regular file
一些逻辑错误
1) 您应该在 find_min()
中每次计算文件大小,因为每当您向文件写入数据时它都会发生变化。
2) fwrite()
实际上不会立即将数据转储到文件中。你需要打电话给 fflush()
。
解决了以上问题后,这是修改后的代码。
代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#include <sys/stat.h>
struct file_t
{
FILE* f;
int size;
}t[5];
void close_file(struct file_t* f) {
if (f == NULL || f->f == NULL) {
}
else {
fclose(f->f);
}
}
int open_file(struct file_t* f, const char* filename) {
if (f == NULL || filename == NULL) {
return 1;
}
f->f = fopen(filename, "a");
if (f->f == NULL)
return 2;
struct stat statbuf;
fstat(fileno(f->f), &statbuf);
f->size = statbuf.st_size;
return 0;
}
struct file_t* find_min(const struct file_t* files, int size) {
if (files == NULL || size <= 0) {
return NULL;
}
struct stat statbuf;
fstat(fileno(files->f), &statbuf);
int x = statbuf.st_size, i = 0, index = 0;
for (i = 0; i < size; i++) {
fstat(fileno((files+i)->f), &statbuf);
if (statbuf.st_size < x) {
x = statbuf.st_size;
index = i;
}
}
return (struct file_t*)(files + index);
}
int main() {
puts("Input files' names:");
char tab[100];
int num = 0;
while(1){
int c;
while (1) {
c = getc(stdin);
if (c == EOF || c == ' ')
goto user_input;
if(c != '\n')
break;
}
tab[0] = c;
if (scanf("%[^\n]s", tab+1) == EOF)
break;
if (*tab == '[=13=]') {
if (num == 0) {
printf("Couldn't open file");
return 4;
}
break;
}
if (strlen(tab) > 30) {
*(tab + 30) = '[=13=]';
}
if (open_file((t + num), tab) > 0) {
}
else {
num++;
}
*tab = '[=13=]';
}
user_input:
if (num == 0) {
printf("Couldn't open file");
return 4;
}
fflush(stdin);
char str[1000];
printf("Input text:\n");
*str = '[=13=]';
while(1) {
int c;
while(1) {
c = getc(stdin);
if (c == EOF)
goto main_exit;
if (c != '\n')
break;
}
str[0] = c;
if (scanf("%[^\n]s", str+1) == EOF)
break;
struct file_t* p = find_min(t, num);
fwrite(str, sizeof(char), strlen(str), p->f);
fflush(p->f);
}
main_exit:
for (int i = 0; i < num; i++) {
close_file(t + i);
}
printf("File saved");
return 0;
}
终端会话
$ ./a.out
Input files' names:
test file1.txt
test file2.txt
' '(NOTE: Space character inputted before pressing enter.)
Input text:
this is
Whosebug
File saved
测试file1.txt
this is
测试file2.txt
Whosebug
从第一个循环(文件输入)中断的注意事项。您需要输入 space 然后按回车键(您可以对此进行调整)。
程序应该读取文件名列表,打开这些文件并将它们的句柄放在结构数组中,然后读取字符串并使用结构数组中包含的句柄将连续的字符串行打印到最小文件。
我的程序将所有行的数据仅放入一个文件,该文件最初是最小的,这是错误的,因为每次将数据打印到文件中时,它都应该是最小的文件。这是我的程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
struct file_t
{
FILE* f;
int size;
}t[5];
void close_file(struct file_t* f) {
if (f == NULL || f->f == NULL) {
}
else {
fclose(f->f);
}
}
int open_file(struct file_t* f, const char* filename) {
if (f == NULL || filename == NULL) {
return 1;
}
FILE* fp;
fp = fopen(filename, "ab");
if (fp == NULL) {
return 2;
}
long int res = ftell(fp);
fclose(fp);
f->size = res;
f->f = fopen(filename, "ab+");
if (fp == NULL) {
return 2;
}
return 0;
}
struct file_t* find_min(const struct file_t* files, int size) {
if (files == NULL || size <= 0) {
return NULL;
}
int x = (files + 0)->size, i = 0, index = 0;
for (i = 0; i < size; i++) {
if ((files + i)->size <= x) {
x = (files + i)->size;
index = i;
}
}
return (struct file_t*)(files + index);
}
int main() {
puts("Input files' names:");
char tab[100];
int num = 0;
while(1==1){
if(fgets(tab, 100, stdin)==NULL||*tab=='\n'){
if (num == 0) {
printf("Couldn't open file");
return 4;
}
break;
}
int index=strlen(tab);
*(tab+index-1)='\x0';
if (strlen(tab) > 30) {
*(tab + 30) = '\x0';
}
if (open_file((t + num), tab) > 0) {
}
else {
num++;
}
}
if (num == 0) {
printf("Couldn't open file");
return 4;
}
char str[1000];
printf("Input text:");
*str = '\x0';
while (fgets(str, 1000, stdin)==NULL||*str!='\n') {
int index=strlen(str);
*(str+index-1)='\x0';
struct file_t* p = find_min(t, num);
fwrite(str, sizeof(char), strlen(str), p->f);
}
for (int i = 0; i < num; i++) {
close_file(t + i);
}
printf("File saved");
return 0;
}
写入文件时,您在哪里更新 file_t-> 大小? 你正在调用这个:
fwrite(str, sizeof(char), strlen(str), p->f);
但是在那之后你应该做 p->size += strlen(str) 来更新它的大小,否则所有的文件大小都被设置为初始值,因此所有的字符串都被写入一个文件。
至于获取垃圾数据,请尝试在 while 循环中打印您正在从 scanf 读取的字符串。
您正在使用 scanf 读取 '\n' 之前的字符,但您没有读取 '\n' 本身。您还需要在该循环中使用 fseek(stdin, 0, SEEK_END);
。
最后,你为什么要使用这样的语法:
(files + i)->size
什么时候可以像这样更干净地调用它:
files[i].size
因此你的代码真的很难读。
您需要解决一些严重错误。
fseek(stdin, 0, SEEK_END)
--fseek
通常只适用于磁盘文件,或相当类似的东西。请参考这个linkUsing fseek with a file pointer that points to stdin
事实上连fflush()
都不行。 fflush
是为刷新输出流而设计的东西,它对输入流的行为是依赖于实现的。详情请参考此linkstdinflush
scanf("%[^\n]s", tab)
如果您在循环中或多次使用它,只有第一次读取会成功。原因是,\n
字符从先前的输入中被遗漏了,并且如前所述,fflush()
可能无法成功删除 \n
。对 scanf()
的进一步调用将只是 return 而不会读取任何内容。
'[=26=]x'
如果您打算将其用作字符串终止符,则不是。它是一个具有整数值120
的多字符常量。下面是一个模糊的测试运行
代码
#include <stdio.h>
int main()
{
if ('[=10=]' == '[=10=]x' )
printf("both are same\n");
printf("%d",'[=10=]x');
}
编译警告
test.c: In function ‘main’:
test.c:5:14: warning: multi-character character constant [-Wmultichar]
5 | if ('[=11=]' == '[=11=]x' )
| ^~~~~
test.c:8:14: warning: multi-character character constant [-Wmultichar]
8 | printf("%d",'[=11=]x');
| ^~~~~
输出
120
fseek(fp, 0, SEEK_END); ftell(fp);
-- 这不应用于确定文件大小。在二进制文件的情况下,fseek()
和SEEK_END
的行为是不确定的。请参考这个linkDo not use fseek() and ftell() to compute the size of a regular file一些逻辑错误
1) 您应该在 find_min()
中每次计算文件大小,因为每当您向文件写入数据时它都会发生变化。
2) fwrite()
实际上不会立即将数据转储到文件中。你需要打电话给 fflush()
。
解决了以上问题后,这是修改后的代码。
代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#include <sys/stat.h>
struct file_t
{
FILE* f;
int size;
}t[5];
void close_file(struct file_t* f) {
if (f == NULL || f->f == NULL) {
}
else {
fclose(f->f);
}
}
int open_file(struct file_t* f, const char* filename) {
if (f == NULL || filename == NULL) {
return 1;
}
f->f = fopen(filename, "a");
if (f->f == NULL)
return 2;
struct stat statbuf;
fstat(fileno(f->f), &statbuf);
f->size = statbuf.st_size;
return 0;
}
struct file_t* find_min(const struct file_t* files, int size) {
if (files == NULL || size <= 0) {
return NULL;
}
struct stat statbuf;
fstat(fileno(files->f), &statbuf);
int x = statbuf.st_size, i = 0, index = 0;
for (i = 0; i < size; i++) {
fstat(fileno((files+i)->f), &statbuf);
if (statbuf.st_size < x) {
x = statbuf.st_size;
index = i;
}
}
return (struct file_t*)(files + index);
}
int main() {
puts("Input files' names:");
char tab[100];
int num = 0;
while(1){
int c;
while (1) {
c = getc(stdin);
if (c == EOF || c == ' ')
goto user_input;
if(c != '\n')
break;
}
tab[0] = c;
if (scanf("%[^\n]s", tab+1) == EOF)
break;
if (*tab == '[=13=]') {
if (num == 0) {
printf("Couldn't open file");
return 4;
}
break;
}
if (strlen(tab) > 30) {
*(tab + 30) = '[=13=]';
}
if (open_file((t + num), tab) > 0) {
}
else {
num++;
}
*tab = '[=13=]';
}
user_input:
if (num == 0) {
printf("Couldn't open file");
return 4;
}
fflush(stdin);
char str[1000];
printf("Input text:\n");
*str = '[=13=]';
while(1) {
int c;
while(1) {
c = getc(stdin);
if (c == EOF)
goto main_exit;
if (c != '\n')
break;
}
str[0] = c;
if (scanf("%[^\n]s", str+1) == EOF)
break;
struct file_t* p = find_min(t, num);
fwrite(str, sizeof(char), strlen(str), p->f);
fflush(p->f);
}
main_exit:
for (int i = 0; i < num; i++) {
close_file(t + i);
}
printf("File saved");
return 0;
}
终端会话
$ ./a.out
Input files' names:
test file1.txt
test file2.txt
' '(NOTE: Space character inputted before pressing enter.)
Input text:
this is
Whosebug
File saved
测试file1.txt
this is
测试file2.txt
Whosebug
从第一个循环(文件输入)中断的注意事项。您需要输入 space 然后按回车键(您可以对此进行调整)。