2016-05-13 12 views
0

Ich habe versucht, einen Code zum Lesen einer CSV-Datei und einen Wert ändern, indem Sie Zeile und Spalte. In der ersten lese ich die Datei, um zu überprüfen, wie viele Zeilen und Spalten dort oben sind, und dann erstelle ich ein dynamisches 2D-Array - jede Zeile ist die Zeile in der Datei. tatsächlich machen Sie die Datei in 2D-Array. und dann werde ich den Wert der gewählten Zeile und Spalte ändern und das ganze Array zurück in die Datei schreiben. weiß jemand, warum es abgestürzt ist? es ist abgestürzt in der ersten Zeile von -Einige Code zum Lesen .csv-Datei abgestürzt

bigArr [i] [j] = (char) ch;

die Funktion:

int changeValue(int line, int col, char str[],const char* path) 
{ 
    FILE* csvFile = fopen(path, "r"); 
    char arr[VERY_BIG_MEMORY]; 
    int l = 0, c = 1; 
    int i = 0,j=0; 
    int ch = 0; 
    if (!csvFile) 
    { 
     printf("Cant read the file\nPlease open a file\n"); 
     return -1; 
    } 
    do 
    { 
     ch = fgetc(csvFile); 
     if (ch == ',') 
     { 
      c++; 
     } 
    } while (ch !='\n'); 
    fseek(csvFile, 0L, SEEK_SET); 
    do 
    { 
     ch = fgetc(csvFile); 
     if (ch == '\n') 
     { 
      l++; 
     } 
    } while (ch!=EOF); 
    char** bigArr = (char**)calloc(l*c,sizeof(char*)); 
    for (i = 0; i < l*c; i++) 
    { 
     bigArr[i] = (char*)calloc(10,sizeof(char)); 
    } 
    fseek(csvFile, 0L, SEEK_SET); 
    do 
    { 

     ch = fgetc(csvFile); 
     if (ch == ',') 
     { 
      j++; 
     } 
     else if (ch == '\n') 
     { 
      i++; 
     } 
     else 
     { 
      bigArr[i][j]=(char)ch; 
     } 
    } while (ch != EOF); 
} 
+1

löschen 'char arr [VERY_BIG_MEMORY];' weil es ungenutzt ist. – BLUEPIXY

+1

'char arr [VERY_BIG_MEMORY]': wahrscheinlich nicht das auf dem Stapel zuweisen! Wie groß ist sehr groß? Könnten Sie Ihren Stapel töten? besser auf dem Heap mit 'malloc()' zuzuteilen oder (einfach BLUPIXYs Kommentar lesen), wie er sagt, entfernen Sie es ... – Jimbo

+1

Haben Sie eine Fehlermeldung, um die Ursache einzugrenzen? – Dawcars

Antwort

-1

Sie sich von der arr Array befreien, da es nicht verwendet wird.

Sie überprüfen nicht, ob Sie den BigArr-Speicher ok zugewiesen haben, noch die kleineren Arrays darin.

Außerdem weisen Sie bigArr [i] [j] dem Wert eines Zeichens zu, was nicht korrekt ist - Sie wollen das Array, das Sie in bigArr [i] [j] zugewiesen haben, darauf setzen (und müssen handhaben das Zeichen innerhalb dieses Array anhängt, da Sie Zeichen für Zeichen)

+0

Und jemand kann auf Antwort klicken, die nicht nützlich ist, ohne irgendeinen Grund zu geben – lostbard

2

die Schleife zu lesen sind, die eher wie sollte abstürzt:

enum { MAX_FIELD_WIDTH = 10 }; // Including null terminator 

