77

For a char [], I can easily get its length by:

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

However, I cannot do like this to get the length of a char * by:

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

because, I know, a here is a pointer, such that length here will be always be 4 (or something other in different systems).

My question is that how can I get the length of a char * afterwards? I know someone may challenge me that you already know its 10 because you just created it. I want to know this because this step of getting its length may come long long way from its creation and I don't want to come long long way back to check this number. Moreover, I also want to know its real length.

To be more specific

  • how can I get its real length=5?
  • how can I get its total length=10?

for the following example:

char *a = new char[10]; 
strcpy(a, "hello");
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
herohuyongtao
  • 49,413
  • 29
  • 133
  • 174
  • 15
    `strlen`? (....) – Kiril Kirov Jan 09 '14 at 14:15
  • You cannot get the length of the array a pointer it points to. You need to keep track of it by other means. – juanchopanza Jan 09 '14 at 14:16
  • @KillianDS - yes, of course. I may have misunderstood the question, that's why I wrote a comment. – Kiril Kirov Jan 09 '14 at 14:18
  • 3
    @KirilKirov that will not give the length of the array. Well, it will, but only in special circumstances. – juanchopanza Jan 09 '14 at 14:18
  • @juanchopanza - true, but "My question is that how can I get the length of a char * afterwards" sounds a bit misleading - it's not clear if the expected result is the length of the _array_ or of the _string_, pointed by the pointer. – Kiril Kirov Jan 09 '14 at 14:19
  • 2
    This has been answered before, a pointer doesn't hold information about the size of the block of data it points to (if it points to an array), just its starting location in memory. – A Person Jan 09 '14 at 14:20
  • 1
    @KirilKirov Agreed, the "length of a char*" is not very clear. – juanchopanza Jan 09 '14 at 14:21
  • 6
    You may use `std::vector`, so you have the size, and memory management is done for you – Jarod42 Jan 09 '14 at 14:22
  • Using vectors won't work in C though, hurts portability :p, but a good idea nonetheless! – A Person Jan 09 '14 at 14:24
  • @Siidheesh - I disagree. First, the question is about C++, second - you still can take `char*` from a `vector`. Also, if you want really "portability" between C and C++, this means - use only C (and even then, it's not 100% "portable" in this sense) – Kiril Kirov Jan 09 '14 at 14:26
  • If there was a way around this problem, I imagine that passing the length of arrays around would be obsolete. –  Jan 09 '14 at 14:27
  • Just throw in a memset for zeroing out the memory locations, use strlen and bob's yer uncle xD – A Person Jan 09 '14 at 14:28
  • 1
    @herohuyongtao `a = "hello"` is wrong in so many ways.. But at least the edit makes the question a bit more clear. – Kiril Kirov Jan 09 '14 at 14:29
  • 2
    Could you please decide which language you're asking about? If it's C, then you can't use `new`; if it's C++, then you should use higher-level abstractions like `vector` to solve this problem. – Mike Seymour Jan 09 '14 at 14:32
  • @MikeSeymour I removed the C tag b/c as it is stated it is not a C question, I wish I noticed that earlier. – Shafik Yaghmour Jan 09 '14 at 14:34
  • 1
    The gist is to explicitly declare array structures as arrays unless otherwise required, because arrays can collapse easily into pointers but pointers cannot become arrays. – A Person Jan 09 '14 at 14:40
  • 1
    You may be interested in `std::array` too. – Jarod42 Jan 09 '14 at 15:04
  • 1
    Since the C tag has been added a removed several times I have flagged the question and we will let a mod determine this. – Shafik Yaghmour Jan 09 '14 at 16:45
  • This question appears to be off-topic because it is about C-Strings which any C or C++ programming book will tell you about. – quamrana Jan 10 '14 at 14:15
  • Found an interesting tidbit, read more at http://stackoverflow.com/questions/437150/can-someone-explain-this-template-code-that-gives-me-the-size-of-an-array. – A Person Jan 10 '14 at 15:55

16 Answers16

71

You can't. Not with 100% accuracy, anyway. The pointer has no length/size but its own. All it does is point to a particular place in memory that holds a char. If that char is part of a string, then you can use strlen to determine what chars follow the one currently being pointed to, but that doesn't mean the array in your case is that big.
Basically:

A pointer is not an array, so it doesn't need to know what the size of the array is. A pointer can point to a single value, so a pointer can exist without there even being an array. It doesn't even care where the memory it points to is situated (Read only, heap or stack... doesn't matter). A pointer doesn't have a length other than itself. A pointer just is...
Consider this:

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

A pointer can be a single char, as well as the beginning, end or middle of an array...
Think of chars as structs. You sometimes allocate a single struct on the heap. That, too, creates a pointer without an array.

Using only a pointer, to determine how big an array it is pointing to is impossible. The closest you can get to it is using calloc and counting the number of consecutive \0 chars you can find through the pointer. Of course, that doesn't work once you've assigned/reassigned stuff to that array's keys and it also fails if the memory just outside of the array happens to hold \0, too. So using this method is unreliable, dangerous and just generally silly. Don't. Do. It.

Another analogy:
Think of a pointer as a road sign, it points to Town X. The sign doesn't know what that town looks like, and it doesn't know or care (or can care) who lives there. It's job is to tell you where to find Town X. It can only tell you how far that town is, but not how big it is. That information is deemed irrelevant for road-signs. That's something that you can only find out by looking at the town itself, not at the road-signs that are pointing you in its direction

So, using a pointer the only thing you can do is:

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

But this, of course, only works if the array/string is \0-terminated.

As an aside:

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

is actually assigning size_t (the return type of sizeof) to an int, best write:

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

Since size_t is an unsigned type, if sizeof returns bigger values, the value of length might be something you didn't expect...

Sean Breckenridge
  • 1,932
  • 16
  • 26
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
  • @herohuyongtao: using a pointer, you can't get the _max-length_. in your snippet `new char[10]` allocates 10 chars, and assigns the pointer to `a`. You can use `strlen(a)` _after_ `strcpy`, and it'll return 5, but getting the 10 is not possible, not unless you do something like `char *a = calloc(10, sizeof *a);`, then `for(i=0;a[i] == '\0';++i);` after that, `i-1` _could_ give you the total length of the memory allocated, if the memory right next to the allocated block doesn't _accidentally_ hold `\0`, too, so this is dangerous and bad. But you're using C++: use `std::string` or `std::vector` – Elias Van Ootegem Jan 09 '14 at 14:51
  • Just out of curiosity, isn't a[0]==0[a]==*a? Why would using sizeof (*a) be a better habit than using sizeof (a[0])? Unless you meant that it's better than using sizeof(a) by itself... – A Person Jan 09 '14 at 16:40
  • @Siidheesh: Strictly speaking `a[0] == 0[a] == *(a+0)`, but the main reason for using `sizeof *a` is when using other types than char, or usign pointers to pointers in custom allocators. consider `void my_alloc(void **ptr, size_t size) { (*ptr) = malloc(size*sizeof(*(*ptr)));}` this will work when allocating structs, ints, chars... any type, whereas `sizeof(type)` requires your knowing the type. – Elias Van Ootegem Jan 09 '14 at 16:54
  • @APerson: I did mean to say that using `sizeof *a` is better than using `sizeof `, and a lot better than `sizeof a` (which is not always what you want). Personally, I also happen to prefer `*a` over `a[0]`, simply because it makes it very clearl (IMHO) that a pointer is being dereferenced. When reviewing code, or hunting down the cause of a segfault, these lines that are my first port of call. When I see `a[0]`, I might be assume (wrongly) that `a` is a local array variable, and not a NULL pointer – Elias Van Ootegem Dec 29 '14 at 15:18
22

If the char * is 0-terminated, you can use strlen

Otherwise, there is no way to determine that information

Olotiar
  • 3,225
  • 1
  • 18
  • 37
  • 5
    `strlen` will not reliably give the length of the array. – juanchopanza Jan 09 '14 at 14:19
  • 1
    @Olotiar Unless you're working with a specific compiler and locate where the data regarding allocated memory is stored (after all, in order for memory allocation to work properly, the amount of memory that was allocated for that specific location needs to be stored somewhere so it won't be overlapped by another allocation and so that `free` will work properly). – JAB Jan 09 '14 at 14:19
  • 8
    `strlen` *does not* count the `'\0'`. – Maroun Jan 09 '14 at 14:19
  • @JAB This is a good remark, though I don't know of any standard way to access that information. – Olotiar Jan 09 '14 at 14:21
  • @JAB That would still only work if it's dynamically allocated. – molbdnilo Jan 09 '14 at 14:40
  • For my example (updated), how to get 10 as `strlen` can only get me 5? – herohuyongtao Jan 09 '14 at 14:45
  • You can't. Use a sentinel (special delimiter character), an `int` to remember the length, a custom made struct, or a higher level structure like `std::vector` in c++ – Olotiar Jan 09 '14 at 14:50
  • @MarounMaroun Then just add +1 for the `\0`. One can also do the counting on his own by simply saving a copy of the pointer and increasing it gradually until the `\0` is reached. Of course one needs to make sure that the string is actually `\0`-terminated. Another thing that needs to be made clear here is that one has to use `malloc` or some other method for getting a continuous chunk of memory. Otherwise the incrementation of the pointer may land in a block that stores information from something else leading either to obtaining garbage data or a crash. – rbaleksandar Jul 27 '17 at 07:17
7

There are only two ways:

  • If the memory pointer to by your char * represents a C string (that is, it contains characters that have a 0-byte to mark its end), you can use strlen(a).

  • Otherwise, you need to store the length somewhere. Actually, the pointer only points to one char. But we can treat it as if it points to the first element of an array. Since the "length" of that array isn't known you need to store that information somewhere.

DarkDust
  • 90,870
  • 19
  • 190
  • 224
4
  • In C++:

Just use std::vector<char> which keep the (dynamic) size for you. (Bonus, memory management for free).

Or std::array<char, 10> which keep the (static) size.

  • In pure C:

Create a structure to keep the info, something like:

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);
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
4

