使用 fscanf 从文件读取时内存中的随机字符
Random characters from memory when reading from file using fscanf
//create the array from file
char *array[100];
char string[80];
FILE * file;
file = fopen( "file.txt" , "r");
if (file) {
int k = 0;
while (fscanf(file, "%s", string)!=EOF){
array[k] = strdup(string);
k++;
}
fclose(file);
}
//print the history array for debugging
for(int k = 0; k<sizeof(array); k++){
printf("the element at %d is: %s\n", k, array[k]);
}
生成的数组包含内存中的随机字符,这些字符不存在于文件中。有什么办法可以防止这种情况吗?
代码中有两个问题。
首先是您使用 fscanf
读取文件,而不是 fgets
。 fscanf
格式为 "%s"
将从文件中读取一个单词。 fgets
读取一行。
第二个问题是最后一个 for
循环,它使用了 sizeof(array)
。在 32 位机器上,sizeof(array)
是 100*4 = 400。您想要的是计算从文件中读取的行数,然后在 for
循环中使用该计数.
考虑到这一点,下面是我编写代码的方式
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( void )
{
char *array[100];
char string[80];
FILE *fp;
if ( (fp = fopen( "file.txt" , "r")) == NULL )
{
printf( "File not found\n" );
exit( 1 );
}
int count = 0;
while ( fgets( string, sizeof(string), fp ) != NULL )
{
string[strcspn(string,"\n")] = '[=10=]';
if ( count < 100 )
{
array[count] = strdup( string );
count++;
}
}
fclose( fp );
for ( int k = 0; k < count; k++ )
printf( "the element at %d is: %s\n", k, array[k] );
}
行
string[strcspn(string,"\n")] = '[=11=]';
从字符串中删除换行符(如果有)。这是必要的,因为 fgets
将保留换行符。
这段代码中有几个问题...
char *array[100];
char string[80];
到目前为止一切顺利,现在让我们看看这个:
int k = 0;
while (fscanf(file, "%s", string)!=EOF){
array[k] = strdup(string);
k++;
}
这里的问题:
- 你不检查
k
。如果 k
达到 100
,这应该停止
- 检查
EOF
是错误的。其他事情也可能失败。
%s
只会读取下一个空格,可能不是您想要的。
只要有非空白字符,%s
就会读取,因此它 会 溢出你的 string
,给出恶意输入。
正确的版本应该是看起来像这样:
int k = 0;
while (k < 100 && fgets(string, 80, file)){
array[k] = strdup(string);
k++;
}
然后进入下一个有问题的部分:
for(int k = 0; k<sizeof(array); k++){
printf("the element at %d is: %s\n", k, array[k]);
}
sizeof()
为您提供其参数的 字节大小 。一个数组的大小是固定的,不管你实际存储了多少个元素。元素是指针,所以占用1个多字节。
正确版本:
int lines = 0; // nothing read
if (file) {
int k = 0;
while (k < 100 && fgets(string, 80, file)){
array[k] = strdup(string);
k++;
}
fclose(file);
lines = k;
}
for(int k = 0; k<lines; k++){
printf("the element at %d is: %s\n", k, array[k]);
}
如果要阅读文本行,请使用:
fgets(line, sizeof(line), file);
如果一行可以包含 80
个字符,则需要将 line
定义为至少包含 81
个字符的数组——以允许额外的space 用于终止空字符。
char line[81];
您需要存储读取的行数,以便在写出这些行时,您不会尝试写入比读取更多的内容。请确保您阅读的行数不超过 array
能够容纳的行数。
int numLinesRead = 0;
if (file) {
int k = 0;
while (fscanf(file, "%s", string)!=EOF && k < 100 ){
array[k] = strdup(string);
k++;
}
fclose(file);
numLinesRead = k;
}
写的行数不要超过阅读的行数。
for(int k = 0; k<numberOfLinesRead; k++){
printf("the element at %d is: %s\n", k, array[k]);
}
//create the array from file
char *array[100];
char string[80];
FILE * file;
file = fopen( "file.txt" , "r");
if (file) {
int k = 0;
while (fscanf(file, "%s", string)!=EOF){
array[k] = strdup(string);
k++;
}
fclose(file);
}
//print the history array for debugging
for(int k = 0; k<sizeof(array); k++){
printf("the element at %d is: %s\n", k, array[k]);
}
生成的数组包含内存中的随机字符,这些字符不存在于文件中。有什么办法可以防止这种情况吗?
代码中有两个问题。
首先是您使用 fscanf
读取文件,而不是 fgets
。 fscanf
格式为 "%s"
将从文件中读取一个单词。 fgets
读取一行。
第二个问题是最后一个 for
循环,它使用了 sizeof(array)
。在 32 位机器上,sizeof(array)
是 100*4 = 400。您想要的是计算从文件中读取的行数,然后在 for
循环中使用该计数.
考虑到这一点,下面是我编写代码的方式
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( void )
{
char *array[100];
char string[80];
FILE *fp;
if ( (fp = fopen( "file.txt" , "r")) == NULL )
{
printf( "File not found\n" );
exit( 1 );
}
int count = 0;
while ( fgets( string, sizeof(string), fp ) != NULL )
{
string[strcspn(string,"\n")] = '[=10=]';
if ( count < 100 )
{
array[count] = strdup( string );
count++;
}
}
fclose( fp );
for ( int k = 0; k < count; k++ )
printf( "the element at %d is: %s\n", k, array[k] );
}
行
string[strcspn(string,"\n")] = '[=11=]';
从字符串中删除换行符(如果有)。这是必要的,因为 fgets
将保留换行符。
这段代码中有几个问题...
char *array[100];
char string[80];
到目前为止一切顺利,现在让我们看看这个:
int k = 0;
while (fscanf(file, "%s", string)!=EOF){
array[k] = strdup(string);
k++;
}
这里的问题:
- 你不检查
k
。如果k
达到100
,这应该停止
- 检查
EOF
是错误的。其他事情也可能失败。 %s
只会读取下一个空格,可能不是您想要的。
只要有非空白字符,%s
就会读取,因此它 会 溢出你的string
,给出恶意输入。
正确的版本应该是看起来像这样:
int k = 0;
while (k < 100 && fgets(string, 80, file)){
array[k] = strdup(string);
k++;
}
然后进入下一个有问题的部分:
for(int k = 0; k<sizeof(array); k++){
printf("the element at %d is: %s\n", k, array[k]);
}
sizeof()
为您提供其参数的 字节大小 。一个数组的大小是固定的,不管你实际存储了多少个元素。元素是指针,所以占用1个多字节。
正确版本:
int lines = 0; // nothing read
if (file) {
int k = 0;
while (k < 100 && fgets(string, 80, file)){
array[k] = strdup(string);
k++;
}
fclose(file);
lines = k;
}
for(int k = 0; k<lines; k++){
printf("the element at %d is: %s\n", k, array[k]);
}
如果要阅读文本行,请使用:
fgets(line, sizeof(line), file);
如果一行可以包含
80
个字符,则需要将line
定义为至少包含81
个字符的数组——以允许额外的space 用于终止空字符。char line[81];
您需要存储读取的行数,以便在写出这些行时,您不会尝试写入比读取更多的内容。请确保您阅读的行数不超过
array
能够容纳的行数。int numLinesRead = 0; if (file) { int k = 0; while (fscanf(file, "%s", string)!=EOF && k < 100 ){ array[k] = strdup(string); k++; } fclose(file); numLinesRead = k; }
写的行数不要超过阅读的行数。
for(int k = 0; k<numberOfLinesRead; k++){ printf("the element at %d is: %s\n", k, array[k]); }