2015-11-30 2 views
-2

У меня есть текстовый файл с заданным форматом:чтение форматированный текстовый файл в массив

2078.62  5.69982  -0.17815  -0.04732 
5234.95  8.40361  0.04028  0.10852 
2143.66  5.35245  0.10747  -0.11584 
7216.99  2.93732  -0.18327  -0.20545 
1687.24  3.37211  0.14195  -0.14865 
2065.23  34.0188   0.1828  0.21199 
2664.57  2.91035  0.19513  0.35112 
7815.15  9.48227  -0.11522  0.19523 
5166.16  5.12382  -0.29997  -0.40592 
6777.11  5.53529  -0.37287  -0.43299 
4596.48  1.51918  -0.33986  0.09597 
6720.56  15.4161  -0.00158  -0.0433 
2652.65  5.51849  0.41896  -0.61039 

Я написал следующие функции для чтения файла

Прочитайте количество строк

unsigned int getnumline(const char *sn){ 
    unsigned int n; 
    char lcstring[LCLENGTH]; 
    FILE *lcpipe; 
    char buff[512]; 
    snprintf(lcstring, LCLENGTH, 
     "wc -l %s | cut -d ' ' -f1", sn); 
    lcpipe = popen(lcstring, "r"); 
    if (lcpipe == NULL) 
    exit_failure("popen: "); 

    while(fgets(buff, sizeof(buff), lcpipe)!=NULL){ 
     n=atoi(buff); 
    } 
    pclose(lcpipe); 
    printf("Number of lines in the input file: %d\n", n); 
    return n; 
} 

Прочитайте текстовый файл

double **callocmatrix(unsigned int m, unsigned int n) { 

    double **matrix; 
    unsigned int i; 

    matrix = (double **)calloc(m, sizeof(double *)); 
    if (!matrix) 
    return NULL; 

    matrix[0] = (double *)calloc(m*n, sizeof(double)); 
    if (!matrix[0]) 
    return NULL; 

    for (i = 1; i < m; i += 1) 
    matrix[i] = matrix[i-1] + n; 

    return matrix; 
} 

void freematrix(double **matrix) { 

    free((void *)matrix[0]); 
} 



double **ellcat; 
ngal = getnumline(sname); 
ellcat = callocmatrix(ngal, 4); 
void readcat(double **ellcat, unsigned int catlen, const char *sn) { 
    unsigned int i;  
    FILE *fp=fopen(sn,"r"); 
    if(fp == NULL) 
     { 
     printf("Error in opening file\n"); 
     exit(0); 
     }   
    for (i=0 ; i< catlen ; i++) 
    {   
     fscanf(fp, "%lf %lf %lf %lf", &ellcat[i][0], &ellcat[i][1], &ellcat[i][2], &ellcat[i][3]);   
    }  
    for (i=0 ; i< catlen ; i++) 
    { 
     printf("x = %lf, y = %lf, e1 = %lf, e2 = %lf\n", &ellcat[i][0], &ellcat[i][1], &ellcat[i][2], &ellcat[i][3]); 
    } 
    fclose(fp); 
} 

Но ellcat компоненты пустые

x = 0.000000, y = 0.000000, e1 = 0.000000, e2 = 0.000000 
x = 0.000000, y = 0.000000, e1 = 0.000000, e2 = 0.000000 
x = 0.000000, y = 0.000000, e1 = 0.000000, e2 = 0.000000 
x = 0.000000, y = 0.000000, e1 = 0.000000, e2 = 0.000000 
x = 0.000000, y = 0.000000, e1 = 0.000000, e2 = 0.000000 
x = 0.000000, y = 0.000000, e1 = 0.000000, e2 = 0.000000 
x = 0.000000, y = 0.000000, e1 = 0.000000, e2 = 0.000000 
x = 0.000000, y = 0.000000, e1 = 0.000000, e2 = 0.000000 
x = 0.000000, y = 0.000000, e1 = 0.000000, e2 = 0.000000 
x = 0.000000, y = 0.000000, e1 = 0.000000, e2 = 0.000000 

Я не могу понять, что проблема с моей readcat функции.

P.S. Должен упомянуть, что я новичок в отношении языка C.

+0

Начните поиск результата, возвращенного 'fscanf': он вернет количество элементов, которые будут правильно прочитаны. – Evert

+0

Просьба представить декларацию и инициализацию 'ellcat' в вашем вопросе. – Evert

+0

@Evert Я получаю 'catlen', используя функцию' getnumline'. – Dalek

ответ

1

Если не требуется, чтобы вы заранее прочитать, чтобы определить количество строк в файле перед выделением пространства/читая значения в вашем массиве, нет причин для этого. Вы можете легко считывать значения из своего файла, выделять пространство для их хранения и отслеживать количество строк данных, считанных в одном цикле функций/чтения. Фактически, вы делаете это довольно легко, указав указатель на тип (двойной указатель) в качестве своего типа данных.

