Size of String Array Passed to Function

Thank you for reading this and attempting to help me.

I'm having trouble trying to determine the size of a string array that is passed to a function. Normally, this would work pretty well if the array was created in the same scope.

int size = sizeof(array)/sizeof(array[0]);

However, I figured out that when passing an array (by value) to a function, you actually only pass the pointer to the first element of the array. So when I do the following inside the function...I get this:

1
2
3
4
5
6
sizeof(array) = 4
sizeof(array[0]) = 32
size = 4/32 = 0

sizeof(*array) = 32
sizeof(&array) = 4


Does anyone know how I can determine the number of elements in the string array that is passed to a function?

Thanks for your help!
No, you can't. Generally, you pass it as an argument to the function.
Thanks firedraco. I feared that would be the case.

If someone knows an alternative solution, please share!
Do strings end in a '\0' character? If they do you could just have a pointer that starts at the first memory location of the string array, checks if it points to a '\0' character gets increased by one and then continues on checking. You would use the sizeof(array) to find out how many memory locations it would need to search. Each time you hit a '\0' it means that there is another string inside that array... This is all guess work, I'm sure this would not work as smoothly as I am saying but it should be possible in theory.
You would use the sizeof(array) to find out how many memory locations it would need to search.
Looks like you missed the point of the thread.

Each time you hit a '\0' it means that there is another string inside that array...
No, it doesn't. It means you found the end of the string. Putting more than one string in a single array is just a recipe for maddening complexity.

strlen() works just fine to determine the size of the string, but that's not what OP is asking. He wants the size of the array.
Ya ignore what I was saying, no idea what I was thinking. I had thought that the strings would appear one after the other in memory which after testing it turns out that they don't...

Why doesn't sizeof(array) return the number of bytes used by the string array? Is it because a string is a class rather than a data type?

I phrased my idea horribly in my earlier post but the plan was to use a pointer to treat the string arrays as one huge string and then go from there.

Also, when I do
 
(sizeof(array)/sizeof(string))


I get the size of the string array + 1, why can't he just use this to find the size of the array?
Last edited on
^OP explains why quite well IMO.
Alright, I have a semi-working function that takes an array of strings and tells how many different strings are inside the array, the only problem is that if the size of the array is larger than 10 and you try to access the last part of the array(9) it will read the array just fine, it reads the first character of the array.... and then breaks. Every other time it works just fine, if you increase the size of the array to 11 it will work again.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <string>

using namespace std;

int findsize(string*);
int count_numberITZ = 0;

int main()
{
    string test[11];
    test[0] = "HAGA2";
    test[1] = "dude2";
    test[2] = "mandude";
    test[3] = "man2";
    test[4] = "WOAH";
    test[5] = "heh";
    test[6] = "Shame";
    test[7] = "Dude";
    test[8] = "Huh";
    test[9] = "Fii ";





 /*   lul = (char*)test[0].data();
    cout << (void *)lul<< endl;
    lul = (char*)test[1].data();
    cout << (void *)lul<< endl;
    cout << (void *)exta->data() << endl;
    exta += 1;
    cout << (void *)exta->data() << endl;
    cout << (void *)exta; */


    cout << findsize(test);
    return 0;
}

int findsize(string *stringpt)
{
    static char * characterpt;
    static int size = 0;
    characterpt = (char*)stringpt->c_str();
    cout << characterpt << endl;
    for (unsigned short int i = 0; i <= stringpt->size(); i++)
    {
        cout <<*characterpt;
        if ((*characterpt == '\0' && (*(char*)(stringpt + 1)->data() >= 32 && *(char*)(stringpt + 1)->data() < 128) || *(char*)(stringpt + 1)->data() == '\0'))
        {
            size++;
            stringpt++;
            cout << endl;
            findsize(stringpt);
            break;

        }
        else
        characterpt++;
    }
    return size;
}


The couts are in there so you can see where it breaks.... I have a feeling it has to do with the fact that the function is recursive(overloaded stack maybe? I have no idea first time using recursion)

Anyone know what is wrong with it, if I can fix this last crashing problem it would work perfectly.
I...
What?
How did you ever come up with this?

1
2
3
4
5
6
7
8
9
10
11
    string test[11];
    test[0] = "HAGA2";
    test[1] = "dude2";
    test[2] = "mandude";
    test[3] = "man2";
    test[4] = "WOAH";
    test[5] = "heh";
    test[6] = "Shame";
    test[7] = "Dude";
    test[8] = "Huh";
    test[9] = "Fii ";
Okay, it's a little odd that you wouldn't initialize everything, but I guess it's not wrong.

static char * characterpt;
Getting a little suspicious...

for (unsigned short int i = 0; i <= stringpt->size(); i++)
I kinda see your mental process, but std::string::size() doesn't work that way.
http://www.cplusplus.com/reference/string/string/size/

if ((*characterpt == '\0' && (*(char*)(stringpt + 1)->data() >= 32 && *(char*)(stringpt + 1)->data() < 128) || *(char*)(stringpt + 1)->data() == '\0'))
Oh, my God.