So the thing with the sizeof operator is that it returns you the amount of storage needed, in bytes, to store the operand.

The amount of storage needed to store a char is always 1 byte. So the sizeof(char) will always return 1.

char a[] = "aaaaa";

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

This is the same for both len1 and len2 because this division of 1 does not influence the equation.

The reason why both len1 and len2 carry the value 6 has to do with the string termination char '\0'. Which is also a char which adds another char to the length. Therefore your length is going to be 6 instead of the 5 you were expecting.

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

You already mentioned that the length turns out to be 4 here, which is correct. Again, the sizeof operator returns the storage amount for the operand and in your case it is a pointer a. A pointer requires 4 bytes of storage and therefore the length is 4 in this case. Since you probably compile it to a 32-bit binary. If you'd created a 64-bit binary the outcome would be 8.

This explanation might be here already be here. Just want to share my two cents.

Montaldo
  • 863
  • 8
  • 16
3

Given just the pointer, you can't. You'll have to keep hold of the length you passed to new[] or, better, use std::vector to both keep track of the length, and release the memory when you've finished with it.

Note: this answer only addresses C++, not C.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Assuming he's only using C++. If the code needs to work as a C program as well, then `std::vector` will unfortunately not be much help. – JAB Jan 09 '14 at 14:22
  • 2
    @JAB: Oh yes, I just noticed the question is asking about two languages at once. I wish people would stop doing that. – Mike Seymour Jan 09 '14 at 14:23
  • 3
    If he's using `new`, he can't be using C. – John Dibling Jan 09 '14 at 14:27
  • @JohnDibling True, but the question was tagged with both `C++` and `C` (though it is not anymore). – JAB Jan 09 '14 at 14:45