i = j = 0; 
while ((ch = getc(csvFile)) != EOF) 
{ 
    if (ch == ',' || ch == '\n') 
    { 
     bigArr[i++][j] = '\0'; 
     j = 0; 
    } 
    else 
    { 
     if (j < MAX_FIELD_WIDTH - 1) 
      bigArr[i][j++] = ch; 
     // else ignore excess characters 
} 

Warnung: ungetesteten Code!

Ihr Code erstellt einfach eine lineare Liste von l * c Feldwerten, die in Ordnung ist. Sie können die Felder für die Zeile n auswählen, indem Sie auf die Felder bigArr[n * c] bis bigArr[n * c + c - 1] (gezählt von Zeile 0) zugreifen.

Für wichtige Variablen wie l und c, verwende ich längere Namen wie rows (oder lines) und cols. Immer noch nicht lange, aber sinnvoller. Namen einzelner Zeichen sollten mit begrenztem Umfang verwendet werden.

Beachten Sie, dass dieser Code Feinheiten des CSV-Formats ignoriert, z. B. Felder mit Kommas in doppelten Anführungszeichen, ganz zu schweigen von Zeilenumbrüchen in doppelt zitierten Feldern. Es ignoriert auch die Möglichkeit, die Anzahl der Felder in den Zeilen zu ändern. Wenn der Code die Zeilennummern verfolgen würde, wäre es möglich, sowohl zu viele Felder (Ignorieren des Extra) als auch zu wenige Felder (Erzeugen von leeren Einträgen für fehlende Felder) zu handhaben. Wenn der Code, der die Datei vorab scannt, cleverer ist, könnte er die minimale und maximale Anzahl der Spalten pro Zeile sowie die Anzahl der Zeilen aufzeichnen. Probleme könnten dann auch diagnostiziert werden.

Mit einem komplexeren Speicherverwaltung Schema, es wäre auch möglich, die Datei nur einmal zu scannen, was Vorteile hat, wenn die Datei tatsächlich ein Terminal oder eine Pipe ist, anstatt eine Disk-Datei. Es könnte auch beliebig lange Feldwerte verarbeiten, anstatt sie auf 10 Byte einschließlich des Terminal-Nullbytes zu beschränken.


Der Code sollte überprüfen, dass die Datei geöffnet werden konnte, und schließen, wenn sie fertig ist. Die aktuelle Funktionsschnittstelle lautet:

Die ersten drei Werte werden jedoch vom angezeigten Code ignoriert.Dies liegt wahrscheinlich daran, dass der endgültige Code einen der gelesenen Werte ändert und dann die Datei neu schreibt. Vermutlich würde es einen Fehler melden, wenn Sie aufgefordert werden, eine nicht vorhandene Spalte oder Zeile zu ändern. Diese relativ geringen Fehler sind wahrscheinlich auf die Minimierung zurückzuführen, um den Code einem MCVE (How to create a Minimal, Complete, and Verifiable Example?) zu ähneln.

0

Wenn Ihr Ziel ist es, die Daten und speichern sie in einem char ** Zeiger zu lesen, dann ist dies ein Weg, um es

int 
changeValue(const char *path) 
{ 
    FILE *file; 
    size_t column_count; 
    size_t row_count; 
    int character; 
    char **result; 
    char *field; 
    char large_buffer[100]; 
    size_t length; 
    size_t index; 

    file = fopen(path, "r"); 
    if (file == NULL) 
    { 
     printf("Cant read the file\nPlease open a file\n"); 
     return -1; 
    } 

    /* Count Rows and Columns */ 
    while ((character = fgetc(file)) != EOF) 
    { 
     switch (character) 
     { 
      case ',': 
       ++column_count; 
       break; 
      case '\n': 
       ++row_count; 
       break; 
     } 
    } 
    rewind(file); 

    result = malloc(row_count * column_count * sizeof(char *)); 
    if (result == NULL) 
    { 
     fclose(file); 
     return -1; /* Do something to inform the caller */ 
    } 

    length = 0; 
    index = 0; 
    while ((character = fgetc(file)) != EOF) 
    { 
     switch (character) 
     { 
      case '\n': 
      case ',': 
       field = malloc(length + 1); 
       if (field != NULL) 
       { 
        memcpy(field, large_buffer, length); 
        field[length] = '\0'; 
       } 
       result[index++] = field; 

       length = 0; 
       break; 
      default: 
       if (length < sizeof(large_buffer)) 
        large_buffer[length++] = character; 
       break; 
     } 
    } 
    /* USE THE DATA NOW AND FREE THE POINTERS */ 
    fclose(file); 

    return 0; 
} 

Hinweis zu tun, dass:

  1. Sie Reihen zählen können und Spalten, um das Ziel vorzubelegen, aber Sie können es in einer einzelnen Schleife tun, weil Sie die Datei ein Zeichen zu einem Zeitpunkt lesen.

  2. Sie müssen nicht jeden Zeiger in der char ** Array auf eine feste Größe im Voraus zuweisen, weil das nicht viel Sinn macht, könnte man einfach die feste Größe verwenden, um es so

    vorbelegt
    char (*bigArr)[10] = malloc(sizeof(*bigArr)); 
    

    , sondern in der zweiten Schleife verwendet nur einen Puffer groß genug, um Zeichen eines bis ',' zu halten oder '\n' gefunden wird (Zeichen ignorieren, wenn sie nicht passen, wie Sie in Ihrem Code sowieso würden) und dann die zuteilen Zeiger und kopieren Sie die Daten hinein.

  3. Das eigentliche Problem, wie durch @JonathanLefflerHere in der Antwort darauf hingewiesen, dass Sie so richtig den j Index nicht Zurücksetzen wurden nach den Grenzen des Arrays zu schreiben.