How to get the real and total length of char * (char array)?

303,860

Solution 1

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...

Solution 2

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

Otherwise, there is no way to determine that information

Solution 3

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.

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

Solution 5

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.

Share:
303,860
herohuyongtao
Author by

herohuyongtao

Stack Exchange Data Explorer - You're an amateur developer until you realize that everything you write sucks. - We're going to go that way, really fast. And if something gets in our way, we'll turn.

Updated on February 08, 2020

Comments

  • herohuyongtao
    herohuyongtao about 4 years

    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");
    
  • juanchopanza
    juanchopanza over 10 years
    strlen will not reliably give the length of the array.
  • JAB
    JAB over 10 years
    @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).
  • Maroun
    Maroun over 10 years
    strlen does not count the '\0'.
  • Olotiar
    Olotiar over 10 years
    @JAB This is a good remark, though I don't know of any standard way to access that information.
  • Maroun
    Maroun over 10 years
    Depends on s.. Is it a C String?
  • Mike Seymour
    Mike Seymour over 10 years
    Only if you put a terminated string in the array; and then you'll get the length of the string, not the array.
  • JAB
    JAB over 10 years
    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.
  • DarkDust
    DarkDust over 10 years
    I guess the you didn't want to paste the first three lines.
  • Mike Seymour
    Mike Seymour over 10 years
    @JAB: Oh yes, I just noticed the question is asking about two languages at once. I wish people would stop doing that.
  • DarkDust
    DarkDust over 10 years
    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" ;-)
  • ragip
    ragip over 10 years
    Put your array like this , and try please... char a[]="aaaaa"; WriteString (100, 225, &a);
  • Jarod42
    Jarod42 over 10 years
    @ps06756: still crashes stringVar = new char[10], and doesn't answer the OP question.
  • John Dibling
    John Dibling over 10 years
    If he's using new, he can't be using C.
  • DarkDust
    DarkDust over 10 years
    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.
  • ragip
    ragip over 10 years
    You all right. I give sample code for idea.But This is only a code part.
  • molbdnilo
    molbdnilo over 10 years
    @JAB That would still only work if it's dynamically allocated.
  • ragip
    ragip over 10 years
    If you want you can use this code... int WriteString(char *s){ return strlen(s); }
  • herohuyongtao
    herohuyongtao over 10 years
    For my example (updated), how to get 10 as strlen can only get me 5?
  • JAB
    JAB over 10 years
    @JohnDibling True, but the question was tagged with both C++ and C (though it is not anymore).
  • Olotiar
    Olotiar over 10 years
    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++
  • Elias Van Ootegem
    Elias Van Ootegem over 10 years
    @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
  • DarkDust
    DarkDust over 10 years
    +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
    DarkDust over 10 years
    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.
  • ragip
    ragip over 10 years
    Because it is only a code part from my projects. Actually it is a tft display driver code for fujitsu chip.
  • Bill Lynch
    Bill Lynch over 10 years
    If you set all of the values of a char * array to '\0', then strlen() will return 0.
  • Siddharth
    Siddharth over 10 years
    @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
    Siddharth over 10 years
    Please read the previous answers and the question to get a firm idea of the question being asked here. Thank you.
  • A Person
    A Person over 10 years
    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...
  • Elias Van Ootegem
    Elias Van Ootegem over 10 years
    @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
    Elias Van Ootegem over 9 years
    @APerson: I did mean to say that using sizeof *a is better than using sizeof <type>, 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
  • rbaleksandar
    rbaleksandar almost 7 years
    @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.
  • Toby Speight
    Toby Speight about 4 years
    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
    Toby Speight about 4 years
    That's just (a poor implementation of) strlen(), with all its limitations ().
  • Theforgotten
    Theforgotten over 3 years
    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).