3

char *a = new char[10];

My question is that how can I get the length of a char *

It is very simply.:) It is enough to add only one statement

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

Now you can get the size of the allocated array

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

Many mentioned here C standard function std::strlen. But it does not return the actual size of a character array. It returns only the size of stored string literal.

The difference is the following. if to take your code snippet as an example

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

then std::strlen( a ) will return 5 instead of 6 as in your code.

So the conclusion is simple: if you need to dynamically allocate a character array consider usage of class std::string. It has methof size and its synonym length that allows to get the size of the array at any time.

For example

std::string s( "aaaaa" );

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

or

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

std::cout << s.length() << std::endl;
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

You can implement your own new and delete functions, as well as an additional get-size function:

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

Alternatively, you can override the new and delete operators in a similar manner.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
barak manos
  • 29,648
  • 10
  • 62
  • 114
  • 2
    +1 for creativity, although I wouldn't recommend doing that in a real application. You'd also have to implement copy and resize. When using C++, there are better ways to solve the problem. – DarkDust Jan 09 '14 at 14:51
1

This may sound Evil™ and I haven't tested it, but how about initializing all values in an array at allocation to '\0' and then using strlen() ? This would give you your so-called real value since it would stop counting at the first '\0' it encounters.

Well, now that I think about it though, please don't Ever™ do this. Unless, you want to land in a pile of dirty memory.

Also, for the allocated memory or the total memory you may use the following functions if your environment provides them:

Siddharth
  • 1,146
  • 3
  • 15
  • 28
  • 1
    If you set all of the values of a char * array to `'\0'`, then `strlen()` will return 0. – Bill Lynch Jan 09 '14 at 15:40
  • @sharth, that is indeed the _real value_ he wants, since what you mentioned is only the case when the memory hasn't been used yet. Assuming he changes the elements by equalising them to _real values_ he won't get 0 from a call to strlen() anymore. – Siddharth Jan 09 '14 at 16:04
  • This can lead to some problems when the char array contains binary informations (image pointer for instance) : the array can contains '\0' bytes in the data and in this case, the data length is greater than strlen(data). – Theforgotten Oct 21 '20 at 11:15
