2016-03-20 7 views
-2

Ich habe ein Problem mit dem Drucken einer Zeichenfolge in C (nun, die Zeichenfolge, die *ptr verweist auf).Seltsames Verhalten von printf nach memcpy

ich den folgenden Code haben:

char *removeColon(char *word) { 
    size_t wordLength; 
    char word1[MAXLENGTH]; 

    wordLength = strlen(word); 
    wordLength--; 
    memcpy(word1, word, wordLength); 
    printf("word1: %s\n", word1); 
    return *word1; 
} 

ich das mit Wort lief = "MAIN:" (der Wert des Wortes kommt aus strtok auf einer Zeichenkette aus einer Datei lesen). Es funktioniert gut bis die printf, wo das Ergebnis ist:

word1: MAIN╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠

und dann gibt es eine Ausnahme und alles bricht.

Irgendwelche Gedanken?

+4

nullabschluss, (raten) –

+0

Können Sie bitte weitere Details angeben? Ich habe versucht, '\ 0' am Ende von Word1 hinzuzufügen, aber es hat nicht geholfen. –

+0

Wenn nicht, kann ich die Frage später lesen. –

Antwort

0
wordLength = strlen(word); 

Sie haben den Nullabschluss in der Länge umfassen, denn jeder Zeichenfolge ein abschließendes Zeichen, deren ASCII-Wert hat, ist 0, Dinkel \0 in C. Verwenden Sie auch die str... Familie von Funktionen statt mem..., da die former ist für null terminierte Strings gedacht, letzteres für Arrays. Außerdem können Sie keinen lokalen Stapel zugewiesenen Array zurückgeben. Basierend auf dem Code der Funktion klingt es so, als ob Sie das letzte Zeichen entfernen würden. Wenn das der Fall ist, ist es besser zu tun

void remlast(char *str) 
{ 
    str[strlen(str) - 1] = '\0'; 
} 

Beachten Sie, dass dies bei leeren Zeichenfolgen nicht funktioniert.

+1

komm schon, die "überarbeitete Funktion" enthält noch viele Fehler. Auch "remlast" bricht bei leeren Saiten. –

+0

fixed @ M.M [16 Zeichen] – stackptr

+0

@stackptr: nicht wirklich behoben ;-) es hätte tatsächlich weniger gekostet, den Code zu reparieren, als den Fehler zu dokumentieren. – chqrlie

0

Sie kopieren über wordLength Bytes, aber Sie können kein Nullterminierungsbyte hinzufügen. Da word1 vor dieser Kopie nicht initialisiert ist, sind die verbleibenden Bytes nicht definiert.

Also, wenn printf versucht, die Zeichenfolge zu drucken, findet es keinen Null-Terminator und liest weiter, bis es ein Nullbyte irgendwo außerhalb der Grenzen des Arrays findet. Dies ist ein nicht definiertes Verhalten.

Nachdem die Bytes zu kopieren, müssen Sie manuell den Nullabschluss hinzuzufügen:

memcpy(word1, word, wordLength); 
word1[wordLength] = '\0'; 

Auch sind Sie einen Zeiger auf eine lokale Variable zurück. Wenn die Funktion zurückkehrt, ist diese Variable außerhalb des Gültigkeitsbereichs und Dereferenzierung dieses Zeigers ist ebenfalls undefiniert.

Anstatt word1 ein lokales Array zu machen, können Sie Speicher dynamisch dafür vergeben:

char *word1 = malloc(strlen(word)); 

Wenn Sie dies tun, Sie zu free diesen Speicher irgendwo in der aufrufenden Funktion benötigen. Die andere Möglichkeit ist, den Anrufer Pass in einem Puffer in der richtigen Größe zu haben:

