Errore di segmentazione che si verifica quando si modifica una stringa utilizzando i puntatori?

Contesto

Sto imparando C, e sto cercando di invertire una stringa sul posto usando i puntatori. (So ​​che puoi usare un array, questo è più che altro sull’apprendimento dei puntatori.)

Problema

Continuo ad avere errori di segmentazione quando provo a eseguire il codice qui sotto. GCC sembra non gradire *end = *begin; linea. Perché?

Soprattutto perché il mio codice è quasi identico alla funzione C non male già discussa in un’altra domanda

 #include  #include  void my_strrev(char* begin){ char temp; char* end; end = begin + strlen(begin) - 1; while(end>begin){ temp = *end; *end = *begin; *begin = temp; end--; begin++; } } main(){ char *string = "foobar"; my_strrev(string); printf("%s", string); } 

Un problema si trova nel parametro passato alla funzione:

 char *string = "foobar"; 

Questa è una stringa statica allocata nella porzione di sola lettura. Quando si tenta di sovrascriverlo con

 *end = *begin; 

otterrai il segfault.

Prova con

 char string[] = "foobar"; 

e dovresti notare una differenza.

Il punto chiave è che nel primo caso la stringa esiste nel segmento di sola lettura e viene utilizzato solo un puntatore ad esso mentre nel secondo caso una serie di caratteri con la dimensione appropriata è riservata nello stack e la stringa statica (che esiste sempre) è copiato in esso. Dopodiché sei libero di modificare il contenuto dell’array.

È inoltre ansible utilizzare il carattere null alla fine di una stringa per scambiare i caratteri all’interno di una stringa, evitando così l’uso di spazi aggiuntivi. Ecco il codice:

 #include  void reverse(char *str){ int length=0,i=0; while(str[i++]!='\0') length++; for(i=0;i 

Nel tuo codice hai il seguente:

 *end--; *begin++; 

È solo pura fortuna che ciò faccia la cosa giusta (in realtà, la ragione è la precedenza degli operatori). Sembra che tu abbia inteso realmente il codice

 (*end)--; (*begin)++; 

Che è completamente sbagliato. Il modo in cui lo hai, le operazioni accadono come

  • decrementa la end e poi denotala
  • l’incremento begin e poi lo dereferenzia

In entrambi i casi il dereferenziamento è superfluo e dovrebbe essere rimosso. Probabilmente hai inteso che il comportamento fosse

 end--; begin++; 

Queste sono le cose che fanno impazzire gli sviluppatori perché sono così difficili da rintracciare.

Questo sarebbe sul posto e usando i puntatori

  #include #include #include void reve(char *s) { for(char *end = s + (strlen(s) - 1); end > s ; --end, ++s) { (*s) ^= (*end); (*end) ^= (*s); (*s) ^= (*end); } } int main(void) { char *c = malloc(sizeof(char *) * 250); scanf("%s", c); reve(c); printf("\nReverse String %s", c); } 

Cambia char *string = "foobar"; to char string[] = "foobar"; . Il problema è che un char * indica solo la memoria che si tenta di modificare causando un errore di segmentazione.

Questo crea una piccola funzione ricorsiva (ish) e funziona memorizzando i valori lungo la via verso il basso nello stack e incrementando il puntatore all’inizio della stringa (* s) al ritorno (ritorno).

Codice dall’aspetto intelligente ma terribile in termini di utilizzo dello stack.

 #include  char *reverse_r(char val, char *s, char *n) { if (*n) s = reverse_r(*n, s, n+1); *s = val; return s+1; } int main(int argc, char *argv[]) { char *aString; if (argc < 2) { printf("Usage: RSIP \n"); return 0; } aString = argv[1]; printf("String to reverse: %s\n", aString ); reverse_r(*aString, aString, aString+1); printf("Reversed String: %s\n", aString ); return 0; } 

Ecco la mia versione dell’inversione di stringa C sul posto.

 #include  #include  int main (int argc, const char * argv[]) { char str[] = "foobar"; printf("String:%s\n", str); int len = (int)strlen(str); printf("Lenth of str: %d\n" , len); int i = 0, j = len - 1; while(i < j){ char temp = str[i]; str[i] = str[j]; str[j] = temp; i++; j--; } printf("Reverse of String:%s\n", str); return 0; } 

Di seguito, puoi vedere il mio codice per questo problema:

 #include  #include  char* strRev(char* str) { char *first,*last; if (!str || !*str) return str; size_t len = strlen(str); for (first = str, last = &str[len] - 1; first < last ; first++, last--) { str[len] = *first; *first = *last; *last = str[len]; } str[len] = '\0'; return str; } int main() { char test[13] = "A new string"; std::cout << strRev(test) << std::endl; return 0; }