Arrays as Parameters are 4 Bytes?

When I use the sizeof() function to determine the size of an array passed as a parameter to a udf, it always returns 4 bytes. Here's an example. Why is this so and how can I fix it without manually passing the array size?

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
#include <iostream>
using namespace std;

void printarray(char myarray[]);
void printarray(char myarray[], int arsize);

int main()
{
    //declare array
    char tmparray[10];
    for (int i=0; i<sizeof(tmparray); i++)
        tmparray[i] = 'x';

    //print size and contents outside function
    cout << "\n int main()\n Size: " << sizeof(tmparray)  << " bytes.\n ";
    for (int i=0; i<sizeof(tmparray); i++)
        cout << tmparray[i];
    cout << endl;

    //print size and contents with two functions
    printarray(tmparray);
    printarray(tmparray,sizeof(tmparray));
    cout << "\n\n ";
    system("pause");
    return 0;
}

void printarray(char myarray[])
{
    cout << "\n void printarray(char myarray[])\n Size: " << sizeof(myarray) << " bytes.\n ";
    for (int i=0; i<sizeof(myarray); i++)
        cout << myarray[i];
    cout << endl;
}

void printarray(char myarray[], int arsize)
{
    cout << "\n void printarray(char myarray[], int arsize)\n Size: " << sizeof(myarray) << " bytes.\n ";
    for (int i=0; i<arsize; i++)
        cout << myarray[i];
    cout << endl;
}

closed account (1yR4jE8b)
Arrays are always passed as a pointer to the first element. What you are getting with the sizeof() operator is the size of the pointer. If you were on a 64-bit operating system it would be 8 bytes.
Line 16 will cause a buffer overflow on line 17. sizeof gives sizes in bytes, but the offset operator expects offsets in elements.
Line 22 will cause another one on line 40.

There's NO way to tell the size of an array from a function other than the one that created it without passing the size as a parameter. None whatsoever.

(Cue jsmith posting his template sizeOf() function.)
Thanks for the information. I'll remember to manually pass the dimensions my arrays in the future. Also, how do I prevent the buffer overflow?
closed account (1yR4jE8b)
Assuming you have 10 elements in your array:

this:
1
2
for (int i=0; i<sizeof(tmparray); i++)
        cout << tmparray[i];


should be:
1
2
for (int i=0; i<10; i++) //because there are 10 elements in the array
        cout << tmparray[i];


You treat it just like any other array.
Since this is a c++ program the other obvious and better solution is the std::vector which knows its own size. std::deque or std::list could also work in some situations.

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
#include <iostream>
#include <vector>
using namespace std;

void printarray(const std::vector<char>& myarray);
/* no longer necessary
   void printarray(char myarray[], int arsize);*/

int main()
{
    //declare array
    std::vector<char> tmparray(10, 'x');
    /* no longer necessary to loop
      for (int i=0; i<sizeof(tmparray); i++)
      tmparray[i] = 'x'; */

    //print size and contents outside function
    cout << "\n int main()\n Size: " << tmparray.size()  << " bytes.\n ";
    for (int i=0; i<tmparray.size(); i++)
        cout << tmparray[i];
    cout << endl;

    //print size and contents with two functions
    printarray(tmparray);
    /* no longer necessary
       printarray(tmparray,sizeof(tmparray));*/
    cout << "\n\n ";
    system("pause");
    return 0;
}

void printarray(const std::vector<char>& myarray)
{
    cout << "\n void printarray(const std::vector<char>& myarray)\n Size: " << myarray.size() << " bytes.\n ";
    for (int i=0; i<myarray.size(); i++)
        cout << myarray[i];
    cout << endl;
}

/* no longer necessary
void printarray(char myarray[], int arsize)
{
    cout << "\n void printarray(char myarray[], int arsize)\n Size: " << sizeof(myarray) << " bytes.\n ";
    for (int i=0; i<arsize; i++)
        cout << myarray[i];
    cout << endl;
    } */