void removeColon(char *word, char *word1) { 
1

Sie müssen sicherstellen, (1) jede Saite ist nul-terminiert und (2) Sie versuchen, keine zu ändern Zeichenfolgenliteral. Sie haben viele Möglichkeiten, die Sie ergreifen können. Ein einfacher Ansatz das letzte Zeichen (beliebiges Zeichen) mit strlen entfernen:

char *rmlast (char *s) 
{ 
    if (!*s) return s;  /* return if empty-string */ 
    s[strlen (s) - 1] = 0; /* overwrite last w/nul */ 
    return s; 
} 

(Sie auch die string.h Funktionen nutzen können strchr (für 0 Suche), strrchr (für Ihr Ziel char suchen, wenn übergeben), strpbrk (Suche nach einem von mehreren Zeichen), etc .. das letzte Zeichen zu lokalisieren als auch)

Oder Sie können mit Zeigern das gleiche tun:

char *rmlast (char *s) 
{ 
    if (!*s) return s; /* return if empty-string */ 
    char *p = s; 

    for (; *p; p++) {} /* advance to end of str */ 
    *--p = 0;   /* overwrite last w/nul */ 

    return s; 
} 

Sie können auch das letzte Zeichen von Interesse übergeben, wenn Sie das Entfernen auf ein bestimmtes Zeichen beschränken und einen einfachen Vergleich in der Funktion vornehmen möchten, bevor Sie es mit einem nullendenzeichen überschreiben.

Schauen Sie beide und lassen Sie mich wissen, wenn Sie irgendwelche Fragen haben.

+0

Ist 0 (eine Ganzzahl) nicht anders als '\ 0'? – RastaJedi

+0

Nein, das 'Null-Zeichen' '' \ 0'' hat den ASCII-Wert '0' - es gibt keinen Unterschied. Es braucht nur mehr tippen, um die vier Zeichen ''\ 0'' als eine' 0' 'einzugeben:)' –

+0

Es ist also nur die Zeichendarstellung. Ich war mir nicht sicher, ob die Ganzzahl Null irgendwie durch etwas anderes als das "Nullbyte" dargestellt wurde. Offensichtlich ist "0" völlig anders, aber das musste nicht einmal gesagt werden. – RastaJedi

1

Ihre Funktion removeColon sollte entweder

  • anstelle betreiben und die Zeichenfolge als Argument übergeben ändern
  • einen Zielpuffer gegeben werden, und die verkürzte Zeichenfolge, um es zu kopieren oder
  • weisen Speicher für die verkürzte string und gib das zurück.

Sie kopieren nur die Zeichen in das lokale Array, nicht das Nullabschluss, noch müssen Sie ein im Puffer gesetzt, vorbei an dieses Array zu printf("%s", ...) ruft nicht definiertes Verhalten: printf setzt den Pufferinhalt drucken, bis es eine '\0' findet Byte, geht es sogar über das Ende des Arrays hinaus, ruft unbestimmtes Verhalten auf, druckt Müll und stirbt schließlich bei einem Absturz ab.

Sie können keinen Zeiger auf ein automatisches Array zurückgeben, da dieses Array nicht mehr verfügbar ist, sobald die Funktion zurückkehrt. Wenn Sie den Zeiger zu einem späteren Zeitpunkt deaktivieren, wird ein nicht definiertes Verhalten ausgelöst.

Hier ist eine Funktion, die an Ort und Stelle funktioniert:

char *removeColon(char *word) { 
    if (*word) word[strlen(word) - 1] = '\0'; 
    return word; 
} 

Hier ist eine, die Kopien zu einem Zielpuffer, lang genug sein, angenommen:

char *removeColon(char *dest, const char *word) { 
    size_t len = strlen(word); 
    memcpy(dest, word, len - 1); 
    dest[len - 1] = '\0'; 
    return dest; 
} 

Hier ist eine, die Speicher zuweist:

char *removeColon(const char *word) { 
    size_t len = strlen(word); 
    char *dest = malloc(len); 
    memcpy(dest, word, len - 1); 
    dest[len - 1] = '\0'; 
    return dest; 
}