22

i know two way's to get length of const char *

const char * str = "Hello World !";
int Size = 0;
while (str[Size] != '\0') Size++;

and other way is very simple

const char * str = "Hello World !";
size_t Size = strlen(str);

but i don't want to use str lib functions like strlen and i think this function use my first way behavior too. because in the pc world when we want to count something we need to count each block's and there is no magic to get the length with one movement so i think the first way is the best option to get length of const char *. other way i think the first way is maybe too heavy for heavy string's. so im confused. which way is better and why other way is not ?

JamesAlb
  • 263
  • 1
  • 3
  • 7
  • 5
    Something from the standard library will almost always be faster than anything you code yourself to do the same thing, and will certainly be less likely to have a bug. – Mark Ransom Jun 22 '17 at 04:23
  • 2
    Both of those samples are equivalent, but `strlen`  might be faster because of compiler specific things and regardless it's better to use the code that's already been written for you. – Etienne de Martel Jun 22 '17 at 04:24
  • 1
    Why don't you want to use `strlen()`? – Galik Jun 22 '17 at 04:24
  • 8
    Also, since this is C++, just use `std::string`, then you can use its `size()` method. – Etienne de Martel Jun 22 '17 at 04:25
  • 1
    Or use the new std::string_view together with your C string. –  Jun 22 '17 at 06:15
  • 1
    ` const char*` is a **pointer**. It does not have a length. **If** it points at a nul-terminated array of `char` you can talk about the length **of that array**. Don't muddle pointers and arrays; that leads to endless confusion. – Pete Becker Jun 22 '17 at 12:46

3 Answers3

38

Let's inspect the assembly listing of these two methods.

#include <cstddef>
#include <cstring>

int string_size_1()
{
    const char * str = "Hello World !";
    int Size = 0;
    while (str[Size] != '\0') Size++;
    return Size;
}

int string_size_2()
{
    const char * str = "Hello World !";
    size_t Size = strlen(str);
    return Size;
}

Using Clang 4.0.0 with flags -std=c++14 -O2

string_size_1():                     # @string_size_1()
        mov     eax, 13
        ret

string_size_2():                     # @string_size_2()
        mov     eax, 13
        ret

Link: https://godbolt.org/g/5S6VSZ

Both methods end up with exactly the same assembly listing. Also, the compiler optimizes away everything and just return a constant because the string literal is known during compile-time. So, in terms of performance, they are equally good.

But in terms of readability, strlen(str) is definitely better. A function call states the intention through the function name. A loop cannot do that.


Besides, std::string and std::string_view are more preferable than C-string in many cases. Consider them.

  • 1
    If you put a `\0` inside the string do you get the same compiled code? That would be a bug. – Mark Ransom Jun 22 '17 at 15:43
  • That's some seriously strange code generation for the first case, but I suppose it delivers the right answer eventually. – Mark Ransom Jun 22 '17 at 18:50
  • @MarkRansom both of those functions calculate the number 13, why do you think it strange that an optimising compiler recognise that? – Caleth Sep 06 '21 at 14:36
  • @Caleth the first sample is a little more complex than I'd expect the optimizer to handle at compile time, but I honestly don't remember exactly why I left that comment over 4 years ago. – Mark Ransom Sep 06 '21 at 15:36
3

In this case the answer is known at compile time:

template <std::size_t S>
constexpr std::size_t string_length
(
    char const (&)[S]
)
{
    return S - 1;
}

usage:

std::cout << string_length("example") << std::endl;

For cases where the string is not a compile time constant use strlen if only the pointer to the string is available, std::distance if both pointers to the beginning and end are available, or .size() if your dealing with a std::string

  • They specifically requested `const char *` as being the input, which your code won't work with – M.M Jun 22 '17 at 05:51
  • my answer did address char * as well. His example also deals with char[] type but simply forced the decay by not using auto. The spirit of both the question and the answer were clear. – Michael Maniscalco Jun 22 '17 at 06:00
3

3 years late but better late that never.

Short answer

#define length(array) ((sizeof(array)) / (sizeof(array[0])))

Long answer

So using sizeof(array) returns the size of the type of the array * the amount of elements. Knowing this, we could achieve this:

#define length(array) ((sizeof(array)) / (sizeof(array[0])))

and you would use it like:

type yourArray[] = {your, values};
length(yourArray);    // returns length of yourArray

For example:

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

#define length(array) ((sizeof(array)) / (sizeof(array[0])))


int main()
{
    const char *myStrings[] = {"Foo", "Bar", "Hello, World!"};    // 3 elements
    int myNums[] = {0, 1, 5, 7, 11037};    // 5 elements
    char myChars[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};    // 7 elements

    printf("Length of myStrings array: %lu\n", length(myStrings));
    printf("Length of myNums array: %lu\n", length(myNums));
    printf("Length of myChars array: %lu\n", length(myChars));

    return 0;

    /* Output:
           Length of myStrings array: 3
           Length of myNums array: 5
           Length of myChars array: 7 */
}

I tested it and it also works with uninitialized arrays, probably because they contain garbage (from being uninitialized) from the same type. Integer uninitialized arrays contain random integer numbers and const char* uninitialized arrays contain (null) which is treated as a const char*.

Now, this only works with arrays on the stack. Pointers pointing to space reserved in the heap used as an array would give unexpected results. For example:

int *myNums = (int *)malloc(3 * sizeof(int));    // Space for 3 integers
printf("Length of myNums: %lu\n", length(myNums));  // Outputs 2 instead of 3

So be advised. Who uses arrays on the heap anyways so whatever.

Note: This is relevant to this question as it works with const char * as requested. Works with other types too.

Clara
  • 70
  • 5
  • 1
    This fails miserably at giving the desired answer of 13 when presented `const char * str = "Hello World !"; length(str)`. And "Integer uninitialized arrays contain random integer numbers and const char* uninitialized arrays contain (null) which is treated as a const char*." is misleading. Programs that read uninitialised values have undefined behaviour, which you have observed (at one point) to be as if there were arbitrary values present. Other symptoms are possible – Caleth Sep 06 '21 at 14:38
  • @Caleth That's because this macro is intended to get the length of *an array int the stack*, not a pointer. Given a `const char *str[] = {"Hello World !"};` it returns the proper length of 1. Either way, I just realized that I misinterpreted the question, so that was my bad. Thank you for pointing it out – Clara Sep 06 '21 at 14:46
  • Yes, so this fails to answer the question posed – Caleth Sep 06 '21 at 14:47
  • It doesn't really help. The best way is to provide the size in an additional argument from the point, where we're still aware of it. – Attis Sep 27 '21 at 15:24