Обычный подход в вашей ситуации состоит в том, чтобы выделить память для некоторого разумно ожидаемого количества строк (указателей), а затем читать/выделять пространство для каждой строки данных до тех пор, пока вы не достигнете этого первоначального предела, а затем до realloc дополнительных указателей как требуется для чтения всего файла в массив указателей на массив парных чисел. Счет строки передается аргументом указателя на функцию и обновляется внутри функции, что делает общее количество строк доступным в вызывающей функции (main() здесь).

Пример одной функции, которая будет отвечать вашим требованиям будет:

/* read rows in filename 'fn' that consist of 4 whitespace 
* separated double values into the dynamically allocated 
* array of pointer to array of 4 doubles 'ar', updating the 
* size_t value 'nrows' with the number of rows of data read. 
* returns pointer to allocated array on success, NULL otherwise 
*/ 
double **readcat (double ***ar, size_t *nrow, const char *fn) 
{ 
    double tmp[4] = {0.0};     /* tmp array for values */ 
    FILE *fp = fn ? fopen (fn, "r") : stdin; /* read from fn or stdin */ 
    if (!fp) { 
     fprintf (stderr, "readcat() error: file open failed '%s'.\n", fn); 
     return NULL; 
    } 

    /* allocate MAXR pointers to double* */ 
    if (!(*ar = calloc (MAXR, sizeof **ar))) { 
     fprintf (stderr, "readcat() error: virtual memory exhausted.\n"); 
     return NULL; 
    } 

    *nrow = 0; /* set index to 0, read each row in file */ 
    while (fscanf (fp, "%lf %lf %lf %lf", 
       &tmp[0], &tmp[1], &tmp[2], &tmp[3]) == 4) { 

     /* 4 values read, allocate memory in *ar */ 
     if (!((*ar)[*nrow] = calloc (4, sizeof ***ar))) { 
      fprintf (stderr, "readcat() error: virtual memory exhausted.\n"); 
      return NULL; 
     } 
     /* copy values to *ar */ 
     memcpy ((*ar)[*nrow], tmp, sizeof tmp); 
     (*nrow)++; /* increment row index */ 

     if (*nrow == MAXR) { /* test rows againt max (break/realloc) */ 
      fprintf (stderr, "readcat() warning: MAXR rows read.\n"); 
      break; 
     } 
    } 

    if (fp != stdin) fclose (fp); /* close file */ 

    return *ar; 
} 

Обратите внимание, коды Перераспределения опущены выше, и цикл чтения вышло, если максимальное количество указателей (линии) MAXR достигается , Также обратите внимание, что, возвращая указатель, вы можете не только проверить успех/неудачу на основе возврата, но также можете назначить возврат указателю.

Короткая программа драйвера использования функции с вашими данными будет:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#define MAXR 64 

double **readcat (double ***ar, size_t *nrow, const char *fn); 

int main (int argc, char **argv) { 

    size_t i, n = 0; 
    double **ellcat = NULL; 
    char *filename = argc > 1 ? argv[1] : NULL; 

    ellcat = readcat (&ellcat, &n, filename); 

    if (!ellcat) { /* validate address returned by readcat */ 
     fprintf (stderr, "error: readcat returned no values.\n"); 
     exit (EXIT_FAILURE); 
    } 

    printf ("\n %zu rows of data read:\n\n", n); 
    for (i = 0; i < n; i++) /* print each row of data */ 
     printf (" %8.2lf %8.5lf %8.5lf %8.5lf\n", 
       ellcat[i][0], ellcat[i][1], ellcat[i][2], ellcat[i][3]); 
    putchar ('\n'); 

    for (i = 0; i < n; i++) /* free all allocated memory */ 
     free (ellcat[i]); 
    free (ellcat); 

    return 0; 
} 

Использование/выход

$ ./bin/fscanf_4col_dyn dat/float_4col.txt 

13 rows of data read: 

    2078.62 5.69982 -0.17815 -0.04732 
    5234.95 8.40361 0.04028 0.10852 
    2143.66 5.35245 0.10747 -0.11584 
    7216.99 2.93732 -0.18327 -0.20545 
    1687.24 3.37211 0.14195 -0.14865 
    2065.23 34.01880 0.18280 0.21199 
    2664.57 2.91035 0.19513 0.35112 
    7815.15 9.48227 -0.11522 0.19523 
    5166.16 5.12382 -0.29997 -0.40592 
    6777.11 5.53529 -0.37287 -0.43299 
    4596.48 1.51918 -0.33986 0.09597 
    6720.56 15.41610 -0.00158 -0.04330 
    2652.65 5.51849 0.41896 -0.61039 

Ошибка памяти/Leak Проверить

В любой код, который вы пишете, который динамически распределяет память, у вас есть 2 ответа относительно любого b блокировка выделенной памяти: (1) всегда сохраняет указатель на начальный адрес для блока памяти, поэтому (2) он может быть освобожден, когда он больше не нужен. Крайне важно, чтобы вы использовали программу проверки ошибок памяти, чтобы убедиться, что вы не писали за пределами вашего выделенного блока памяти и не подтверждали, что освободили всю выделенную память. Для Linux valgrind это обычный выбор. Есть так много тонких способов злоупотребления блоком памяти, который может вызвать реальные проблемы, нет оправдания, чтобы не делать этого. Для каждой платформы есть аналогичные проверки памяти. Все они просты в использовании. Просто запустите свою программу.

