14

I am trying to write a function that prints out the elements in an array. However when I work with the arrays that are passed, I don't know how to iterate over the array.

void
print_array(int* b)
{
  int sizeof_b = sizeof(b) / sizeof(b[0]);
  int i;
  for (i = 0; i < sizeof_b; i++)
    {
      printf("%d", b[i]);
    }
}

What is the best way to do iterate over the passed array?

unj2
  • 52,135
  • 87
  • 247
  • 375

8 Answers8

19

You need to also pass the size of the array to the function.
When you pass in the array to your function, you are really passing in the address of the first element in that array. So the pointer is only pointing to the first element once inside your function.

Since memory in the array is continuous though, you can still use pointer arithmetic such as (b+1) to point to the second element or equivalently b[1]

void print_array(int* b, int num_elements)
{
  for (int i = 0; i < num_elements; i++)
    {
      printf("%d", b[i]);
    }
}

This trick only works with arrays not pointers:

sizeof(b) / sizeof(b[0])

... and arrays are not the same as pointers.

zforgo
  • 2,508
  • 2
  • 14
  • 22
Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
  • 2
    +1, but you should be using `size_t`, not `int`, for the array size. – Jonathan Grynspan Oct 06 '10 at 02:05
  • I almost did, but I'm not sure if that's a type in C and I tried to provide an answer that is applicable to both since the question was tagged as both. – Brian R. Bondy Oct 06 '10 at 02:07
  • I tried the same kind of explanation as the link you provided in that answer: http://stackoverflow.com/questions/3613302/passing-array-of-structures-to-function-c/3613350#3613350 very common mistake indeed. – kriss Oct 06 '10 at 08:58
5

Why don't you use function templates for this (C++)?

template<class T, int N> void f(T (&r)[N]){
}

int main(){
    int buf[10];
    f(buf);
}

EDIT 2:

The qn now appears to have C tag and the C++ tag is removed.

