2013-10-29 6 views
5

Listener di lunga durata, primo chiamante.Errore di segmentazione durante l'assegnazione dei valori ai puntatori nella funzione

Mi scuso se questo problema è già stato affrontato (immagino che sia è stato ampiamente coperto), ma ho cercato attraverso molte domande su puntatori e altri argomenti apparentemente affini, ma sono ancora in grado di risolvere il mio problema.

Attualmente sto scrivendo una stringa di libreria per progetto di classe, e quando sto ottenendo un errore di segmentazione quando provo questo:

#include "str2107.h" 
#include <stdio.h> 

void lstrip(char *s) { 

     char *p, *q; 
     p = q = s; 

     while (*p == ' ' && *p != '\0') { 
      *p++; 
     } 

     while (*p != '\0') { 
      *q = *p; //this is where the actual segmentation fault occurs. 
      p++; 
      q++; 
     } 

     *q = '\0'; 
} 

Il mio programma principale si presenta così:

#include <stdio.h> 
#include <stdlib.h> 
#include "str2107.h" 


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

    char *z1 = "  weeee"; 
    printf("lstrip function\n"); 
    printf("%s\n",z1); 
    lstrip(z1); 
    printf("%s\n",z1); 

    return 0; 
} 
+1

non collegato: spero che si vede la futilità della seconda metà di questa espressione in un istante-condizione: '(* p == ''! && * p = '\ 0') '. Sotto esattamente quali condizioni possibili la prima parte sarà vera e la seconda parte sarà * falsa * ??? Versione più breve: '(* p == '')' – WhozCraig

+0

Grazie per averlo indicato! – Torchedmuffinz

+0

+1 per fornire un [SSCCE] (http://sscce.org/) che riproduce il problema. –

risposta

5

z1 sta puntando a un stringa letterale e la modifica di una stringa letterale è undefined behavior. In alternativa è possibile utilizzare la seguente dichiarazione di z1 che sarà modificabile:

char z1[] = "  weeee"; 

Se guardiamo il progetto C99 standard di sezione 6.4.5stringhe letterali paragrafo dice (sottolineatura mia):

Non è specificato se questi array sono distinti purché i loro elementi abbiano i valori appropriati . Se il programma tenta di modificare un array di questo tipo, il comportamento è indefinito.

alcuni altri punti come WhozCraig sottolinea questa linea:

while (*p == ' ' && *p != '\0') { 

poteva essere più succintamente scritto come:

while (*p == ' ') { 

anche che si sta utilizzando indirezione qui:

*p++; 

ma in realtà non utilizza il valore risultante, in modo da poter cambiare a:

p++; 
+0

Questo ha fatto il trucco. Grazie mille. =) – Torchedmuffinz

1

Quando si scrive char *z1 = " weeee"; poi z1 è un puntatoreche punta a una memoria che si trova nella parte codice, quindi non è possibile cambiarlo.

Se si modifica char z1[] = " weeee"; poi z1 è un array di caratteri che si trovano sul pila e si può cambiare.

Se avessi scritto char const *z1 = "..."; allora sarebbe un errore di compilazione , che è migliore e preferibile rispetto segmentation fault.

+0

Grazie per la spiegazione. Ha definitivamente eliminato alcune cose! – Torchedmuffinz

0
char *z1 = "  weeee"; 

dovrebbero essere

const char *z1 = "  weeee"; 

perché letterali stringa sono costanti. Provare qualcosa di simile:

const char *z1 = "  weeee"; 
char *z2 = strdup(z1); 
lstrip(z2); 

Per chiamare lstrip su una stringa mutabile pur mantenendo z2 un char* (se essere un char[] non è ciò che si desidera).

+0

Si noti che mentre si tenta di modificare una stringa letterale richiama il comportamento non definito, i valori letterali stringa non hanno il tipo 'const' in C. –

+0

@ElchononEdelson True. Forse non ero chiaro che il cambiamento dovrebbe essere fatto per prevenire accidentalmente causare un comportamento indefinito piuttosto che per accordo di tipo. –

+0

Forse. Una soluzione alternativa sarebbe scrivere 'char z1 [] =" weeee ";', creando 'z1' come array piuttosto che come puntatore. –

0

Come un sacco di altre persone hanno già fatto notare a te, quando si scrive:

char *whatever = "some value";

Questo è molto diverso da quello:

char *whatever = malloc(length("some value") + 1); 
strcpy(whatever, "some value");

La differenza è che qualcosa che è un letterale (cioè una stringa definita in fase di compilazione) può essere una costante, anche se non so se sia sempre o richiesto t o essere costante. Poiché una costante non deve essere modificata e si inserisce un carattere '\ 0' nella stringa, si verifica un errore di segmentazione.

Ci possono essere molti motivi per questo, ma quello facile che so è che il programma può ottimizzare se sa che ogni utilizzo della stessa stringa è sicuro da riutilizzare.

Per fare un esempio:

char *whatever1 = malloc(length("some value") + 1); 
strcpy(whatever1, "some value"); 
char *whatever2 = malloc(length("some value") + 1); 
strcpy(whatever2, "some value"); 
if(whatever1 == whatever2) { 
    printf("This should never happen!\n"); 
} 

if("some value" == "some value") { 
    printf("A good compiler should always do this!\n"); 
}
+0

I valori letterali delle stringhe non sono costanti in C. Cioè, non hanno il tipo 'const'. Quello che lo standard dice è semplicemente che se il tuo programma tenta di modificarne uno, il comportamento non è definito. La maggior parte dei compilatori C attuali inserirà letterali di stringa in una sezione di sola lettura, ma non sono obbligatori e, di solito, non lo erano. –