2015-04-14 11 views
17

Ho un programma semplice come questo:array di caratteri nelle strutture: perché strlen() restituisce qui il valore corretto?

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

typedef struct 
{ 
    int numberOfDays; 
    char name[10]; 
} Month; 


int main(void) 
{ 
    const Month months[12] = { 
     { 31, {'J', 'a', 'n'} }, 
     { 28, {'F', 'e', 'b'} } 
    }; 

    printf("%zu\n", strlen(months[0].name)); 
    printf("%zu\n", sizeof(months[0].name)); 

    printf("%zu\n", strlen(months[1].name)); 
    printf("%zu\n", sizeof(months[1].name)); 

    return 0; 
} 

L'output è simile a questo:

3 
10 
3 
10 

capisco perché sizeof(months[i].name) stampe 10, ma perché strlen restituire il valore corretto in questo caso?

Il mio pensiero era, che strlen conta fino al primo '\0', ma l'array char name[3] non è terminato con null. Dalla mia comprensione questo dovrebbe essere un comportamento indefinito? Funziona solo per caso?

Mi chiedo quale sia il layout di memoria nell'array months[12] precedente.

+10

SBAGLIATO. Questo non è UB. Il resto della struct viene inizializzato su zeri. –

+0

Mi dispiace, sono i miei cattivi ragazzi. Nella struct in scritto 'char name [10]' ma nella domanda ho parlato di 'char name [3]'. Entrambi funzionano però, questo è ciò che mi meraviglia. – Max

+6

@Max Si prega di non modificare la domanda in un modo che faccia apparire la risposta già fornita fuori dal contesto. Grazie. –

risposta

26

TL; DR Risposta: No, questo è un comportamento ben definito.

Spiegazione: Secondo il documento uniforme C11, capitolo 6.7.9, inizializzazione del,

Se ci sono meno inizializzatori in un elenco brace-allegata che ci sono elementi o membri di un aggregato, o un numero inferiore di caratteri in un letterale stringa utilizzato per inizializzare un array di dimensioni note rispetto a quelli presenti nell'array, il resto dell'aggregato deve essere inizializzato implicitamente come oggetti con durata di archiviazione statica.

Nel tuo caso, si dispone di una serie di char10 elementi

char name[10]; 

e hai fornito inizializzatore per soli 3 elementi, come

{ 31, {'J', 'a', 'n'} }, 

Così, il resto del gli elementi di name vengono inizializzati su 0 o '\0'. Quindi, in questo caso, strlen() restituisce il risultato corretto.

Nota: Si prega di non fare affidamento su questo metodo di per terminazione null di stringhe . Nel caso in cui tu stia fornendo il numero esatto di elementi come initalizer, non ci sarà alcuna terminazione nulla.


EDIT:

Nel caso la definizione name viene modificato in char name[3] e inizializzato con tre char s, quindi, secondo la nota di cui sopra, l'utilizzo di strlen() (e famiglia) sarà undefined behaviour come sarà scavalcare l'area di memoria allocata alla ricerca di terminare null.

+0

OK, questo fa sende. Quello che mi stavo chiedendo ... anche se cambio la dichiarazione in 'char name [3]' funziona ancora senza segfault. – Max

+1

In tal caso si * è * fortunato, in quanto solo "accade" è uno 0 terminante. –

+0

@Max Si prega di consultare la nota sotto la mia risposta. :-) –

8

Il motivo è che i tuoi mesi sono davvero nul-terminati. Se si dispone di un array con 10 elementi e si dispone di un inizializzatore per 3 elementi, il resto viene riempito con 0. Se avessi un mese con 11 caratteri, il compilatore te lo direbbe. Se avessi un mese con 10 caratteri, saresti nei guai perché non ci sarebbe nessuna terminazione, e il compilatore non te lo direbbe.

4

Quando si parte inizializzare il struct, quelle parti non specificamente inizializzati sono impostate a 0.

Così le corde hanno una terminazione 0 e così strlen() restituisce il valore corretto.

#include <stdio.h> 
#include <string.h> 

int main(){ 
int i; 
    char s[10] = {'a', 'b', 'c'}; 
    for (i=0; i<10; i++) 
     printf("%d ", s[i]); 
    printf("\n%d\n", strlen(s)); 
    return 0; 
} 

output del programma:

97 98 99 0 0 0 0 0 0 0 
3 
Problemi correlati