Terminazione nulle del char array


Answers

Se si digitano più di quattro caratteri, i caratteri supplementari e il terminatore nullo verranno scritti al di fuori della fine dell'array, sovrascrivendo la memoria che non appartiene all'array. Questo è un buffer overflow.

C non ti impedisce di rovinare la memoria che non possiedi. Ciò si traduce in un comportamento indefinito . Il tuo programma potrebbe fare qualsiasi cosa - potrebbe bloccarsi, potrebbe silenziosamente spazzare altre variabili e causare comportamenti confusi, potrebbe essere innocuo, o qualsiasi altra cosa. Si noti che non vi è alcuna garanzia che il vostro programma funzionerà in modo affidabile o si bloccherà in modo affidabile. Non puoi nemmeno dipendere dal fatto che si blocca immediatamente.

Questo è un ottimo esempio del perché scanf("%s") è pericoloso e non dovrebbe mai essere usato. Non conosce la dimensione del tuo array, il che significa che non c'è modo di usarlo in sicurezza. Invece, evitare scanf e usare qualcosa di più sicuro, come fgets () :

fgets () legge al massimo un carattere in meno rispetto alla dimensione dal flusso e li memorizza nel buffer indicato da s. La lettura si interrompe dopo un EOF o una nuova riga. Se una nuova riga viene letta, viene archiviata nel buffer. Un byte null terminante ('\ 0') viene memorizzato dopo l'ultimo carattere nel buffer.

Esempio:

if (fgets(A, sizeof A, stdin) == NULL) {
    /* error reading input */
}

Fastidiosamente, fgets () lascerà un carattere di fine riga finale ('\ n') alla fine dell'array. Quindi potresti anche volere il codice per rimuoverlo.

size_t length = strlen(A);
if (A[length - 1] == '\n') {
    A[length - 1] = '\0';
}

Ugh. Un semplice scanf("%s") è diventato una mostruosità di 7 righe. E questa è la seconda lezione del giorno: C non è buono per I / O e gestione delle stringhe. Può essere fatto, e può essere fatto in sicurezza, ma C prenderà a calci e urlerà per tutto il tempo.

Question

Considera il seguente caso:

#include<stdio.h>
int main()
{
    char A[5];
    scanf("%s",A);
    printf("%s",A);
}

La mia domanda è se char A[5] contiene solo due caratteri. Dì "ab", quindi A[0]='a' , A[1]='b' e A[2]='\0' . Ma se l'input è dire "abcde" allora dove è '\0' in quel caso. A[5] contiene '\0' ? Se sì, perché? sizeof(A) restituirà sempre 5 come risposta. Quindi quando l'array è pieno, c'è un byte extra riservato a '\0' che sizeof() non conta?




\ 0 è un operatore di terminazione che termina quando l'array è pieno se l'array non è pieno allora \ 0 sarà alla fine dell'array quando si inserisce una stringa che leggerà dalla fine dell'array




Finirai con un comportamento indefinito .

Come dici tu, la dimensione di A sarà sempre 5, quindi se leggi 5 o più char , scanf proverà a scrivere in una memoria, che non dovrebbe modificare.

E no, non c'è spazio / carattere riservato per il simbolo \0 .




Non c'è un carattere che è riservato, quindi è necessario fare attenzione a non riempire l'intero array fino al punto in cui non può essere terminato con null. Le funzioni Char si basano sul terminatore nullo e otterrai risultati disastrosi se ti trovi nella situazione che descrivi.

Molto codice C che vedrai utilizzerà le derivate 'n' di funzioni come strncpy. Da quella pagina man puoi leggere:

Le funzioni strcpy () e strncpy () restituiscono s1. Le funzioni stpcpy () e stpncpy () restituiscono un puntatore al carattere terminante `\ 0 'di s1. Se stpncpy () non termina s1 con un carattere NUL, restituisce invece un puntatore a s1 [n] (che non si riferisce necessariamente a una posizione di memoria valida).

strlen si basa anche sul carattere null per determinare la lunghezza di un buffer di caratteri. Se e quando manchi quel personaggio, otterrai risultati errati.




il carattere null viene utilizzato per la terminazione dell'array. è alla fine della matrice e mostra che la matrice è finita in quel punto. l'array fa automaticamente l'ultimo carattere come carattere null in modo che il compilatore possa facilmente capire che l'array è finito.




Qualsiasi stringa superiore a 4 caratteri di lunghezza farà sì che scanf scriva oltre i limiti dell'array. Il comportamento risultante è indefinito e, se sei fortunato, causerà il crash del tuo programma.

Se ti stai chiedendo perché scanf non smette di scrivere stringhe troppo lunghe per essere memorizzate nell'array A , è perché non c'è modo per scanf di sapere che sizeof(A) è 5. Quando passi un array come parametro a una funzione C, l'array decade in un puntatore che punta al primo elemento dell'array. Quindi, non c'è modo di interrogare la dimensione dell'array all'interno della funzione.

Per limitare il numero di caratteri letti nell'array, utilizzare

scanf("%4s", A);



le matrici di caratteri in c sono solo indicatori di blocchi di memoria. Se dici al compilatore di riservare 5 byte per i caratteri, lo fa. Se si tenta di inserire più di 5 byte, si limiterà a sovrascrivere la memoria oltre i 5 byte prenotati.

Ecco perché c può avere implementazioni di sicurezza serie. Devi sapere che stai solo scrivendo 4 caratteri + a \ 0. C ti permetterà di sovrascrivere la memoria fino a quando il programma si blocca.

Per favore non pensare a char foo [5] come a una stringa. Pensalo come un posto dove mettere 5 byte. È possibile memorizzare 5 caratteri senza un valore nullo, ma è necessario ricordare che è necessario eseguire una memcpy (otherCharArray, foo, 5) e non utilizzare strcpy. Devi anche sapere che l'altroCharArray ha spazio sufficiente per quei 5 byte.




Come già sottolineato, devi definire / allocare un array di lunghezza N + 1 per poter memorizzare correttamente N caratteri. È possibile limitare la quantità di caratteri letti da scanf. Nel tuo esempio sarebbe:

scanf("%4s", A);

per leggere max. 4 caratteri da stdin.