web-dev-qa-db-fra.com

Comment obtenir la longueur réelle et totale de char * (char array)?

Pour un char [], je peux facilement obtenir sa longueur en:

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

Cependant, je ne peux pas faire comme ceci pour obtenir la longueur d'un char * en:

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

je sais que a est un pointeur, de sorte que length sera toujours 4 (ou quelque chose d'autre dans des systèmes différents).

Ma question est la suivante: comment puis-je obtenir la longueur d'un char * après? Je sais que quelqu'un peut me défier que vous connaissez déjà son 10 parce que vous venez de le créer. Je veux le savoir parce que cette étape consistant à obtenir sa longueur risque de prendre beaucoup de temps depuis sa création et que je ne veux pas revenir en arrière pour vérifier ce nombre. De plus, je veux aussi connaître sa longueur réelle.

Pour être plus précis

  • comment puis-je obtenir son vrai length=5?
  • comment puis-je obtenir son length=10 total?

pour l'exemple suivant:

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

Si le char * est terminé par 0, vous pouvez utiliser strlen

Sinon, il n'y a aucun moyen de déterminer cette information

13
Olotiar

Il n'y a que deux façons:

  • Si le pointeur de mémoire de votre char * représente une chaîne C (c'est-à-dire qu'il contient des caractères dont l'octet est 0 pour marquer sa fin), vous pouvez utiliser strlen(a).

  • Sinon, vous devez stocker la longueur quelque part. En réalité, le pointeur pointe uniquement sur un char. Mais nous pouvons le traiter comme s'il pointe vers le premier élément d'un tableau. Puisque la "longueur" de ce tableau n'est pas connue, vous devez stocker cette information quelque part.

4
DarkDust

Avec juste le pointeur, vous ne pouvez pas. Vous devrez garder la longueur que vous avez passée à new[] ou, mieux, utiliser std::vector pour garder trace de la longueur et libérer la mémoire une fois que vous aurez fini.

Remarque: cette réponse ne concerne que le C++, pas le C.

3
Mike Seymour
  • En C++:

Utilisez simplement std::vector<char> qui garde la taille (dynamique) pour vous. (Bonus, gestion de la mémoire gratuite).

Ou std::array<char, 10> qui conservent la taille (statique).

  • En C pur:

Créez une structure pour conserver les informations, par exemple:

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);
}
3
Jarod42

Cela peut paraître maléfique et je ne l’ai pas testé, mais pourquoi ne pas initialiser toutes les valeurs d’un tableau lors de l’attribution à '\0' et utiliser ensuite strlen()? Cela vous donnerait votre soi-disant valeur real car il cesserait de compter à la première '\0' qu'il rencontre.

Bien, maintenant que j'y pense, s'il vous plaît, ne faites jamais cela. À moins que vous ne vouliez atterrir dans une pile de mémoires vides.

De plus, pour la mémoire allouée ou la mémoire total, vous pouvez utiliser les fonctions suivantes si votre environnement les fournit:

2
Siddharth

char * a = new char [10];

Ma question est la suivante: comment puis-je obtenir la longueur d'un omble *

C'est très simplement. :) Il suffit d'ajouter une seule déclaration

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

Maintenant, vous pouvez obtenir la taille du tableau alloué

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

Beaucoup ont mentionné ici la fonction standard C std :: strlen. Mais il ne renvoie pas la taille réelle d'un tableau de caractères. Il ne renvoie que la taille du littéral de chaîne stocké.

La différence est la suivante. si prendre votre extrait de code comme exemple

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

alors std :: strlen (a) retournera 5 au lieu de 6 comme dans votre code.

La conclusion est donc simple: si vous devez allouer de manière dynamique un tableau de caractères, envisagez l’utilisation de la classe std::string. Il a la taille methof et sa longueur synonyme qui permet d’obtenir la taille du tableau à tout moment.

Par exemple

std::string s( "aaaaa" );

std::cout << s.length() << std::endl;

ou

std::string s;
s.resize( 10 );

std::cout << s.length() << std::endl;
2
Vlad from Moscow

Vous pouvez implémenter vos propres fonctions new et delete, ainsi qu'une fonction get-size supplémentaire:

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

Vous pouvez également remplacer les opérateurs new et delete de manière similaire.

2
barak manos

Le problème avec l'opérateur sizeof est qu'il vous renvoie la quantité de stockage nécessaire, en octets, pour stocker l'opérande. 

La quantité de mémoire nécessaire pour stocker un caractère est toujours de 1 octet. Donc, sizeof(char) retournera toujours 1.

char a[] = "aaaaa";

int len1 = sizeof(a)/sizeof(char); // length = 6
int len2 = sizeof(a);              // length = 6;

C'est la même chose pour len1 et len2 car cette division de 1 n'influence pas l'équation. 

La raison pour laquelle len1 et len2 portent la valeur 6 est liée au caractère de fin de chaîne '\0'. Ce qui est aussi un caractère qui ajoute un autre caractère à la longueur. Par conséquent, votre longueur sera de 6 au lieu de 5 que vous attendiez. 

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

Vous avez déjà mentionné que la longueur s'avère être ici 4, ce qui est correct. Là encore, l'opérateur sizeof renvoie la quantité de stockage de l'opérande et, dans votre cas, il s'agit d'un pointeur a. Un pointeur nécessite 4 octets de stockage et sa longueur est donc 4 dans ce cas. Puisque vous le compilez probablement en un binaire 32 bits. Si vous aviez créé un fichier binaire 64 bits, le résultat serait 8.

Cette explication pourrait être ici déjà être ici. Je veux juste partager mes deux cents.

1
Montaldo

quand new alloue un tableau, selon le compilateur (j'utilise gnu c ++), le mot devant le tableau contient des informations sur le nombre d'octets alloués.

Le code de test:

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

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

    }
}

sur ma machine jette dehors:

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

Je ne recommanderais pas cette solution (le vecteur est meilleur), mais si vous êtes vraiment désespéré, vous pouvez trouver une relation et pouvoir conclure le nombre d'octets alloués à partir du tas.

0
sak

Dans C++17 (ou plus récent), vous pouvez utiliser std::string_view en tant que wrapper zéro pour les littéraux de chaîne.

0
bobah

Vous pouvez trouver la longueur d'une chaîne char * comme ceci:

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

sprintf () imprime le mystère sur lui-même et renvoie le nombre de caractères imprimés.

0
DevonJohn

Vous pouvez créer un caractère de suivi, par exemple, vous pouvez ajouter n'importe quel caractère spécial, par exemple, "%" à ​​la fin de votre chaîne, puis vérifier l'occurrence de ce caractère.
Mais c'est une manière très risquée que ce personnage puisse être ailleurs aussi dans le personnage *

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* 

Sinon, définissez une structure personnalisée pour suivre la longueur et allouer de la mémoire. 

0
Pratik Singhal