¿Cómo obtener la longitud real y total de char * (char array)?

Para un char [] , puedo obtener su longitud fácilmente de la siguiente manera:

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

Sin embargo, no puedo hacer esto para obtener la longitud de un char * por:

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

porque, lo sé, aquí hay un puntero, de modo que la length aquí siempre será 4 (o algo diferente en diferentes sistemas).

Mi pregunta es ¿cómo puedo obtener la longitud de un char * después? Sé que alguien puede desafiarme porque ya sabes que es 10 porque acabas de crearlo. Quiero saber esto porque este paso para obtener su longitud puede venir muy lejos de su creación y no quiero volver atrás para verificar este número. Además, también quiero saber su longitud real.

Para ser más especifico

  • ¿cómo puedo obtener su length=5 real length=5 ?
  • ¿cómo puedo obtener su length=10 total length=10 ?

para el siguiente ejemplo:

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

No puedes. No con el 100% de precisión, de todos modos. El puntero no tiene longitud / tamaño, pero es propio . Todo lo que hace es señalar a un lugar particular en la memoria que contiene un char. Si ese carácter es parte de una cadena, puede usar strlen para determinar qué caracteres siguen al que se está apuntando en ese momento, pero eso no significa que la matriz en su caso sea tan grande.
Básicamente:

Un puntero no es una matriz , por lo que no necesita saber cuál es el tamaño de la matriz. Un puntero puede apuntar a un único valor, por lo que un puntero puede existir sin que siquiera haya una matriz. Ni siquiera le importa dónde está situada la memoria a la que apunta (solo lectura, montón o stack … no importa). Un puntero no tiene una longitud que no sea ella misma. Un puntero solo es …
Considera esto:

 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 puntero puede ser un único carácter así como el principio, el final o el medio de una matriz …
Piensa en los caracteres como estructuras. A veces asigna una estructura única en el montón. Eso también crea un puntero sin una matriz.

Usar solo un puntero para determinar qué tan grande es apuntando a una matriz es imposible. Lo más cerca que puede llegar es usando calloc y contando el número de caracteres \ 0 consecutivos que puede encontrar a través del puntero. Por supuesto, eso no funciona una vez que has asignado / reasignado cosas a las teclas de esa matriz y también falla si la memoria que está justo fuera de la matriz también tiene \0 . Entonces, usar este método no es confiable, es peligroso y, por lo general, tonto. No lo hagas Hacer. Eso.

Otra analogía:
Piense en un puntero como una señal de tráfico, apunta a la ciudad X. El letrero no sabe cómo es esa ciudad, y no sabe ni le importa (o puede importarle) quién vive allí. Su trabajo es decirle dónde encontrar Town X. Solo puede decirte qué tan lejos está esa ciudad, pero no lo grande que es. Esa información se considera irrelevante para las señales de tráfico. Eso es algo que solo puedes descubrir si miras la ciudad en sí misma, no las señales que te apuntan en su dirección

Entonces, usando un puntero, lo único que puedes hacer es:

 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)); 

Pero esto, por supuesto, solo funciona si la matriz / cadena está \ 0-terminada.

Como un asside:

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

en realidad está asignando size_t (el tipo de devolución de sizeof ) a un int , best write:

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

Como size_t es un tipo sin signo, si sizeof devuelve valores más grandes, el valor de la length puede ser algo que no esperaba …

Si el char * tiene 0 terminaciones, puede usar strlen

De lo contrario, no hay forma de determinar esa información

Solo hay dos formas:

  • Si el puntero de memoria de su char * representa una cadena C (es decir, contiene caracteres que tienen un byte de 0 para marcar su final), puede usar strlen(a) .

  • De lo contrario, necesita almacenar la longitud en alguna parte. En realidad, el puntero solo apunta a un char . Pero podemos tratarlo como si apuntara al primer elemento de una matriz. Como no se conoce la “longitud” de ese conjunto, debe almacenar esa información en algún lugar.

Dado solo el puntero, no puedes. Tendrás que mantener la longitud que pasaste a new[] o, mejor aún, usar std::vector para mantener un registro de la longitud y liberar la memoria cuando hayas terminado con ella.

Nota: esta respuesta solo se dirige a C ++, no a C.

  • En C ++:

