2016-07-12 13 views
1

Ich versuche, eine Zeichenfolge zu tokenisieren.Adresse außerhalb des Bereichs und Speicherverlust wegen malloc

Es gibt verschiedene Linien, die in einem Eingabefeld (char **)

Am unter Verwendung der folgenden Funktion zu speichern, die verschiedenen Tokens gespeichert werden, die in einem anderen Array erzeugt werden.

int tokenize_string(int max_lines,char *input_lines[max_lines],char **tokens) 
{ 
    char *token; 
    int index,token_index=0; 

    for(index = 0; index < max_lines;++index) 
    { 
     token = strtok(input_lines[index]," "); 

     while(token != NULL) 
     { 
      tokens[token_index] = malloc(sizeof(char*)); 
      tokens[token_index] = token; 
      token = strtok(NULL," "); 
      token_index++; 
     } 
    } 
    return token_index; 
} 

bei der Verwendung von valgrind die unten ist

==25710== Invalid write of size 8 
==25710== at 0x400AA6: tokenize_string (functions.c:28) 
==25710== by 0x400953: main (main.c:29) 
==25710== Address 0x51c3048 is 0 bytes after a block of size 8 alloc'd 
==25710== at 0x4C27A2E: malloc (vg_replace_malloc.c:270) 
==25710== by 0x40091B: main (main.c:25) 
==25710== 
==25710== Invalid write of size 8 
==25710== at 0x400ABA: tokenize_string (functions.c:29) 
==25710== by 0x400953: main (main.c:29) 
==25710== Address 0x51c3048 is 0 bytes after a block of size 8 alloc'd 
==25710== at 0x4C27A2E: malloc (vg_replace_malloc.c:270) 
==25710== by 0x40091B: main (main.c:25) 

Ich weiß, gezeigt, dass das Problem mit malloc und der for Schleife ist.

// EDIT

int main(int argc,char *argv[]) 
{ 
    int max_lines = atoi(argv[1]); 
    char *input_lines[max_lines]; 
    char **tokens; 
    char *output_string; 
    int token_index; 
    tokens=malloc(sizeof(char*)); 

    get_input(max_lines,input_lines); 
    token_index = tokenize_string(max_lines,input_lines,tokens); 
    output_string= concat_string(tokens,output_string,token_index); 
    print_string(output_string); 
} 

void get_input(int max_lines,char *input_lines[max_lines]) 
{ 
    int index; 
    printf("Enter %d lines",max_lines); 

    for(index = 0; index < max_lines;++index) 
    { 
     input_lines[index] = malloc(sizeof(char*)); 
     fgets(input_lines[index],50,stdin); 
    } 
} 

irgendwelche Vorschläge?

Danke

+4

'Token [Token_Index] = malloc (sizeof (char *));' ist unnötig (der Wert wird in der nächsten Zeile überschrieben). Können Sie den Code bereitstellen, der diese Funktion aufruft? Was passierst du für ** Tokens? –

+2

Was wird als "Token" weitergegeben? Wie ist es definiert und initialisiert? – alk

+1

Es wäre auch interessant zu wissen, welchen Code Sie auf 'main.c: 25' und' ...: 29' haben, und welche Zeilen 'functions.c: 28' und' ..: 29' sind. Meine Kristallkugel ist gebrochen, – alk

Antwort

2

an diesen beiden Linien einen genaueren Blick Lets nehmen:

tokens[token_index] = malloc(sizeof(char*)); 
tokens[token_index] = token; 

In den ersten Platz für einen Zeiger Sie zuweisen und es tokens[token_index] zuweisen. Die nächste Zeile Sie neu zuordnentokens[token_index] um irgendwo anders zeigen, verlieren den Zeiger von malloc zurückgegeben. Es ist kein Unterschied, als eine int Variable mit (lässt es i nennen), tun

i = 5; 
i = 10; 

Und dann fragen, warum i ist nicht 5.

Wenn die Lebensdauer von tokens in der aufrufenden Funktion kleiner als (oder gleich) auf die Lebensdauer von input_lines dann brauchen Sie nicht Speicher hier zuweisen, die Zuweisung von token (die zweite Zeile) genügt.


