我有一个动态二维浮点数组和一个文件,其中包含字符串,整数(行中浮点数)和浮点数。
M = (float**)malloc(num_lines * sizeof(float));
for(int i = 0; i < num_lines; i++){
M[i] = (float*)malloc(num_columns * sizeof(float));
}
的例子:
2
John 3 5.5 89.5 30.67 0.00
Mary 4 78.9 67.4 67.3 9.0 0.00
(null)
行数是文件上的行数+ 1,列数是最大的整数+ 1(在本例中是5),因为0.00标志着每行的结束。我如何加载只有浮动到内存中?我已经尝试了不同类型的循环与fgets
和strtok
,但它不工作,由于不同类型的变量。
代码如下:
for(int i = 0; i < num_lines; i++){
fgets(buf, 1000, aux);
name = strtok(buf, " ");
col = atoi(strtok(NULL, " "));
for(j = 0; j < num_columns; j++){
M[i][j] = atof(strtok(NULL, " "));
if(M[i][j] == 0.00){
break;
}
}
}
这种解析有点麻烦,但这是一个很好的练习,可以不时地做一下。这是相对容易与scanf
,但scanf
不适合任何东西,除了玩具。(实际上不可能健壮地正确处理任何事情,因为即使是简单的"%d"
格式说明符也会导致某些输入的未定义行为。)除非您愿意读取文件两次以确定列的最大大小,否则您不能预先分配整个数组。相反,我建议这样做:
#include <ctype.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* sample input
2
John 3 5.5 89.5 30.67 0.00
Mary 4 78.9 67.4 67.3 9.0 0.00
*/
FILE * xfopen(const char *, const char *);
void * xmalloc(size_t);
int get_row_count(FILE *in, char **line, size_t *cap, const char *name);
float * parse_line(const char *s, int lc);
int
main(int argc, char **argv)
{
int lc = 0;
char *line = NULL;
size_t cap = 0;
FILE *in = argc > 1 ? xfopen(argv[1], "r") : stdin;
int rows = get_row_count(in, &line, &cap, argv[1]);
float **M = xmalloc(rows * sizeof *M);
for( lc = 0; lc < rows && getline(&line, &cap, in) > 0; lc += 1 ){
M[lc] = parse_line(line, lc + 1);
}
if( lc != rows ){
warnx("invalid input: missing some rows");
}
for( int i = 0; i < lc; i++ ){
float *f = M[i];
for( int j = 0; j < f[0]; j++ ){
printf("%ft", f[j + 1]);
}
putchar('n');
}
}
float *
parse_line(const char *s, int lc)
{
/* Skip the name */
char *end;
while( *s && ! isspace(*s) ){
s += 1;
}
int siz = strtol(s, &end, 10);
if( siz <= 0 || ! isspace(*end) ){
errx(EXIT_FAILURE, "Invalid input on line %d", lc);
}
float *f = xmalloc((1 + siz) * sizeof *f);
f[0] = siz;
for( int i = 1; i < siz + 1; i += 1 ){
f[i] = strtof(end, &end);
}
while( isspace(*end) ){
end += 1;
}
if( *end == ' ' || strcmp(end, "0.00n") ){
errx(EXIT_FAILURE, "Invalid input on line %d", lc);
}
return f;
}
int
get_row_count(FILE *in, char **line, size_t *cap, const char *name)
{
if( getline(line, cap, in) <= 0 ){
if( feof(in) ){
errx(EXIT_FAILURE, "Empty input");
} else {
err(EXIT_FAILURE, "%s", name);
}
}
char *end;
int rows = strtol(*line, &end, 10);
if( rows <= 0 ){
errx(EXIT_FAILURE, "invalid row count: %d", rows);
}
if( *end != 'n' ){
errx(EXIT_FAILURE, "unexpected input on line 1");
}
return rows;
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != ' ' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
void *
xmalloc(size_t s)
{
void *rv = malloc(s);
if( rv == NULL ){
perror("malloc");
exit(EXIT_FAILURE);
}
return rv;
}