$ valgrind ./bin/fscanf_4col_dyn dat/float_4col.txt 
==21392== Memcheck, a memory error detector 
==21392== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. 
==21392== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info 
==21392== Command: ./bin/fscanf_4col_dyn dat/float_4col.txt 
==21392== 

13 rows of data read: 

    2078.62 5.69982 -0.17815 -0.04732 
<snip> 
    2652.65 5.51849 0.41896 -0.61039 

==21392== 
==21392== HEAP SUMMARY: 
==21392==  in use at exit: 0 bytes in 0 blocks 
==21392== total heap usage: 15 allocs, 15 frees, 1,496 bytes allocated 
==21392== 
==21392== All heap blocks were freed -- no leaks are possible 
==21392== 
==21392== For counts of detected and suppressed errors, rerun with: -v 
==21392== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2) 
1

При печати значения, в printf -

printf("x = %lf, y = %lf, e1 = %lf, e2 = %lf\n", 
     &ellcat[i][0], &ellcat[i][1], &ellcat[i][2], &ellcat[i][3]); 
     ^   ^   ^   ^ 

Вам не нужно передавать адреса переменных. Просто передай их. Удалите оператор &.

2

Во-первых, использование внешней программы для подсчета количества строк немного неудобно. Было бы более эффективным (с участием меньше кода, и меньше системных ресурсов) просто подсчитать количество новых строк в файле:

size_t get_newline_count(char const *f) { 
    size_t newline_count = 0; 
    FILE *fd = fopen(f, "r"); 
    if (!fd) { 
     return 0; 
    } 
    int c; 
    do { 
     c = fgetc(fd); 
     newline_count += (c == '\n'); 
    } while (c >= 0); 
    fclose(fd); 
    return newline_count; 
} 

unsigned int n; 
... 
printf("Number of lines in the input file: %d\n", n); 

Возвращаемый тип функции, которую я написал выше является size_t , поэтому вы хотите использовать спецификатор формата %zu для его печати. Когда тип, который вы хотите распечатать, - unsigned int (как в вашем коде), используйте %u; если вы указали неверный тип аргумента (%d соответствует int), поведение не определено.

fscanf(fp, "%lf %lf %lf %lf", &ellcat[i][0], &ellcat[i][1], &ellcat[i][2], &ellcat[i][3]); 

будущее примечание: Это ваша ответственность, чтобы дать нам полное MCVE, что компилирует и воспроизводит эту проблему без заполнения каких-либо бланков.

Вы не дали нам декларацию для ellcat, поэтому мы можем только предположить, что вы, возможно, дали неправильный тип (поскольку вы сделали именно это выше). ellcat должен иметь два уровня косвенности, ссылаясь на double, чтобы этот код был правильным.

printf("x = %lf, y = %lf, e1 = %lf, e2 = %lf\n", &ellcat[i][0], &ellcat[i][1], &ellcat[i][2], &ellcat[i][3]) 

Наконец, как еще один ответ указал, при использовании printf для печати double (или float, тем l в %lf является излишним в данном случае из-за продвижения по умолчанию на double), «Вам не нужно проходить адрес переменных "... Действительно, вы не должны передать адрес, потому что это означает, что вы предоставляете неверный тип, что является неопределенным поведением, как мы рассмотрели ранее.

+0

Я объявил 'ellcat'. Спасибо за ваш ответ, но я изменяю чей-то код, и я знаю очень простой материал о 'c', поэтому, я думаю, я не заслуживаю' -2'. – Dalek

+0

@ Далек NMDV, но -2 ссылается на сообщение, а не на вас. Это удивительно, что ваш компилятор не предупреждал о 'printf (« x =% lf, y ... », & ellcat [i] [0],'. Предложите проверить свои настройки предупреждения компилятора, чтобы включить это базовое предупреждение или, возможно, попробовать новый компилятор. – chux

+0

@Dalek. Вы предоставили все еще не MCVE. Вам нужно убедиться, что ваш тестовый файл ** компилируется **, без необходимости заполнять любые пробелы и ** воспроизводит ** симптом проблемы, если мы не будем угадывать, что входной сигнал или другие факторы, которые вызывают проблемный симптом. Как бы то ни было, у вас явно отсутствует «основная», которую вы могли бы легко включить, обернув код примера с помощью «основной» подписи (это легко, но опять же, это это * ваша * работа, чтобы сообщить о вашей проблеме с нами, если вы хотите помочь ей) ... и нам не хватает 'callocmatrix'. – Sebivor

0

Вам не нужно давать адрес во время печати, измените его

printf("x = %lf, y = %lf, e1 = %lf, e2 = %lf\n",ellcat[i][0],ellcat[i][1],ellcat[i][2],ellcat[i][3]); 
Смежные вопросы