Simplemente use std::vector que mantenga el tamaño (dynamic) para usted. (Bonificación, gestión de memoria gratis).

O std::array que mantienen el tamaño (estático).

  • En C puro:

Crea una estructura para mantener la información, algo como:

 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 = nuevo char [10];

Mi pregunta es ¿cómo puedo obtener la longitud de un char *

Es muy simple 🙂 Es suficiente agregar solo una statement

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

Ahora puedes obtener el tamaño de la matriz asignada

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

Muchos mencionan aquí la función estándar de C std :: strlen. Pero no devuelve el tamaño real de una matriz de caracteres. Devuelve solo el tamaño del literal de cadena almacenado.

La diferencia es la siguiente. si tomar el fragmento de código como ejemplo

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

entonces std :: strlen (a) devolverá 5 en lugar de 6 como en su código.

Entonces, la conclusión es simple: si necesita asignar dinámicamente una matriz de caracteres, considere el uso de la clase std::string . Tiene el tamaño methof y su longitud de sinónimos que permite obtener el tamaño de la matriz en cualquier momento.

Por ejemplo

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

o

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

Esto puede sonar Evil ™ y no lo he probado, pero ¿qué hay de inicializar todos los valores en una matriz en la asignación a '\0' y luego usar strlen() ? Esto le daría el llamado valor real, ya que dejaría de contar en el primer '\0' que encuentre.

Bueno, ahora que lo pienso, no lo hagas nunca. A menos que quieras aterrizar en una stack de memoria sucia.

Además, para la memoria asignada o la memoria total , puede usar las siguientes funciones si su entorno las proporciona:

  • msize ()
  • malloc_usable_size ()

Puede implementar sus propias funciones new y de delete , así como una función de get-size adicional adicional:

 #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]; } 

Alternativamente, puede anular los operadores new y delete de una manera similar.

Puedes hacer un caracter de seguimiento hacia atrás, por ejemplo, puedes agregar cualquier caracter especial, decir “%” al final de tu cadena y luego verificar la ocurrencia de ese caracter.
Pero esta es una forma muy arriesgada ya que ese personaje puede estar en otros lugares también en el 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* 

De lo contrario, defina una estructura personalizada para realizar un seguimiento de la longitud y asignar memoria.

cuando el nuevo asigna una matriz, dependiendo del comstackdor (yo uso gnu c ++), la palabra que está delante de la matriz contiene información sobre la cantidad de bytes asignados.

El código de prueba:

 #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); } } 

en mi máquina vuelca:

 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 

No recomendaría esta solución (el vector es mejor), pero si está realmente desesperado, podría encontrar una relación y poder concluir la cantidad de bytes asignados desde el montón.

Entonces, la cosa con el operador sizeof es que le devuelve la cantidad de almacenamiento necesaria, en bytes, para almacenar el operando.

La cantidad de almacenamiento necesaria para almacenar un char es siempre de 1 byte. Entonces, sizeof(char) siempre devolverá 1.

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

Esto es lo mismo para len1 y len2 porque esta división de 1 no influye en la ecuación.

La razón por la cual len1 y len2 llevan el valor 6 tiene que ver con la terminación de cadena char '\0' . Que también es un char que agrega otro char a la longitud. Por lo tanto, su longitud va a ser 6 en lugar de las 5 que estaba esperando.

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

Ya mencionaste que aquí la longitud es 4, lo cual es correcto. De nuevo, el operador sizeof devuelve la cantidad de almacenamiento para el operando y en su caso es un puntero a . Un puntero requiere 4 bytes de almacenamiento y, por lo tanto, la longitud es 4 en este caso. Dado que probablemente lo compile en un binario de 32 bits. Si hubiera creado un binario de 64 bits, el resultado sería 8.

Esta explicación podría estar aquí ya aquí. Solo quiero compartir mis dos centavos.

Puede encontrar la longitud de una cadena de caracteres * como esta:

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

sprintf () imprime mystring en sí mismo, y devuelve la cantidad de caracteres impresos.

En C++17 (o más reciente) puede usar std::string_view como un contenedor cero-overhead para literales de cadena.

Puedes intentar esto:

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

El comando Strlen me está funcionando. Puedes intentar seguir el código.

// char * s

 unsigned int strLength=strlen(s);