How to get the length of a char array?

Asked

Viewed 1,067 times

2

How do I get the size of a set of char (char**)? The way I’m trying is always returning me the value 4.

const char* opcSalgados[] = { "Pastel", "Mini pizza", "Coxinha", "Pao de queijo", "Pao de frango com queijo", "Pao de carne" };

void ImprimeMenu(const char** menuOpc)
{
    int Length = sizeof(menuOpc[0]) / sizeof(char); // Sempre me retorna o valor 4, deveria me retornar o valor o 6
    printf("Length: %i\n", Length);

    for (int i = 0; i < Length; i++)
        printf("%i - %s\n", i + 1, menuOpc[i]);
}

2 answers

3


It is possible to know the size of an array passed as an argument to a function using templates and type deduction:

template <size_t N>
void imprimeMenu(const char *(&menuOpc)[N])
{
  int Length = N;
  printf("Length: %i\n", Length);

  for (int i = 0; i < Length; ++i)
    printf("%i - %s\n", i + 1, menuOpc[i]);
}

Notice how the parameter differs with your:

template <size_t N>
void imprimeMenu(const char *(&menuOpc)[N])

In this case, we have a parameter menuOpcof the kind reference to an array of const char * fixed-size N. When passing your array opcSalgados for the function (as shown below), this template will deduce parts of the parameter type that are known at compiler time.

imprimirMenu(opcSalgados);

So given any size M of an array, type deduction will conclude that the value of N needs to be equal to M, so that the function template instance is a suitable candidate for the argument types.

It is possible to simplify this code using the container Std::array, which is effectively a fixed size array, but with a better interface:

std::array<const char *, 6> opcSalgados = {
    "Pastel", "Mini pizza",
    "Coxinha", "Pao de queijo",
    "Pao de frango com queijo", "Pao de carne"
};

template <size_t N>
void imprimeMenu(std::array<const char *, N> menuOpc)
{ /* mesma implementação… */ }

The disadvantage of using std::array is that its size needs to be specified in the template parameter (as seen in the code: std::array<const char *, 6>). If your compiler supports C++17, this problem goes away with the new deduction notes:

std::array opcSalgados = {
    "Pastel", "Mini pizza",
    "Coxinha", "Pao de queijo",
    "Pao de frango com queijo", "Pao de carne"
};

The template parameters of std::array are automatically deducted by arguments passed to the constructor.

In any case, when you know the fixed size of the array (be it a primitive array, or the container std::array), it is possible to use the loop for based on intervals (or Range-based for loop) from C++11:

template <size_t N>
void imprimeMenu(const char *(&menuOpc)[N]) // ou std::array<const char *, N>
{
  std::printf("Length: %zu\n", N);
  int i = 1;
  for (auto opcao : menuOpc)
    std::printf("%i - %s\n", i++, opcao);
}

Where auto shall be deducted for the type of menuOpc elements (in this case, const char *). That variation of for ensures that you will never have problems like accessing indexes out of array size etc.

If you need to pass other arrays with different element types, just enter one more generic type in the template parameters and use it instead of const char *:

template <typename T, size_t N>
void imprimeMenu(T(&menuOpc)[N]) // ou std::array<T, N>

Note, however, that now the implementation needs to meet any type that is deduced for T:

template <typename T, size_t N>
void imprimeMenu(T(&menuOpc)[N]) // ou std::array<T, N>
{
  std::cout << "Length: " << N << '\n'; // Aqui.
  int i = 1;
  for (auto opcao : menuOpc)
    std::cout << i++ << " - " << opcao << '\n'; // Aqui.
}
  • Thank you, your example worked correctly. I have a question, is it possible to use, more than one template in this case? In the case of a different variable, it can be several types(double, float, int, long, const long). An example of what I am trying to do (the example is wrong), if it is not clear: https://paste.ofcode.org/343rbSDDTse4zxafLW7sVRy

  • @cYeR You can enter one more generic type in the template parameters and use it instead of const char *. I will edit the answer as per.

  • Thank you, I implemented in my functions according to your example and worked perfectly.

1

The compiler only knows the size of the array in its scope, in another scope it cannot know and has to pass the size by parameter.

#include <stdio.h>

void ImprimeMenu(char *menuOpc[], size_t length) {
    for (int i = 0; i < length; i++) printf("%i - %s\n", i + 1, menuOpc[i]);
}

int main(void) {
    char *opcSalgados[] = { "Pastel", "Mini pizza", "Coxinha", "Pao de queijo", "Pao de frango com queijo", "Pao de carne" };
    ImprimeMenu(opcSalgados, sizeof(opcSalgados) / sizeof(opcSalgados[0]));
}

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

  • I know that passing the argument works perfectly, what I’m trying to do is calculate within the function, there is no way to do this calculation within the function? I think the code would be much cleaner.

  • It doesn’t. Some people create an abstraction for the array that accompanies the size, so no longer need a parameter. In fact the use of array this way is little used, it works more in exercises. It is more a simple allocator than a data structure, although it can be used as well.

  • Don’t have another solution then? Maybe using Std::vector(Size method)? I’m trying to decrease the maximum number of arguments because the original function (this was just an example) already has many arguments which end up soiling the main.

  • You did not put the language and the code seems to be C. If it is C++, not only can it, but it should be Vector or other higher-level structure, and the array C only use as allocation or extreme optimization. Even when you don’t need everything from Vector and needs more performance (although it is already practically the same as other simpler structures), has the Array: https://answall.com/q/163424/101

  • And how would it be to move to an Std::vector? It would go like this? https://paste.ofcode.org/JNWkGS9DdJQHG8bgzTymts

  • No, in C++ practically not used char *, uses string. In addition, within the normal range, the heap and not in the stack.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.