tags:

views:

188

answers:

6

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?

+12  A: 

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.

Brian R. Bondy
+1 good article
alex
+1, but you should be using `size_t`, not `int`, for the array size.
Jonathan Grynspan
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
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
+5  A: 

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
I think the better question is why not use vector?
JoshD
@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
That's a clever solution but it only works for statically sized arrays.
Greg Hewgill
@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
@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
A: 

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
@Tony: b doesn't work because its size is 1 but there are 0 elements.
JoshD
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
@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
@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
@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
@Josh: new type? New template function, yes, but not a new type, surely? And if it is defined inline (`template <size_t N> void print_array(int ( }`) 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
@Ben Voigt: Ah. My mistake. Thanks for clarifying that point.
JoshD
@Josh,@Jonathan,@Ben: thanks for the feedback. Have updated the answer to incorporate the inline forwarding function.
Tony
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..
@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
+1  A: 

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.

ArunSaha
A: 

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
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..
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..
A: 

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