Vectors (and other STL containers) are usually passed as a pair of iterators rather than as the container itself, although both options work.
Vectors (and other STL containers) are usually passed as a pair of iterators
Says who?
Last edited on
@xikkub
try reading this
http://cplusplus.com/forum/beginner/17828/

tummychow wrote:
Vectors (and other STL containers) are usually passed as a pair of iterators
really? can you please give an example
Last edited on
I think what tummychow meant was that a pair of iterators are used on "for each" template operations, rather than writing functions that only work with a vector or whatever.

There are plenty of examples of this all over <algorithm>, like fill(), copy(), etc.
@Disch
wow! you really are a genius, thanks
Last edited on

(Cue jsmith posting his template sizeOf() function.)


Oh sorry, missed that.

1
2
3
template< typename T, size_t N >
size_t asize( T (&)[ N ] )
{ return N; }

Disch, thank you for clarifying my comment.
I'm not saying that passing an iterator range is inherently advantageous over passing a reference to the container itself. It's just that it's the usual way to do it, such as in all the algorithms. No convention states that you should pass by iterator range but it works just as well, is more common and has some additional functionality. In addition passing iterators allows you to pass a piece of the container rather than the whole thing if you only want some section of it operated on.
I'm not saying that passing an iterator range is inherently advantageous over passing a reference to the container itself.
I didn't imply you said so.

It's just that it's the usual way to do it
Again, says who? <algorithm> is one example, but those functions are not representative. For one, they are designed to work also with pointers and non-vector iterators.
If that's the requirement of the function, then it makes sense to pass iterators. Otherwise, you're just unnecessarily limiting yourself, and may have to change the interface if the requirements of the function change.

has some additional functionality
What?? Like what? All an iterator can do is move to a different element and dereference. How is that more functionality than having the entire container?
Last edited on
Yes you can definitely write the printArray function to be even more generic and that could be done in several ways. The function would have to be designed as a template function so that like std algorithms it can handle any type of iterator. Or you could give it a container type such as a vector and allow the type of the vector to be the template type so that it can handle vectors of any type. I was just trying to show the advantage of passing the container by reference. In that case you have all of the features of the container available to you. At the time I only had a few minutes to build an example so that is what I produced.

I'd have to agree with helios on something though. Passing two iterators is a reasonable alternative but I don't see how you get MORE functionality by passing two iterators. You'd get LESS Functionality passing two iterators since the code would be limited to the type of iterator with the least amount of functionality. Some iterators are random access and some aren't. Therefore the function would have to be written to handle all kinds of iterators and would not be able to use any container member functions at all. The solution really has to depend on what the function is required to do with the inputs. If it can be generic, like a std algorithm, then make it so. There are plenty of other cases where you'd want the function to receive a container so that it has the advantage of being able to use the container specific member functions. The other advantage is safety. Passing iterators, the receiving function has very little to work with in order to determine that the values are valid. All you could do is check for null and that the end is greater than the start.
I think there is some minor terminology abuse going on here. STL algorithms operate on ranges (more precisely collections). Ranges have a beginning and an end, which are specified by iterators. The iterator type itself could be a template parameter. This is the way the STL algorithms were designed and it decouples the algorithm from the type of container.

There are two benefits from this change that immediately come to mind:

1. The container could be swapped out inside main and the function would still remain compatible.
2. The function could be called to operate on any subset of the containers contents.

Possible drawbacks, as pointed out by kempofighter, do exist. The function in question, though, doesn't appear to be very dependent on the container type.

Updating the function above to accept two iterators rather than a container reference would be beneficial to say the least.

Then again, if you were just dumping the values to cout, there is always:
 
copy( tmparray, tmparray + 10, ostream_iterator<char>( cout ) );

Null-terminating the array and just using cout is an idea, too...
Last edited on
Topic archived. No new replies allowed.