1

Ok, I know this is an ancient thread. According to my experiments, an assignment like:

char* str = "blah";

does indeed append a null character. This code:

char* str = "blah";
cout << str;
cout << strlen(str);

Outputs:

blah

4

It still works if I change the number of characters assigned. Since the assignment does seem to add a \0 at the end, I don't understand the above admonitions ("strlen only works if there's a nul char" etc.) Am I missing something?

Robert M.
  • 575
  • 5
  • 17
  • 1
    String **literals** are null terminated automatically. See https://en.cppreference.com/w/cpp/language/string_literal – BuvinJ Jun 06 '23 at 12:59
  • 1
    That said, in my opinion, it's a truly terrible practice to write code passing around a char * with the assumption that it is definitely null terminated. If you want a "string", I think 99% of the time one is better off just using an std::string (or string type from some other library). You can pass them around just as well by reference, or pointer, to avoid needless copies (if that's a concern). The disadvantage of using some tiny amount of extra memory or processing with a wrapped object is generally negligible compared to the risk, or the pita, of using char * primitives. – BuvinJ Jun 06 '23 at 13:46
0

You can make a back-tracker character, ex, you could append any special character say "%" to the end of your string and then check the occurrence of that character.
But this is a very risky way as that character can be in other places also in the 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* 

Otherwise define a custom structure to keep track of length and allocate memory.

Pratik Singhal
  • 6,283
  • 10
  • 55
  • 97
  • 2
    Ugh, that smells awfully! Null-terminate the string instead. It's a bad idea to use a character that might turn up in actual text (like, "You owe me $1 for that terrible idea" ;-) – DarkDust Jan 09 '14 at 14:24
  • @ps06756: still crashes `stringVar = new char[10]`, and doesn't answer the OP question. – Jarod42 Jan 09 '14 at 14:27
0

when new allocates an array, depending on the compiler (i use gnu c++), the word in front of the array contains information about the number of bytes allocated.

The test code:

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

    }
}

on my machine dumps out:

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

I would not recommend this solution (vector is better), but if you are really desperate, you could find a relationship and be able to conclude the number of bytes allocated from the heap.

sak
  • 3
  • 2
0

Legit question. I personally think people confuse pointers with arrays as a result of character pointers (char*), which serve almost the same purpose as character arrays (char __[X]). This means that pointers and arrays are not the same, so pointers of course don't contain a specific size, only an address if I could say so. But nonetheless you can try something similar to strlen.

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

    return 0;
}
HolyRandom
  • 79
  • 1
  • 11
-1

You can find the length of a char* string like this:

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

sprintf() prints mystring onto itself, and returns the number of characters printed.

  • 1
    So it's exactly equivalent to `strlen`, and only works if the last character in the array is a NUL, and there are no NULs before that. – Toby Speight Feb 07 '20 at 14:24
-2

You could try this:

int lengthChar(const char* chararray) {
   int n = 0;
   while(chararray[n] != '\0')
     n ++;
   return n;  
}
Felipe Oriani
  • 37,948
  • 19
  • 131
  • 194
-4

Strlen command is working for me . You can try following code.

// char *s

unsigned int  strLength=strlen(s);
ragip
  • 9
  • 2
  • Depends on `s`.. Is it a C String? – Maroun Jan 09 '14 at 14:22
  • Only if you put a terminated string in the array; and then you'll get the length of the string, not the array. – Mike Seymour Jan 09 '14 at 14:22
  • I guess the you didn't want to paste the first three lines. – DarkDust Jan 09 '14 at 14:23
  • Put your array like this , and try please... char a[]="aaaaa"; WriteString (100, 225, &a); – ragip Jan 09 '14 at 14:27
  • Your code doesn't even compile. No `return` statement, no `}`, and wrapping a call to `strlen` in a function with unused arguments, unused variables and misleading name is absolutely horrible. Also, you're trying to pass a `char **` as argument in your comment. – DarkDust Jan 09 '14 at 14:32
  • You all right. I give sample code for idea.But This is only a code part. – ragip Jan 09 '14 at 14:37
  • If you want you can use this code... int WriteString(char *s){ return strlen(s); } – ragip Jan 09 '14 at 14:40
  • 2
    Why do you insist on wrapping `strlen` in a function called `WriteString`? Your function does not write a string, it returns the length of a string. – DarkDust Jan 09 '14 at 14:52
  • Because it is only a code part from my projects. Actually it is a tft display driver code for fujitsu chip. – ragip Jan 09 '14 at 14:58
  • Please read the previous answers and the question to get a firm idea of the question being asked here. Thank you. – Siddharth Jan 09 '14 at 16:32