-3

In C, how can I pass an array with unknown size to a function (by reference)?

The size of the array is only determined inside the function.

Arnaud
  • 4,884
  • 17
  • 54
  • 85
  • You must also pass the size of your array as a separate argument (like `argc` in `main`). – rslemos Jul 07 '14 at 18:59
  • You can't, you have to pass the size as another parametre of the function call. Unless you have the size of the array in the first X bytes, but that's your protocol, not standard. – AntonH Jul 07 '14 at 18:59
  • 1
    Or provide some form of encoding so your function knows when to stop incrementing the array pointer, like stating that the array ends in 0, so 0 cannot legally appear anywhere on the array (the case of [`environ`](http://man7.org/linux/man-pages/man7/environ.7.html) array). – rslemos Jul 07 '14 at 19:00
  • 1
    @rslemos: last element `argv[argc]` is always set to `NULL`, so `argc` is not really "a must", you can just iterate trough pointers unless you find it. – Grzegorz Szpetkowski Jul 07 '14 at 19:56
  • 1
    @GrzegorzSzpetkowski, the `argc` was just an example. The idea is just to tell that another piece of information should be passed along. I just thought that the OP were familiar with argc-argv pair (and how the are used in general). But you're right, `argv[argc] == NULL`, and that's another way to tell that the array has ended, just as I noted before. – rslemos Jul 07 '14 at 20:13
  • How do you declare your array, and how is your function expected to know how long it is? – Floris Jul 07 '14 at 23:10

3 Answers3

4

If the array is a null terminated character array then you can use strlen to calculate the length of that character array. Otherwise you need to use a delimiter to know the end of the array and find length using a loop to the delimiter.

NOTE: No pass by reference in C.

haccks
  • 104,019
  • 25
  • 176
  • 264
  • You can only use `strlen` if your char array is null terminated. Otherwise its result is undefined. – rslemos Jul 07 '14 at 19:03
  • On the contrary: in C, arrays are always passed by reference (although its address is usually passed by value, but can also be passed by reference). – rslemos Jul 07 '14 at 19:04
  • 3
    @rslemos; Give me a quote/reference from C standard where it says that `in C arrays are always passed by reference`. I will award you a bounty of 500 to any of your answer. – haccks Jul 07 '14 at 19:06
  • @FiddlingBits; Still waiting for explanation :\ – haccks Jul 07 '14 at 19:16
  • 2
    @rslemos, you are wrong, in C all is passed by value, the answer seems correct to me, +1 – David Ranieri Jul 07 '14 at 19:17
  • The pointer, the address to the array yes, by value (as I said first). The array itself (the values it contains) are passed by reference. See? – rslemos Jul 07 '14 at 19:18
  • 1
    @rslemos, again, you are wrong, [take a look](http://c-faq.com/ptrs/passbyref.html) – David Ranieri Jul 07 '14 at 19:23
  • @AlterMann and haccks, look at questions 6.4b and 4.11 of comp.lang.c FAQ. That explains all. I still mantain that "in C, arrays are always passed by reference". – rslemos Jul 07 '14 at 19:23
  • 2
    Strictly speaking, C always uses pass by value. You can **simulate** pass by reference yourself, by defining functions which accept pointers and then using the & operator when calling, and the compiler will essentially simulate it for you when you pass an array to a function (by passing a pointer instead, see question 6.4 et al.). – David Ranieri Jul 07 '14 at 19:24
  • 1
    @rslemos; I read that before. It says: ***Strictly speaking**, C always uses pass by value. You can **simulate** pass by reference yourself [...]* – haccks Jul 07 '14 at 19:25
  • @haccs; See question 6.4b: "Q: So arrays are passed by reference, even though the rest of C uses pass by value? A: That's one way of thinking about it". I'll clarify a last time: the **address** [to the first element] is passed by value, that is, no matter you change it a thousand times inside the function, the caller will never see the change in the **address**; on the other hand the function is free to change whatever contents the array has (unless qualified by `const`), and the caller will see those changes. – rslemos Jul 07 '14 at 19:29
  • 1
    @rslemos; 6.4b redirects me to 4.11. And there again it says: *Fundamentally, **C has nothing truly equivalent to formal pass by reference** or C++ reference parameters.* – haccks Jul 07 '14 at 19:35
  • 1
    To pass by value, the behavior of creating a copy of the object must be apparent. The only copy made in the case of passing an array is the address of the array element provided. Since an array is defined as a contiguous sequence of elements of a given type, and no padding is allowed, it suggests that the array was passed by reference when, in fact, the address of one array element is passed, and the other array elements come directly after the array element referenced by the function parameter. (NB: the behavior may be performed by machine code, or the machine may handle it natively) –  Jul 07 '14 at 19:36
  • @haccks; from 4.11: "You can **simulate** pass by reference **yourself** [...] and **the compiler will essentially simulate it for you** when you pass an ***array to a function***". Got it? And then "another way of looking at it is that if an parameter has type, say, int * **then an integer is being passed *by reference*** and a **pointer** to an integer is being passed ***by value***." – rslemos Jul 07 '14 at 19:40
  • 2
    That's a void holy war. As a **concept**, pass-by-reference surely exists in C, regardless of whether it's achieved by pointers or not. Array here is an example. As a C++ reference, there is no direct equivalent in C. But who decided that C++ way is the only way? – SomeWittyUsername Jul 07 '14 at 19:41
  • 1
    @rslemos; Once I explained about [pass by reference](http://stackoverflow.com/a/24468853/2455888). Read only The paragraph under "**NOTE**". Hope this would help. – haccks Jul 07 '14 at 21:05
  • 1
    @haccks, thanks. It's what I've said all the time. I don't want to advance on this any further. I still say array passing to be "by reference", because is what we get anyway (modifiable content) no matter the pointer is copied (again, as I've said all the time, the pointer is "by value"). Apart of this, your explanation was simply brilliant, and I upvoted that answer then. Let it rest and we'll agree to disagree. – rslemos Jul 07 '14 at 21:31
2

You have to pass the starting address of the array along with the number of arguments such as the following.

void f (int* array, int n) {
     int i, x;
     for (i = 0; i < n; i++) {
          x = array[i];  // use x
          ...
     }
     ...
 }

Alternative: You would have to agree on a standard EOD (End of Data) marker. In this case you may not pass the length of the array explicitly, but rather rely on the value to check for the end of the array. An example is the 0 terminated string (char array of C).

#define END_OF_ARRAY -1

void f (int* array) {
     int i;
     while (array[i] != END_OF_ARRAY) {
          // use array[i]
          ...
          i++;
     }
     ...
 }
Debasis
  • 3,680
  • 1
  • 20
  • 23
  • The problem is that `n` is determined by `f`. Is it possible? – Arnaud Jul 07 '14 at 19:58
  • yes, in the 2nd case f (your called function) can simply check for the EndOfData marker to know that the array has ended... – Debasis Jul 07 '14 at 21:16
  • When I try that I have a segmentation fault. I declare the array before calling the function on it. Where am I wrong? – Arnaud Jul 07 '14 at 22:07
1

You'll have to malloc the array inside the function. Then either:

[examples given for array of int; adapt accordingly]

(i) return a pointer to it:

int* f(void) {
    int *array;
    .
    .
    .
    array = malloc(length * sizeof int);
    .
    .
    .
    return array;
}

or

(ii) store it inside a pointer passed by the caller

void f(int **array) { // yes, double pointer
    .
    .
    .
    *array = malloc(length * sizeof int); // here malloc's your array and store it in *array
    .
    .
    .
}

Don't forget to free this array after you finished with it.

Edit: the callee would be:

(i)

int *array; // can't use the array yet
.
.
.
array = f(); // now it's available for use
.
.
.
free(array); // no longer available

(ii)

int *array; // can't use the array yet
.
.
.
f(&array); // now it's available for use
.
.
.
free(array); // no longer available
rslemos
  • 2,454
  • 22
  • 32