Come ottenere la lunghezza reale e totale di char * (char array)?

Per un char [] , posso facilmente ottenere la sua lunghezza da:

 char a[] = "aaaaa"; int length = sizeof(a)/sizeof(char); // length=6 

Tuttavia, non posso fare così per ottenere la lunghezza di un char * da:

 char *a = new char[10]; int length = sizeof(a)/sizeof(char); 

perché, lo so, a qui è un puntatore, tale che la length qui sarà sempre 4 (o qualcosa di diverso in sistemi diversi).

La mia domanda è che come posso ottenere la lunghezza di un char * dopo? So che qualcuno potrebbe sfidarmi che conosci già il suo 10 perché l’hai appena creato. Voglio sapere questo perché questo passo della sua lunghezza può arrivare molto lontano dalla sua creazione e non voglio tornare molto indietro nel tempo per controllare questo numero. Inoltre, voglio anche sapere la sua lunghezza reale.

Per essere più specifici

    • come posso ottenere la sua length=5 reale length=5 ?
    • come posso ottenere la sua length=10 totale length=10 ?

    per il seguente esempio:

     char *a = new char[10]; strcpy(a, "hello"); 

    Non puoi Non con una precisione del 100%, comunque. Il puntatore non ha lunghezza / dimensione ma è proprio . Tutto ciò che fa è indicare un particolare luogo in memoria che contiene un carattere. Se il char è parte di una stringa, è ansible utilizzare strlen per determinare quali caratteri seguono quello attualmente indicato, ma ciò non significa che l’ array nel tuo caso sia così grande.
    Fondamentalmente:

    Un puntatore non è un array , quindi non ha bisogno di sapere quale sia la dimensione dell’array. Un puntatore può puntare a un singolo valore, quindi un puntatore può esistere senza che nemmeno ci sia un array. Non interessa nemmeno dove si trova la memoria a cui punta (solo lettura, heap o stack … non importa). Un puntatore non ha una lunghezza diversa da se stesso. Un puntatore è solo …
    Considera questo:

     char beep = '\a'; void alert_user(const char *msg, char *signal);//for some reason alert_user("Hear my super-awsome noise!", &beep);//passing pointer to single char! // void alert_user(const char *msg, char *signal) { printf("%s%c\n", msg, *signal); } 

    Un puntatore può essere un singolo carattere e l’inizio, la fine o il centro di un array …
    Pensa ai caratteri come strutture. A volte si assegna una singola struttura all’heap. Anche questo crea un puntatore senza un array.

    Usando solo un puntatore, per determinare quanto è grande una matrice a cui punta è imansible. Il più vicino a cui puoi accedere utilizza calloc e conta il numero di caratteri \ 0 consecutivi che puoi trovare attraverso il puntatore. Ovviamente, questo non funziona una volta che hai assegnato / riassegnato elementi alle chiavi di quell’array e fallisce anche se la memoria appena fuori dall’array sembra contenere anche \0 . Quindi, usare questo metodo è inaffidabile, pericoloso e solo in generale sciocco. Non farlo. Fare. Si.

    Un’altra analogia:
    Pensa a un puntatore come a un segnale stradale, punta a X città . Il segno non sa come si presenta quella città, e non sa né importa (o può fregarsene) chi vive lì. Il suo compito è dirti dove trovare la Città X. Può solo dirti quanto è lontana quella città, ma non quanto è grande. Questa informazione è considerata irrilevante per i segnali stradali. È qualcosa che puoi scoprire solo guardando la città stessa, non i segnali stradali che ti stanno indicando nella sua direzione

    Quindi, usando un puntatore, l’unica cosa che puoi fare è:

     char a_str[] = "hello";//{h,e,l,l,o,\0} char *arr_ptr = &a_str[0]; printf("Get length of string -> %d\n", strlen(arr_ptr)); 

    Ma questo, ovviamente, funziona solo se l’array / stringa è terminato con \ 0.

    Come un aiuto:

     int length = sizeof(a)/sizeof(char);//sizeof char is guaranteed 1, so sizeof(a) is enough 

    è in realtà l’assegnazione di size_t (il tipo di ritorno di sizeof ) a un int , meglio scrivere:

     size_t length = sizeof(a)/sizeof(*a);//best use ptr's type -> good habit 

    Poiché size_t è un tipo senza segno, se sizeof restituisce valori più grandi, il valore della length potrebbe essere qualcosa che non ti aspetti …

    Se il char * è terminato da 0, è ansible utilizzare strlen

    Altrimenti, non c’è modo di determinare quell’informazione

    Ci sono solo due modi:

    • Se il puntatore della memoria con il tuo char * rappresenta una stringa C (cioè contiene caratteri che hanno un byte 0 per segnarne la fine), puoi usare strlen(a) .

    • Altrimenti, è necessario memorizzare la lunghezza da qualche parte. In realtà, il puntatore punta solo a un char . Ma possiamo trattarlo come se puntasse al primo elemento di un array. Poiché la “lunghezza” di tale array non è nota, è necessario archiviare tali informazioni da qualche parte.

    Dato solo il puntatore, non è ansible. Dovrai mantenere la lunghezza che hai passato a new[] o, meglio, usare std::vector per tenere traccia della lunghezza e rilasciare la memoria quando hai finito con essa.

    Nota: questa risposta riguarda solo C ++, non C.

    • In C ++:

    Basta usare std::vector che mantiene la dimensione (dynamic) per te. (Bonus, gestione della memoria gratis).

    O std::array che mantiene la dimensione (statica).

    • Nella pura C:

    Crea una struttura per mantenere le informazioni, qualcosa come:

     typedef struct { char* ptr; int size; } my_array; my_array malloc_array(int size) { my_array res; res.ptr = (char*) malloc(size); res.size = size; return res; } void free_array(my_array array) { free(array.ptr); } 

    char * a = new char [10];

    La mia domanda è che come posso ottenere la lunghezza di un char *

    È molto semplice. 🙂 È sufficiente aggiungere solo una dichiarazione

     size_t N = 10; char *a = new char[N]; 

    Ora puoi ottenere la dimensione dell’array assegnato

     std::cout << "The size is " << N << std::endl; 

    Molti menzionati qui C funzione standard std :: strlen. Ma non restituisce la dimensione effettiva di un array di caratteri. Restituisce solo la dimensione della stringa letterale memorizzata.

    La differenza è la seguente. se prendere lo snippet di codice come esempio

     char a[] = "aaaaa"; int length = sizeof(a)/sizeof(char); // length=6 

    quindi std :: strlen (a) restituirà 5 anziché 6 come nel tuo codice.

    Quindi la conclusione è semplice: se hai bisogno di allocare dynamicmente un array di caratteri, considera l'uso della class std::string . Ha dimensioni methof e lunghezza del sinonimo che consente di ottenere la dimensione dell'array in qualsiasi momento.

    Per esempio

     std::string s( "aaaaa" ); std::cout << s.length() << std::endl; 

    o

     std::string s; s.resize( 10 ); std::cout << s.length() << std::endl; 

    Questo potrebbe sembrare Evil ™ e io non l’ho testato, ma che ne diresti di inizializzare tutti i valori in un array all’allocazione a '\0' e quindi usare strlen() ? Questo ti darebbe il tuo cosiddetto valore reale dato che smetterebbe di contare al primo '\0' che incontra.

    Bene, ora che ci penso comunque, per favore non farlo mai. A meno che tu voglia atterrare in una pila di sporchi ricordi.

    Inoltre, per la memoria allocata o la memoria totale è ansible utilizzare le seguenti funzioni se il proprio ambiente le fornisce:

    • msize ()
    • malloc_usable_size ()

    È ansible implementare le proprie funzioni new ed delete , nonché una funzione di get-size aggiuntiva:

     #define CEIL_DIV(x,y) (((x)-1)/(y)+1) void* my_new(int size) { if (size > 0) { int* ptr = new int[1+CEIL_DIV(size,sizeof(int))]; if (ptr) { ptr[0] = size; return ptr+1; } } return 0; } void my_delete(void* mem) { int* ptr = (int*)mem-1; delete ptr; } int my_size(void* mem) { int* ptr = (int*)mem-1; return ptr[0]; } 

    In alternativa, è ansible ignorare gli operatori new ed delete in modo simile.

    Puoi creare un carattere di back-tracker, ex, puoi aggiungere qualsiasi carattere speciale dì “%” alla fine della stringa e quindi controllare l’occorrenza di quel personaggio.
    Ma questo è un modo molto rischioso in quanto quel personaggio può essere in altri posti anche nel char *

     char* stringVar = new char[4] ; stringVar[0] = 'H' ; stringVar[1] = 'E' ; stringVar[2] = '$' ; // back-tracker character. int i = 0 ; while(1) { if (stringVar[i] == '$') break ; i++ ; } // i is the length of the string. // you need to make sure, that there is no other $ in the char* 

    Altrimenti definire una struttura personalizzata per tenere traccia della lunghezza e allocare memoria.

    quando il nuovo alloca un array, a seconda del compilatore (io uso gnu c ++), la parola davanti all’array contiene informazioni sul numero di byte allocati.

    Il codice di prova:

     #include  #include  int main () { int arraySz; char *a; unsigned int *q; for (arraySz = 5; arraySz <= 64; arraySz++) { printf ("%02d - ", arraySz); a = new char[arraySz]; unsigned char *p = (unsigned char *) a; q = (unsigned int *) (a - 4); printf ("%02d\n", (*q)); delete[] (a); } } 

    sulla mia macchina esce:

     05 - 19 06 - 19 07 - 19 08 - 19 09 - 19 10 - 19 11 - 19 12 - 19 13 - 27 14 - 27 15 - 27 16 - 27 17 - 27 18 - 27 19 - 27 20 - 27 21 - 35 22 - 35 23 - 35 24 - 35 25 - 35 26 - 35 27 - 35 28 - 35 29 - 43 30 - 43 31 - 43 32 - 43 33 - 43 34 - 43 35 - 43 36 - 43 37 - 51 38 - 51 39 - 51 40 - 51 41 - 51 42 - 51 43 - 51 44 - 51 45 - 59 46 - 59 47 - 59 48 - 59 49 - 59 50 - 59 51 - 59 52 - 59 53 - 67 54 - 67 55 - 67 56 - 67 57 - 67 58 - 67 59 - 67 60 - 67 61 - 75 62 - 75 63 - 75 64 - 75 

    Non consiglierei questa soluzione (il vettore è migliore), ma se sei davvero disperato, potresti trovare una relazione ed essere in grado di concludere il numero di byte allocati dall'heap.

    Quindi la cosa con l’operatore sizeof è che ti restituisce la quantità di memoria necessaria, in byte, per memorizzare l’operando.

    La quantità di memoria necessaria per memorizzare un carattere è sempre 1 byte. Quindi la dimensione di sizeof(char) restituirà sempre 1.

     char a[] = "aaaaa"; int len1 = sizeof(a)/sizeof(char); // length = 6 int len2 = sizeof(a); // length = 6; 

    Questo è lo stesso per entrambi len1 e len2 perché questa divisione di 1 non influenza l’equazione.

    Il motivo per cui sia len1 che len2 hanno il valore 6 ha a che fare con il carattere di terminazione della stringa '\0' . Che è anche un carattere che aggiunge un altro carattere alla lunghezza. Quindi la tua lunghezza sarà 6 anziché 5 che ti aspettavi.

     char *a = new char[10]; int length = sizeof(a)/sizeof(char); 

    Hai già detto che la lunghezza risulta essere 4 qui, che è corretta. Di nuovo, l’operatore sizeof restituisce la quantità di memoria per l’operando e nel tuo caso è un puntatore a . Un puntatore richiede 4 byte di memoria e quindi la lunghezza è 4 in questo caso. Dal momento che probabilmente lo si compila in un binario a 32 bit. Se avessi creato un binario a 64 bit, il risultato sarebbe 8.

    Questa spiegazione potrebbe essere qui già qui. Voglio solo condividere i miei due centesimi.

    Puoi trovare la lunghezza di una stringa char * in questo modo:

     char* mystring = "Hello World"; int length = sprintf(mystring, "%s", mystring); 

    sprintf () stampa mystring su se stesso e restituisce il numero di caratteri stampati.

    In C++17 (o più recente) è ansible utilizzare std::string_view come wrapper zero-overhead per i letterali stringa.

    Potresti provare questo:

     int lengthChar(const char* chararray) { int n = 0; while(chararray[n] != '\0') n ++; return n; } 

    Il comando Strlen funziona per me. Puoi provare il seguente codice.

    // char * s

     unsigned int strLength=strlen(s);