What exactly is this function trying to do, and why isn't the size of the array being passed?
The function returns the size of the array :P. I used std::string::size() to find the number of characters in the particular string that my pointer is pointing to, then that number has to be incremented by one because I am dealing with cstrings(which have the null terminator at the end).

The huge ungodly if statement essentially does this: If the current character we are looking at is a '\0' character AND the first character of the next string in the array is something readable by humans OR if the next string is empty, move the string pointer by one and call itself.

This repeats until the function reaches the end of the string array, at which point it breaks out of the loop(the for statements will never actually finish until the end of the function).

The goal of the function was to create something that if you gave it nothing but an array of strings, it would be able to return all the values inside that string array and give how many different strings are inside the array.

Ignore the commented section of code... That was for testing purposes, thats how I found out you have to use std::string::data() to get a pointer to the actual characters inside a string rather than a pointer to the string object.


 
(*(char*)(stringpt + 1)->data() >= 32 && *(char*)(stringpt + 1)->data() < 128)


That just checks if the ascii value of the first character in the next string is within the ranges of human readable characters.

Problem is that after a certain array size the function breaks when reading the last string in the array.
[code]
template< typename T, size_t N >
size_t ArraySize( T (&)[ N ] )
{ return N; }
[code]

Works on older versions of GCC. The correct declaration is (const &) if your compiler doesn't
complain.

This works for all stack-based arrays.
How would you use templates? I tried doing
int size_temp = ArraySize(test);
but my compiler says it is not declared in the current scope.

Which header file is it included in?
No, sorry. I still have no idea what you're trying to do. Could you explain your reasoning in full detail?

EDIT: It's not declared in any header. It's a function jsmith just wrote up.
I should add that the function only works with stack arrays provided that the compiler has enough type information.
In other words:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//will fail:
size_t f(T *array){
    return ArraySize(array);
}

//will fail:
size_t f(T array[]){
    return ArraySize(array);
}

//will work:
size_t f(T array[10]){
    return ArraySize(array);
}

//will work:
template <size_t S>
size_t f(T array[S]){
    return ArraySize<T,S>(array);
}
Last edited on
Alright, I'll start with the reason. The OP asked if there was a way to find the size of an array of strings, I would assume so that he could use dynamically allocated string arrays. I thought that there had to be a way to do this by only using a pointer to the string as the starting point, my logic was that: The OS knows how it is divided up, therefor there must be a pattern that can be used to determine the array size.

The first line of code
static char * characterpt;

Is just a simple pointer to a single character, I have it as a static so the compiler won't try and re-initialize it every time findsize() calls itself.

characterpt = (char*)stringpt->c_str();

std::string::c_str() returns a pointer to a null terminated cstring containing a copy of the data inside the std::string. This is returned as a const char, so I typecasted it to a char pointer to allow my characterpt to point to the memory location of the first character in the string.

stringpt is a pointer to the first string inside the string array that was passed to it(test[0])

for (unsigned short int i = 0; i <= stringpt->size(); i++)

This for loop is what cycles through each individual character inside the strings. std::string::size() returns the amount of characters in the C++ string(without a null terminator) which is why it is <= rather than the usual <, by adding the equals it accounts for the null terminator found at the end of the cstrings.


if ((*characterpt == '\0' && (*(char*)(stringpt + 1)->data() >= 32 && *(char*)(stringpt + 1)->data() < 128) || *(char*)(stringpt + 1)->data() == '\0'))

Messiest part of the code, it works by looking at the current character pointed to by characterpt checking if it indicates the end of a string(if it is a null character) if it does AND if the next string contains human readable characters(This is to prevent the function to continue moving through the computers memory in search of more strings), then we have :

stringpt++;

Which increments the string pointer by one, moving us over to the next string inside the array. stringpt now points to test[1].

If the if statement evaluates as false, then the pointer to the character inside the string is incremented by one, which moves the pointer onto the next character.

The function now call itself, just this time it looks at the data inside test[1] rather than test[0]. This pattern repeats until it reaches the point where either: There is no null terminator at the end of a string, or the string contains unreadable characters(This means that the stringpt overshot the number of strings inside the array and is now pointing at random data in memory)


A pointer must be set to either std::string::c_str() or std::string::data() because the actual characters inside the string are not stored inside the class itself, instead the string class contains a pointer to a location in memory that contains the characters.

This is why if you do the sizeof() a string variable it will always be four bytes long, no matter how many characters are "inside" the string object.

EDIT:

How does that template work? I can't find anything about a function called ArraySize(I assume this is a function since I am completely unfamiliar with templates and how they work).

Also, I realize now that if you are creating a dynamic array, you will know the size of the array because it will be a variable, feel somewhat of an idiot now >.>

EDIT2: Function works correctly now, no idea why. All of a sudden it just works without any problems.


Last edited on
Well, I still can't grasp your reasoning (or maybe I just don't feel like trying. I don't know), but no. Having just a pointer, there is no portable way of knowing the size of an array, dynamically-allocated or not. There are unportable ways (maybe), but you can trust me is easier to just pass the size.

Don't loop using recursion, in C++. It's just annoying. And certainly don't recurse non-reentrant functions. size should be passed as a parameter, and characterpt doesn't need to be neither passed nor static.
Topic archived. No new replies allowed.