Es gibt andere Probleme als auch, wie Sie nicht token_index überall zu erhöhen.

Wie für die "ungültige schreiben" ist es wirklich schwer, etwas ohne eine ordnungsgemäße Minimal, Complete, and Verifiable Example zu sagen, die zeigt, wie diese Funktion aufgerufen wird.

+0

ich hatte den wert von token_index wie erforderlich erhöht dass die Gesamtzahl der Token zu kennen ist – Meghana

1

In Ihrem malloc() ordnen Sie Speicherplatz für den Zeiger selbst zu und weisen dann den Wert zu, der darauf verweist. In der nächsten Zeile überschreiben Sie es.

Angenommen, Sie müssen nach der Lebensdauer dieser Funktion Token als ein Array der Token verwenden, wonach Sie suchen. Sie erstellen den Platz für die Zeichenfolge, die das Token enthält, im Array tokens und kopieren es dann über.

int tokenize_string(int max_lines,char *input_lines[max_lines],char **tokens) 
{ 
    char *token; 
    int index,token_index=0; 

    for(index = 0; index < max_lines;++index) 
    { 
     token = strtok(input_lines[index]," "); 

     while(token != NULL) 
     { 
      size_t len = strlen(token) + 1; 
      tokens[token_index] = malloc(len); 
      strcpy(tokens[token_index], token); 
      token = strtok(NULL," "); 
     } 
    } 
    return token_index; 
} 

Beachten Sie auch, dass diese Funktion nur die gleiche token_index überschreiben, wenn Sie es irgendwo in der Schleife zu ändern. Sie müssen auch sicher sein, dass tokens[] alle Zeiger auf die Zeichenfolgen passen kann, die Sie erstellen müssen.


bearbeiten

Okay, ich werde von Anfang an beginnen und meinen Weg nach unten, aber

tokens=malloc(sizeof(char*)); 

ist nicht ein Array von Zeigern auf Strings zu schaffen, wie ich glaube, du erwartest. Dies sagt nur tokens zeigt auf einen Bereich des Speichers mit genügend Platz für einen einzelnen Zeiger auf eine char. Sie benötigen entweder eine vordefinierte maximale Anzahl an Zeichenfolgen, auf die Sie zeigen möchten, oder Sie finden eine Möglichkeit, dies im Voraus zu wissen.

In get_input(), tun Sie eine ähnliche thing-- Sie

verwenden
input_lines[index] = malloc(sizeof(char*)); 

, um zu versuchen, den Raum für eine neue Zeichenfolge zu schaffen, aber dies nur Punkte auf einen Zeiger, der auf einem char verweist. Angesichts Ihren fgets() Anruf, und das Limit auf 50 Zeichen, können Sie einfach tun

input_lines[index] = malloc(50); 

Damit Sie den Platz für Ihre 50 Zeichen lang sein. Danach müssen Sie sicherstellen, dass es eine nullterminierte Zeichenfolge ist.

Die wichtigste Sache zu entfernen ist, dass malloc(sizeof(char *)) ist NICHT Zuweisung der Speicherplatz für eine Zeichenfolge, nur Platz für einen Zeiger. Diese sind nicht die gleichen, und ich würde vorschlagen, ein wenig mehr darüber zu lesen here.

Im Wesentlichen scheinen Sie außerhalb des Speicherbereichs zu schreiben, den Sie zuweisen.

+2

'sizeof (char)' ist 1 per definitionem, also ist es redundant und kann entfernt werden Wenn Sie auf der sicheren Seite bleiben wollen, ersetzen Sie es durch 'sizeof * Token [token_index]'. – alk

+0

In dieser Funktion werde ich nicht die Anzahl der Zeichenfolgen eingeben, so dass meine Adresse bei Verwendung von 'strtok' aus dem Rahmen geht. – Meghana

+0

Eine maximale Anzahl von Zeilen wird über die Befehlszeile eingegeben. Ich nehme diese Eingabezeilen unbekannter Länge und tokeniere sie dann. – Meghana