0

I am new to C/C++ and am learning about arrays. I just finished reading about passing arrays to functions, and am trying to implement it. I start off with an array x[] = "Hello, which of course has a sizeof() 6. But for some reason, when I pass it to my function, listElements(char arr[]), then I get sizeof(arr) equal to 4. Why is my array being cut off like this?

Also, sizeof(char) on my compiler is 1.

#include <iostream>
using namespace std;

void listElements(char[]);

int main(){
    char x[] = "Hello";
    cout << sizeof(x) << endl; // 6
    listElements(x);
    cin >> x[0];
    return 0;
}

void listElements(char arr[]){
    cout << "Size of arr: " << sizeof(arr) << endl; // 4  <--- why is this 4?
    cout << "Size of char: " << sizeof(char) << endl; // 1
    for (int j = 0; j < (sizeof(arr) / sizeof(char)); j++){
        cout << arr[j] << endl;
    }
    return;
}
Alex G
  • 747
  • 4
  • 15
  • 27
  • 3
    Arrays decays to *pointers*, so `sizeof(arr)` in the function is the size of the pointer and not the array you pass to the function. Use `strlen` to get the length of a string. Or, since you're programming in C++, use [`std::string`](http://en.cppreference.com/w/cpp/string/basic_string) instead. – Some programmer dude Mar 03 '15 at 23:44
  • 1
    sizeof(char) is *always* 1. – ryanpattison Mar 03 '15 at 23:45
  • see [Why do C and C++ compilers allow array lengths in function signatures when they're never enforced](http://stackoverflow.com/questions/22677415/why-do-c-and-c-compilers-allow-array-lengths-in-function-signatures-when-they) – M.M Mar 04 '15 at 00:11
  • @JoachimPileborg it is nothing to do with arrays decaying to pointers. `arr` was always a pointer; the declarator in the prototype list is alternative syntax for `char *arr`. – M.M Mar 04 '15 at 00:12
  • @MattMcNabb But the argument in `main` is an array, that it's that array thay decays to a pointer, that's what I meant. – Some programmer dude Mar 04 '15 at 00:17
  • You should pick one language at a time. Learn either C or C++ but not both. Learning those 2 at the same time is exceptionally confusing, even harder then learning PHP and Java at the same time. – MSalters Mar 04 '15 at 12:27

4 Answers4

8

If you really want to pass an array, then pass it by reference (or const reference if you don't intend to change it) via a template, like

template<std::size_t N>
void listElements(/*const*/ char (&arr)[N])
{ 
    // sizeof(arr) will be equal to N
    // rest of the function body here
}

If you pass it by value, then it decays to a pointer, i.e. void listElements(char arr[]) is the same as void listElements(charr arr[1024]) is the same as void listElements(char* arr).

PS: note that if you pass the array by reference like above, then your function won't work with pointers anymore, as in this case the compiler differentiate between pointers and arrays. That is, listElements(p) won't compile for char* p;. If you want to use it with pointers (which may be convenient), then you must specify the size manually as an additional parameter of the function, or use some convention for an end-of-array delimiter, such as a zero-terminated strings in C.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • If it decayed to a pointer, though, then wouldn't that make `sizeof(arr)` equal to 1? Either way, if it passes a pointer, then, why is the pointer's size 4? – Alex G Mar 03 '15 at 23:56
  • 1
    @AlexG No, pointers do not have size 1 in general and on no system I know of in particular. They are usually of size 4 on 32 bit machines and of size 8 on 64 bit machines. – Baum mit Augen Mar 03 '15 at 23:57
  • 1
    @AlexG, no, it makes it equal to the size of a pointer to `char`, which usually is 32 or 64 bit (i.e. 4 or 8 bytes), depending on the OS. A pointer is a special type of variable that stores an address, so if your OS uses 32-bit addressing, then the size of the pointer to `char` (smallest addressable unit) is 32 bit. – vsoftco Mar 03 '15 at 23:58
  • Okay, so if I didn't want to use a template, I'd have to pass a separate argument of the array's size. `listElements(x, 6);` – Alex G Mar 04 '15 at 00:02
  • @AlexG you could have both versions (template taking array, and non-template taking pointer plus length). Don't be scared of templates, they're not scary and not magic – M.M Mar 04 '15 at 00:15
  • It's something I haven't really learned yet, but I plan to soon. On another note, why is it that the compiler can see the `sizeof(x)` is 6, but even if I ask it for `sizeof(&arr)`, which should de-reference the poiinter, it won't work? Still shows 4 either way. When I ask for `sizeof(x)`, what am I really doing that allows it to return 6? – Alex G Mar 04 '15 at 00:22
  • @AlexG `&arr` means "address of `arr`", which is the address of the pointer to the first element of the array. Basically the type of `&adr` is `char**`, i.e. pointer to pointer to `char`. The size of a pointer is always fixed and usually equals 32 bit or 64 bit on modern OS. On the other hand, `sizeof(x)` gives the size of its parameter, which in this case is of type `char [6]`, i.e. array of 6 chars. – vsoftco Mar 04 '15 at 00:58
5

char[] as a function argument is the same as char* in C++. And apparently on your system, sizeof(char*) == 4. Also, sizeof(char) always equals 1.

To properly pass the C-style string, pass its length as extra integer argument or, even better, use std::string instead of char[] and char*.

Code examples:

void listElements(char *arr, int length){
    for (int j = 0; j < length; j++){
        cout << arr[j] << endl;
    }
}

or

void listElements(const std::string& str){
    for (const auto& v : str)
        std::cout << v << std::endl;
}
Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
3
char x[] = "Hello";
cout << sizeof(x) << endl; // 6 because the compiler knows x is an array of 6 characters long

void listElements(char arr[]){
    cout << "Size of arr: " << sizeof(arr) << endl; // 4  arr[] is actually a pointer

Calling listElement() is doesn't actually pass the entire array, it only passes the pointer to x. I think that's why you expected 6.

Tony J
  • 599
  • 5
  • 16
  • True. I didn't realize it, but the later example in my book passes arrays by including the array length as a separate argument. So I guess that's the best way to do it. – Alex G Mar 04 '15 at 00:03
1

You are getting the size of a 32bit pointer to a null terminated char[]. Effectively, a char*

RobStone
  • 187
  • 7