2015-02-11 2 views
-1

Я искал и искал решение этого вопроса, могу найти множество ответов о многомерных массивах int, float, double, но no char *. Я думаю, что я понимаю принципы указателей, знаю разницу между char, char * и char [] и т. Д., Но указатель на 2D-массив указателей на символы стал лучше меня. Я пытаюсь разобрать файл csv и заполнить свой 2D-массив строками (char *). Вот мой код:Прочитайте файл csv строк в 2D char * array, используя C

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

#define COLS 10 
#define ROWS 1000 

int main (void) { 
     char***myarray; 
     FILE *fp; 
     char charTemp[100]; 
     char *varTemp = NULL; 
     char *strTemp = NULL; 
     int i, j; 

     // allocate memory to hold array ROWS 
     if ((myarray = (char***) malloc(ROWS * sizeof(char**))) == NULL) 
      return -1; 

     // then allocate memory to hold array COLS 
     for (i = 0; i < ROWS; i++) 
     { 
      if ((myarray[i] = (char**) malloc(COLS * sizeof(char**))) == NULL) 
       return -2; 
     } 

     // read file 
     if ((fp = fopen ("myfile.csv", "r")) == NULL) 
      return -3; 

     // parse and fill 'myarray' 
     i = 0; 
     j = 0; 

     while (!feof(fp) && fgets(charTemp, sizeof charTemp, fp)) { 
       strTemp = strtok(charTemp, ","); 
       while (strTemp != NULL) { 
        sscanf(strTemp, "%s", &varTemp); 
        myarray[i][j] = varTemp; 
        printf("%s ", myarray[i][j]); 
        j++; 
        if (j > COLS - 1) 
         j = 0; 
        strTemp = strtok(NULL, ","); 
       } 
       printf("\n"); 
       i++; 
      } 
     return 0; 
} 

myfile.csv выглядит примерно так:

ABCD,1,0.2,0.5,0,A123,ZZ,1,120,1 
BCDE,1.038,0,0.525,0,B321,YY,1.25,100,0.7 
CDEF,1,0.2,0.5,0,C3P0,XX,1,120,1 
DEFG,,,,,,,,, 
EFGH,1,0.3,0.8,0,R2D2,WW,1.25,120,1 
FGHI,,,,,,,,, 
etc..... 

Я знаю, некоторые из них Интс и плавает т.д., но я хочу, чтобы они все идти как полукокса *, то я могу atoi или что-то еще, когда мне нужно их использовать.

Печать предназначена только для просмотра того, что я загрузил для тестирования. Если я использую токен%. * S, он отображает, если я использую% s, он segfaults на линии printf. Я предполагаю, что это означает, что я пропускаю нулевые указатели в конце моих строк?

Отладка предполагает, что varTemp использует память за пределами границ. Кроме того, при использовании printf с %.*s в строках без данных после первого ключа он печатает COL 0 в позиции COL 1, где должен быть указатель NULL. то есть:

ABCD 1 0.2 0.5 0 A123 ZZ 1 120 1 
BCDE 1.038 0 0.525 0 B321 YY 1.25 100 0.7 
CDEF 1 0.2 0.5 0 C3P0 XX 1 120 1 
DEFG DEFG 
EFGH 1 0.3 0.8 0 R2D2 WW 1.25 120 1 
FGHI FGHI 
etc..... 

Я смущен, любые идеи ?!

+0

'char *** myarray;' ... нет, я не трехзвездный программист. Я также смущен :-) –

+1

Для начала, [в C вы не должны накладывать результат 'malloc'] (http://stackoverflow.com/questions/605845/do-i-cast-the-result- из-таНоса). Чтобы продолжить, взгляните на второй цикл, выделяющий память, и * что * он выделяет. Тогда поймите, что все указатели 'myarray [i] [j]', которые вы устанавливаете, устанавливаются одинаково. –

+1

О, и вам не нужно '! Feof (fp)' проверить условие цикла, 'fgets' вернет' NULL', если вы нажмете конец файла и выйдете из цикла * перед * 'feof (fp)' возвращает true. –

ответ

2

Вы никогда не выделить место для varTemp, вам нужно пространство для scanf() й строки должны быть сохранены, так что вы могли бы попробовать это

char varTemp[100]; 

и scanf() таким образом

sscanf(strTemp, "%99s", varTemp); 

, а затем скопировать varTemp строка в массив malloc() ing, а затем strcpy() ing.

Причина, по которой необходимо скопировать строку, потому что вы будете переписывать его на последующих вызовах sscanf() так скопировать его и использовать varTemp в качестве буфера для хранения строки scanf() ред.

Также Don't cast malloc(), и это !feof(fp) проверка в цикле while является излишним, он никогда не будет так, потому что, когда вы дойдете до конца файла fgets() вернет NULL, а затем после этого feof() будет правдой, так что он никогда не оценивали при это вернет истину.

Это не имеет значения в данном случае, потому что sizeof(char *) == sizeof(char **) но, как правило, вы должны malloc() с одной звездой меньше, чем у указателя вы malloc() ИНГ для, так

if ((myarray[i] = malloc(COLS * sizeof(char *))) == NULL) 

будет легче понять , а также при отказе вы просто возвращаетесь с main(), не освобождая ранее выделенные указатели.

Наконец, если COLS и ROWS имеют фиксированные значения нет абсолютно никакой необходимости в malloc(), если ваш массив не будет изменен позже, или они являются слишком большими для стека, чтобы держать их.

char *varTemp является указателем, для того, чтобы иметь силу, она должна указать куда-то, вы можете сделать это где-то указать, потребовав somewher от ОС через malloc(), как

char *varTemp; 
varTemp = malloc(NumberOfBytesIWant); 
if (varTemp == NULL) 
    ohNo_TheSystemDidNotGiveMeMemory_PerhapsThereIsNoMemoryLeft_IShouldNotContinue(); 
/* now varTemp is accessible and you are allowed to write NumberOfBytesIWant 
* into it. But you must remember to calll 'free(varTemp)' later when you no 
* longer need the data. 
*/ 

I'ts не единственный способ вы можете сделать это где-то, таким образом вы можете динамически выделять пространство, и это очень часто является подходящим решением, когда вы узнали, сколько байтов вам нужно, а затем просто попросите эту сумму, ничего больше и не меньше, но это также Работа

char array[100]; 
char *varTemp; 

varTemp = array; 

массивы в c-распадке для указателей, поэтому приведенное выше действие и в этом примере также доступно varTemp, и вы можете, например, sscanf(sourceString, "%99s", varTemp);.

Но если вы не указываете на какой-либо действительный адрес памяти с указателем, попытка доступа к нему - неопределенное поведение, так как это не определено, на которое указывает указатель.

+0

Спасибо iharob, очень информативный. Для пояснения, почему char * varTemp не подходит, а char varTemp [100] требуется? Требует ли sscanf массив символов для использования в качестве буфера, а не для связанного списка? – Charlton

+0

@ user4554380 Думаю, теперь я ясно дал понять, если бы я не угодил, дайте мне знать. –