Chubsdad
  • 24,777
  • 4
  • 73
  • 129
  • 2
    I think the better question is why not use vector? – JoshD Oct 06 '10 at 01:53
  • 2
    @JoshD: sans C++0x, fixed-sized arrays are very handy for the concision with which you can initialise them (ala `int a[] = { 1, 2, 3};`. They also avoid the heap allocation - particularly nice if they're small, transcient, and in a performance-sensitive loop. – Tony Delroy Oct 06 '10 at 02:01
  • That's a clever solution but it only works for statically sized arrays. – Greg Hewgill Oct 06 '10 at 02:02
  • @Tony: I do agree there. But in that case you can use the `sizeof(b) / sizeof(b[0])` trick and pass the size to a function, right? My impression was that these are pointers to dynamically sized arrays. Perhaps I misunderstood. – JoshD Oct 06 '10 at 02:09
  • @Greg/@JoshD: check the question: the complaint was that `int sizeof_b = sizeof(b) / sizeof(b[0]);` couldn't be done inside the called function. Clearly the attempt to use it indicates compile-time constant size. – Tony Delroy Oct 06 '10 at 02:44
2

For C, you have to pass the length (number of elements)of the array.

For C++, you can pass the length, BUT, if you have access to C++0x, BETTER is to use std::array. See here and here. It carries the length, and provides check for out-of-bound if you access elements using the at() member function.

Arun
  • 19,750
  • 10
  • 51
  • 60
0

You could try this...

#include <cstdio>                                                               

void 
print_array(int b[], size_t N) 
{ 
    for (int i = 0; i < N; ++i) 
        printf("%d ", b[i]);
    printf("\n");
}

template <size_t N>
inline void 
print_array(int (&b)[N]) 
{
    // could have loop here, but inline forwarding to
    // single function eliminates code bloat...
    print_array(b, N);
}                                                                                

int main()                                                                      
{                                                                               
    int a[] = { 1, 2 };                                                         
    int b[] = { };
    int c[] = { 1, 2, 3, 4, 5 };                                                

    print_array(a);                                                             
    // print_array(b);                                                          
    print_array(c);                                                             
}

...interestingly b doesn't work...

array_size.cc: In function `int main()':
array_size.cc:19: error: no matching function for call to `print_array(int[0u])'

JoshD points out in comments below the issue re 0 sized arrays (a GCC extension), and the size inference above.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • @Tony: b doesn't work because its size is 1 but there are 0 elements. – JoshD Oct 06 '10 at 01:54
  • 1
    It's a bit excessive having 3 functions created for the 3 differently sized arrays, isn't it? You would be better off having a generic print function, and have the template function (inline?) call the generic function with the array and size arguments, wouldn't you? – Jonathan Leffler Oct 06 '10 at 01:56
  • @JoshD: keen insight, thanks. @Jonathan: for functions this simple I don't think it matters. For something bigger, you simply write a templated inline front-end that calls the non-templated implementation, passing the array size. – Tony Delroy Oct 06 '10 at 01:57
  • 1
    @Jonathan and @Tony: Even with the front-end, you'll get a new type for each value of N. That's some serious code bloat. Why use a template when you can have a function parameter? – JoshD Oct 06 '10 at 02:04
  • 1
    @JoshD: A new type? No you won't, and since there are no virtual functions, it wouldn't be covered by RTTI: hence zero cost. The size-detecting wrapper would be marked inline anyway, the compiler will generate the exact same code as if the programmer passed the size, but without the possibility of a type at the call site. – Ben Voigt Oct 06 '10 at 02:07
  • 1
    @Josh: new type? New template function, yes, but not a new type, surely? And if it is defined inline (`template void print_array(int (&b([N]) { print_array(b, N); }`) the bloat is minimal to non-existent, is it not. Since I'm primarily a C programmer, badges notwithstanding, I'd use the function and expect to call it with the explicit argument - as you suggest. – Jonathan Leffler Oct 06 '10 at 02:08
  • @Ben Voigt: Ah. My mistake. Thanks for clarifying that point. – JoshD Oct 06 '10 at 02:12
  • @Josh,@Jonathan,@Ben: thanks for the feedback. Have updated the answer to incorporate the inline forwarding function. – Tony Delroy Oct 06 '10 at 03:31
  • I would say any C++ solution like this is not a good solution, because if you're using C++ you shouldn't be using arrays to begin with. – R.. GitHub STOP HELPING ICE Oct 06 '10 at 06:13
  • @R: And I'd say you are completely wrong. But, for both of us, there's no point making assertions unless you've got logic to back them up - arguments that take performance, convenience and space efficiency into account. I've mentioned some of such arguments in comments on Chubsdad's answer above. If you'd like to, please do share... – Tony Delroy Oct 06 '10 at 08:33
0

In C99, you can require that an array an array has at least n elements thusly:

void print_array(int b[static n]);

6.7.5.3.7: A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.

In GCC you can pass the size of an array implicitly like this:

void print_array(int n, int b[n]);
Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
  • It's worth mentioning that `T foo(T myptr[static 1])` is a convenient and portable way of expressing the notion that `foo` takes a pointer of type `T *` which cannot be `NULL` (or any other invalid pointer value like `(T *)-1`). – R.. GitHub STOP HELPING ICE Oct 06 '10 at 06:07
  • And I believe the `void print_array(int n, int b[n]);` example you gave is standard C, not a gcc extension. However, it's utterly useless in the case of 1-dimensional arrays. When it gets useful is when you have a multi-dimensional array of variable size in a dimension other than the first. – R.. GitHub STOP HELPING ICE Oct 06 '10 at 06:11
0

In c++ you can also use a some type of list class implemented as an array with a size method or as a struct with a size member(in c or c++).

Roman A. Taycher
  • 18,619
  • 19
  • 86
  • 141
0

Use variable to pass the size of array. int sizeof_b = sizeof(b) / sizeof(b[0]); does nothing but getting the pre-declared array size, which is known, and you could have passed it as an argument; for instance, void print_array(int*b, int size). size could be the user-defined size too.

int sizeof_b = sizeof(b) / sizeof(b[0]); will cause redundant iteration when the number of elements is less than the pre-declared array-size.

Chris Tang
  • 567
  • 7
  • 18
0

The question has already some good answers, for example the second one. However there is a lack of explanation so I would like to extend the sample and explain it:

Using template and template parameters and in this case None-Type Template parameters makes it possible to get the size of a fixed array with any type.

Assume you have such a function template:

template<typename T, int S>
int getSizeOfArray(T (&arr)[S]) {
    return S;
}

The template is clearly for any type(here T) and a fixed integer(S). The function as you see takes a reference to an array of S objects of type T, as you know in C++ you cannot pass arrays to functions by value but by reference so the function has to take a reference.

Now if u use it like this:

int i_arr[] = { 3, 8, 90, -1 };
std::cout << "number f elements in Array: " << getSizeOfArray(i_arr) << std::endl;

The compiler will implicitly instantiate the template function and detect the arguments, so the S here is 4 which is returned and printed to output.

void
  • 7,760
  • 3
  • 25
  • 43