在C程序中我写作时我必须从文本文件中读取值并将它们放在一个数组中供以后使用。
我不喜欢我的代码(下面显示的代码段),因为我做了两个while
循环,第一个计算值的数量,然后创建一个与该值一样大的数组,最后我再次读取文件,填充数组。
此外,在第一个循环中,我使用变量x
,因为fscanf()
需要它,但我以后从未在代码中使用它,我想完全避免使用它如果可能的话。
int x, n=0, sum=0;
fp=fopen("data.txt", "r");
while(fscanf(fp,"%d\n",&x)!=EOF){
n++;
}
rewind(fp);
int v[n];
while(fscanf(fp,"%d\n",&v[i])!=EOF){
sum+=v[i];
i++;
}
那么,有关如何改进此代码的任何建议?我想我可能有点"修复"它通过声明一个大的"足够的"在开始时根据需要填写。但我事先并不知道我有多少价值,所以我决定废弃这种方法。
答案 0 :(得分:3)
这是动态内存分配可以派上用场的一种方案。您可以按照以下描述的一般程序进行操作
fopen()
并阅读文件fscanf()
中的第一个元素。还应该注意错误检查。malloc()
分配给指针并复制值。阅读下一个元素。
4.1。如果读取成功
如果读取成功,请使用一个新元素大小重新分配内存realloc()
。
将最后读取的值复制到新分配的内存中。
4.2。如果读取ID失败,请检查EOF并停止读取。
继续执行第4步。
另外,请记住,使用动态内存分配分配的内存也需要free()
d。
作为 @ szczurcio 先生的referring to the comment注意事项,这不是优化的努力,因为您在每次成功时重新分配内存读。为了最小化动态内存分配的影响,我们可以决定一个阈值,我们将用它来分配内存,然后,当用尽时,将使前一个值的两倍加倍。这样,分配将在块中发生,并且可以避免每个读取周期中的分配开销。功能
答案 1 :(得分:1)
对代码稍作修改,请注意我已将v更改为int *,然后检查文件中的回车量。然后我为数组分配正确的内存量,倒回文件,然后让你的代码再次遍历文件...
int x, n=0, sum=0;
char c;
int* v;
int i = 0;
fp=fopen("data.txt", "r");
while (f.get(c))
if (c == '\n')
++i;
rewind(fp);
v = malloc( i * sizeof( int ));
i = 0;
while(fscanf(fp,"%d\n",&v[i])!=EOF)
{
sum+=v[i];
i++;
}
答案 2 :(得分:0)
正如Sourav所说,动态内存分配绝对是可行的方法。
也就是说,您也可以将数据结构更改为另一个不需要N先验知识的结构。如果您只需要对值进行顺序访问而不需要随机访问,则链接列表是一个选项。而且,您始终可以使用二叉树,哈希表等。取决于您想要对数据做什么。
P.S:srry,我发布此评论作为评论,但我没有声誉。答案 3 :(得分:0)
这是您希望在创建阵列之前知道文件大小的典型方案。好吧,更好的说,文件中的行数。
我要提出一些根本不同的东西。由于这是一个文本文件,最小的数字将占用两个字符(在“文本”意义上最小),一个用于数字,另一个用于\n
(尽管\n
可以是一个或两个字节,这取决于操作系统。)
我们现在可以查看文件的大小。在fopen
之后,您可以通过ftell
知道它拥有多少字节。如果将该数除以2,则将得到文件中最大可能行数的近似值。因此,您可以创建该大小的数组,然后保存真正占用的位置数。
FILE * fp = fopen( "data.txt", "rt" );
/* Get file size */
fseek( fp, SEEK_END, 0 );
long size = ftell( fp );
fseek( fp, SEEK_SET, 0 );
/* Create data */
long MaxNumbers = size / 2;
int * data = (int *) malloc( sizeof( int ) * MaxNumbers );
long lastPos = 0;
/* Read file */
int * next = data;
while( fscanf(fp, "%d\n", next) != EOF ) {
++next;
}
lastPos = ( next - data ) / sizeof( int );
/* Close the file */
fclose( fp );
在data
中加载数据后,您就知道了实际的项目数,因此您可以将其复制到另一个具有确切大小的数组(可能通过memcpy()
),或者保留此项阵列。如果要更改数组:
int * v = (int *) malloc( sizeof( int ) * lastPos );
memcpy( v, data, sizeof( int ) * lastPos );
free( data );
注意:这段代码是一个简单的演示,在调用malloc()
后它不会检查NULL,而真正的程序应该。
由于数据不适合,此代码在扩展阵列时不会浪费内存或计算时间。但是,它a)在开头创建一个可能比需要的更大的数组,并且b)如果你想拥有一个确切大小的数组,那么你将暂时分配两倍所需的空间。我们正在改变内存以获得更好的性能,有时这对我们的环境(即嵌入式系统)来说并不是一个好主意。
这种策略的一个重大改进是能够处理输入文件。如果你为每个数字指定相同的空格(假设总有三个位置,并且3存储为003),并且你知道最大数量(为了知道每个数字需要多少空格),那么算法将完全准确,您不需要将读取的数据更改为另一个数组或其他任何数组。有了这个改变,这个策略就是我能想象到的最好的策略。
希望这有帮助。