Hoe krijg ik de echte en totale lengte van char * (char array)?

Voor een char []kan ik de lengte gemakkelijk krijgen door:

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

Ik kan echter niet op deze manier de lengte van een char *krijgen door:

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

omdat, ik weet, ahier een aanwijzer is, zodanig dat lengthhier altijd 4zal zijn (of iets anders in systemen).

Mijn vraag is hoe kan ik achteraf de lengte van een char *krijgen? Ik weet dat iemand me kan uitdagen dat je de 10al kent omdat je hem net hebt gemaakt. Ik wil dit weten omdat deze stap om de lengte ervan te krijgen, ver verwijderd kan zijn van de oprichting ervan en ik wil niet ver teruggaan om dit aantal te controleren. Bovendien wil ik ook de echte lengte weten.

Om specifieker te zijn

  • hoe kan ik de echte length=5krijgen?
  • hoe kom ik aan de totale length=10?

voor het volgende voorbeeld:

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

Antwoord 1, autoriteit 100%

Dat kan niet. Niet met 100% nauwkeurigheid in ieder geval. De aanwijzer heeft geen lengte/grootte maar zijn eigen. Het enige dat het doet, is naar een bepaalde plaats in het geheugen wijzen die een char bevat. Als dat teken deel uitmaakt van een tekenreeks, kunt u strlengebruiken om te bepalen welke tekens volgen op degene waarnaar momenteel wordt verwezen, maar dat betekent niet dat de arrayin uw geval is zo groot.
Kortom:

Een pointeris geen array, dus het hoeft nietom te weten wat de grootte van de array is. Een aanwijzer kan naar een enkele waarde verwijzen, dus een aanwijzer kan bestaan zonder dat er zelfs maar een array is. Het maakt niet eens uit waar het geheugen waarnaar het verwijst zich bevindt (alleen-lezen, heap of stapel… maakt niet uit). Een aanwijzer heeft geen andere lengte dan zichzelf. Een aanwijzer is gewoon…
Overweeg dit:

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

Een aanwijzer kan een enkele char zijn, maar ook het begin, het einde of het midden van een array…
Zie tekens als structs. Soms wijst u een enkele struct toe op de heap. Ook dat maakt een aanwijzer zonder array.

Het is onmogelijk om alleen een aanwijzer te gebruiken om te bepalen hoe groot een array is waarnaar deze verwijst. Je kunt er het dichtst bij komen door callocte gebruiken en het aantal opeenvolgende \0-tekens te tellen dat je via de aanwijzer kunt vinden. Dat werkt natuurlijk niet als je eenmaal dingen hebt toegewezen/opnieuw toegewezen aan de sleutels van die array en het mislukt ook als het geheugen net buitenvan de array toevallig \0ook. Dus het gebruik van deze methode is onbetrouwbaar, gevaarlijk en gewoon over het algemeen dom. niet doen. Doen. Het.

Nog een analogie:
Zie een aanwijzer als een verkeersbord, het wijst naar Town X. Het bord weet niet hoe die stad eruitziet, en het kan het niet schelen of het kan schelen wie er woont. Het is zijn taak om u te vertellen waar u Town Xkunt vinden. Het kan je alleen vertellen hoe ver die stad is, maar niet hoe groot het is. Die informatie wordt voor verkeersborden niet relevant geacht. Dat kun je alleen ontdekken door naar de stad zelf te kijken, niet naar de verkeersborden die je in de richting wijzen

Dus, met behulp van een aanwijzer is het enige dat u kunt doen:

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

Maar dit werkt natuurlijk alleen als de array/string \0-beëindigd is.

Terzijde:

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

kent feitelijk size_t(het retourtype van sizeof) toe aan een int, beste schrijf:

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

Aangezien size_teen niet-ondertekend type is en sizeofgrotere waarden retourneert, kan de waarde van lengthiets zijn dat u niet had verwacht. ..


Antwoord 2, autoriteit 26%

Als de char *op 0 is beëindigd, kunt u strlen

gebruiken

Anders is er geen manier om die informatie te achterhalen


Antwoord 3, autoriteit 12%

Er zijn maar twee manieren:

  • Als de geheugenaanwijzer naar door uw char *een C-tekenreeks vertegenwoordigt (dat wil zeggen, het bevat tekens met een 0-byte om het einde aan te geven), kunt u strlen(a).

  • Anders moet je de lengte ergens opslaan. Eigenlijk wijst de aanwijzer slechts naar éénchar. Maar we kunnen het behandelen alsof het naar het eerste element van een array verwijst. Aangezien de “lengte” van die array niet bekend is, moet je die informatie ergens opslaan.


Antwoord 4, autoriteit 7%

  • In C++:

Gebruik gewoon std::vector<char>die de (dynamische) grootte voor u behoudt. (Bonus, geheugenbeheer gratis).

Of std::array<char, 10>die de (statische) grootte behouden.

  • In zuivere C:

Maak een structuur om de informatie te bewaren, zoiets als:

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

Antwoord 5, autoriteit 5%

Gezien alleen de aanwijzer, kun je dat niet. Je moet de lengte behouden die je hebt doorgegeven aan new[]of, beter nog, std::vectorgebruiken om zowel de lengte bij te houden als de geheugen wanneer je ermee klaar bent.

