How to get the real and total length of char * (char array)?
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 usestrlen(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.
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, 2020Comments
-
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 thatlength
here will be always be4
(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 its10
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");
- how can I get its real
-
juanchopanza over 10 years
strlen
will not reliably give the length of the array. -
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 over 10 years
strlen
does not count the'\0'
. -
Olotiar over 10 years@JAB This is a good remark, though I don't know of any standard way to access that information.
-
Maroun over 10 yearsDepends on
s
.. Is it a C String? -
Mike Seymour over 10 yearsOnly if you put a terminated string in the array; and then you'll get the length of the string, not the array.
-
JAB over 10 yearsAssuming 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 over 10 yearsI guess the you didn't want to paste the first three lines.
-
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 over 10 yearsUgh, 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 over 10 yearsPut your array like this , and try please... char a[]="aaaaa"; WriteString (100, 225, &a);
-
Jarod42 over 10 years@ps06756: still crashes
stringVar = new char[10]
, and doesn't answer the OP question. -
John Dibling over 10 yearsIf he's using
new
, he can't be using C. -
DarkDust over 10 yearsYour code doesn't even compile. No
return
statement, no}
, and wrapping a call tostrlen
in a function with unused arguments, unused variables and misleading name is absolutely horrible. Also, you're trying to pass achar **
as argument in your comment. -
ragip over 10 yearsYou all right. I give sample code for idea.But This is only a code part.
-
molbdnilo over 10 years@JAB That would still only work if it's dynamically allocated.
-
ragip over 10 yearsIf you want you can use this code... int WriteString(char *s){ return strlen(s); }
-
herohuyongtao over 10 yearsFor my example (updated), how to get 10 as
strlen
can only get me 5? -
JAB over 10 years@JohnDibling True, but the question was tagged with both
C++
andC
(though it is not anymore). -
Olotiar over 10 yearsYou can't. Use a sentinel (special delimiter character), an
int
to remember the length, a custom made struct, or a higher level structure likestd::vector
in c++ -
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 toa
. You can usestrlen(a)
afterstrcpy
, and it'll return 5, but getting the 10 is not possible, not unless you do something likechar *a = calloc(10, sizeof *a);
, thenfor(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++: usestd::string
orstd::vector
-
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 over 10 yearsWhy do you insist on wrapping
strlen
in a function calledWriteString
? Your function does not write a string, it returns the length of a string. -
ragip over 10 yearsBecause it is only a code part from my projects. Actually it is a tft display driver code for fujitsu chip.
-
Bill Lynch over 10 yearsIf you set all of the values of a char * array to
'\0'
, thenstrlen()
will return 0. -
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 over 10 yearsPlease read the previous answers and the question to get a firm idea of the question being asked here. Thank you.
-
A Person over 10 yearsJust 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 over 10 years@Siidheesh: Strictly speaking
a[0] == 0[a] == *(a+0)
, but the main reason for usingsizeof *a
is when using other types than char, or usign pointers to pointers in custom allocators. considervoid my_alloc(void **ptr, size_t size) { (*ptr) = malloc(size*sizeof(*(*ptr)));}
this will work when allocating structs, ints, chars... any type, whereassizeof(type)
requires your knowing the type. -
Elias Van Ootegem over 9 years@APerson: I did mean to say that using
sizeof *a
is better than usingsizeof <type>
, and a lot better thansizeof a
(which is not always what you want). Personally, I also happen to prefer*a
overa[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 seea[0]
, I might be assume (wrongly) thata
is a local array variable, and not a NULL pointer -
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 usemalloc
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 about 4 yearsSo 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 about 4 yearsThat's just (a poor implementation of)
strlen()
, with all its limitations (). -
Theforgotten over 3 yearsThis 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).