Opmerking: dit antwoord heeft alleen betrekking op C++, niet op C.


Antwoord 6, autoriteit 5%

char *a = nieuwe char[10];

Mijn vraag is hoe kan ik de lengte van een char krijgen *

Het is heel eenvoudig. 🙂 Het is voldoende om slechts één verklaring toe te voegen

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

Nu kun je de grootte van de toegewezen array krijgen

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

Velen noemden hier C standaardfunctie std::strlen. Maar het geeft niet de werkelijke grootte van een tekenreeks terug. Het geeft alleen de grootte van de opgeslagen letterlijke tekenreeks terug.

Het verschil is het volgende. als u uw codefragment als voorbeeld wilt nemen

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

vervolgens zal std::strlen(a) 5 teruggeven in plaats van 6 zoals in uw code.

Dus de conclusie is simpel: als je dynamisch een tekenreeks moet toewijzen, overweeg dan het gebruik van klasse std::string. Het heeft methof-grootte en zijn synoniemlengte waarmee je op elk moment de grootte van de array kunt krijgen.

Bijvoorbeeld

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

of

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

Antwoord 7, autoriteit 5%

Het ding met de sizeofoperator is dat het je de hoeveelheid opslagruimte geeft die nodig is, in bytes, om de operand op te slaan.

De hoeveelheid opslagruimte die nodig is om een char op te slaan is altijd 1 byte. Dus de sizeof(char)retourneert altijd 1.

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

Dit is hetzelfde voor zowel len1als len2omdat deze deling van 1 de vergelijking niet beïnvloedt.

De reden waarom zowel len1als len2de waarde 6 dragen, heeft te maken met de tekenreeksbeëindiging char '\0'. Dat is ook een char die nog een char aan de lengte toevoegt. Daarom wordt uw lengte 6 in plaats van de 5 die u verwachtte.

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

Je zei al dat de lengte hier 4 blijkt te zijn, wat correct is. Nogmaals, de operator sizeofretourneert de opslaghoeveelheid voor de operand en in jouw geval is het een pointer a. Een pointer heeft 4 bytes opslagruimte nodig en daarom is de lengte in dit geval 4. Aangezien u het waarschijnlijk naar een 32-bits binair bestand compileert. Als je een 64-bits binair bestand had gemaakt, zou het resultaat 8 zijn.

Deze uitleg kan hier al zijn. Ik wil gewoon mijn twee centen delen.


Antwoord 8, autoriteit 3%

U kunt uw eigen newen delete-functies implementeren, evenals een extra get-size-functie:

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

Als alternatief kunt u de operators newen deleteop dezelfde manier overschrijven.


Antwoord 9, autoriteit 2%

Dit klinkt misschien Evil™ en ik heb het niet getest, maar hoe zit het met het initialiseren van alle waarden in een array bij toewijzing aan '\0'en dan strlen()? Dit zou je je zogenaamde echte waardegeven, aangezien het zou stoppen met tellen bij de eerste '\0'die het tegenkomt.

Nou, nu ik erover nadenk, doe dit alsjeblieft nooit. Tenzij je in een hoop vuile herinneringen wilt belanden.

Ook voor het toegewezen geheugen of het totale geheugenkunt u de volgende functies gebruiken als uw omgeving deze biedt:


Antwoord 10

U kunt een back-tracker-teken maken, u kunt bijvoorbeeld een speciaal teken toevoegen, bijvoorbeeld ‘%’, aan het einde van uw tekenreeks en vervolgens controleren of dat teken voorkomt.
Maar dit is een zeer riskante manier omdat dat personage ook op andere plaatsen in de char*

. kan voorkomen

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* 

Definieer anders een aangepaste structuur om de lengte bij te houden en geheugen toe te wijzen.


Antwoord 11

wanneer new een array toewijst, afhankelijk van de compiler (ik gebruik gnu c++), bevat het woord voor de array informatie over het aantal toegewezen bytes.

De testcode:

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

op mijn computer dumpt:

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

Ik zou deze oplossing niet aanbevelen (vector is beter), maar als je echt wanhopig bent, zou je een relatie kunnen vinden en het aantal toegewezen bytes uit de heap kunnen afleiden.


Antwoord 12

Juiste vraag. Persoonlijk denk ik dat mensen pointers verwarren met arrays als resultaat van character pointers (char*), die bijna hetzelfde doel dienen als character arrays (char __[X]). Dit betekent dat pointers en arrays niet hetzelfde zijn, dus pointers bevatten natuurlijk geen specifieke grootte, alleen een adres als ik dat zou kunnen zeggen. Maar je kunt niettemin iets proberen dat lijkt op strlen.

int ssize(const char* s)
{
    for (int i = 0; ; i++)
        if (s[i] == 0)
            return i;
    return 0;
}

Antwoord 13

U kunt de lengte van een char *-string als volgt vinden:

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

Sprintf () drukt op zichzelf af en retourneert het aantal afgedrukte tekens.


Antwoord 14

U kunt dit proberen:

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

Antwoord 15

Strlen-opdracht werkt voor mij. U kunt het volgende code proberen.

// char * s

unsigned int  strLength=strlen(s);

Other episodes