tags:

views:

831

answers:

7

So I have some code that looks like this:

int a[10];
a = arrayGen(a,9);

and the arrayGen function looks like this:

int* arrayGen(int arrAddr[], int maxNum)
{
int counter=0;
while(arrAddr[counter] != '\0') {
 arrAddr[counter] = gen(maxNum);
 counter++;
    }
return arrAddr;
}

Right now the compilier tells me "warning: passing argument 1 of ‘arrayGen’ makes integer from pointer without a cast"

My thinking is that I pass 'a', a pointer to a[0], then since the array is already created I can just fill in values for a[n] until I a[n] == '\0'. I think my error is that arrayGen is written to take in an array, not a pointer to one. If that's true I'm not sure how to proceed, do I write values to addresses until the contents of one address is '\0'?

A: 

Try calling your parameter int* arrAddr, not int arrAddr[]. Although when I think about it, the parameters for the main method are similar yet that works. So not sure about the explanation part.

Edit: Hm all the resources I can find on the internet say it should work. I'm not sure, I've always passed arrays as pointers myself so never had this snag before, so I'm very interested in the solution.

Ray Hidayat
I already tried that -- sorry for leaving it out.
devin
it's the attempt to assign to an array name, which isn't an lvalue, see my response.
Charlie Martin
and it took me a minute too, even though I've programmed in C for 25 years.
Charlie Martin
@Ray, `int arrAddr[]` and `int* arrAddr` is the same in function parameters. You may freely interchange it. But i also recommend to be explicit and write `int *arrAddr` (the compiler takes `int arrAddr[]` as a pointer anyway, when it's a parameter (but only in this context)). See D.Shawley's answer for an explanation.
Johannes Schaub - litb
+14  A: 

The basic magic here is this identity in C:

*(a+i) == a[i]

Okay, now I'll make this be readable English.

Here's the issue: An array name isn't an lvalue; it can't be assigned to. So the line you have with

a = arrayGen(...)

is the problem. See this example:

int main() {
    int a[10];

    a = arrayGen(a,9);

    return 0;
}

which gives the compilation error:

gcc -o foo foo.c
foo.c: In function 'main':
foo.c:21: error: incompatible types in assignment

Compilation exited abnormally with code 1 at Sun Feb  1 20:05:37

You need to have a pointer, which is an lvalue, to which to assign the results.

This code, for example:

int main() {
    int a[10];
    int * ip;

    /* a = arrayGen(a,9);  */
    ip = a ; /* or &a[0] */
    ip = arrayGen(ip,9);

    return 0;
}

compiles fine:

gcc -o foo foo.c

Compilation finished at Sun Feb  1 20:09:28

Note that because of the identity at top, you can treat ip as an array if you like, as in this code:

int main() {
    int a[10];
    int * ip;
    int ix ;

    /* a = arrayGen(a,9);  */
    ip = a ; /* or &a[0] */
    ip = arrayGen(ip,9);

    for(ix=0; ix < 9; ix++)
        ip[ix] = 42 ;

    return 0;
}


Full example code

Just for completeness here's my full example:

int gen(int max){
    return 42;
}

int* arrayGen(int arrAddr[], int maxNum)
{
    int counter=0;
    while(arrAddr[counter] != '\0') {
        arrAddr[counter] = gen(maxNum);
        counter++;
    }
    return arrAddr;
}

int main() {
    int a[10];
    int * ip;
    int ix ;

    /* a = arrayGen(a,9);  */
    ip = a ; /* or &a[0] */
    ip = arrayGen(ip,9);

    for(ix=0; ix < 9; ix++)
        ip[ix] = 42 ;

    return 0;
}
Charlie Martin
your description is fine- apart from the lvalue stuff. an array is an lvalue. but it's not a modifiable lvalue: arrays and constants fall into this area: const int b = 10; // non-modifiable lvalue too . The important characteristic of an lvalue in C is that there is an object - not just a value.
Johannes Schaub - litb
in fact, c89 only allowed lvalue arrays to decay into pointers. had you returned a struct value which contained an array, and if you tried to assign that array to a pointer, or apply the "*" operator to the array name, that failed, because the array then would be an rvalue. c99 fixed that.
Johannes Schaub - litb
but that's only a small issue. u get +1 anyway from me :)
Johannes Schaub - litb
wait... the function arrayGen() is supposed to fill the array with values from the function gen(). Here, the for loop in your main does that.
devin
I don't understand why you set ip to point to a, pass ip to arrayGen which returns the address of ip then sets ip to what it already was pointing to. Am i missing something?
Phaedrus
Charlie Martin
Devin, I think at that point this is just code to make the pedagogical point I wanted. I had to invent a version of gen() just to make this compilable.
Charlie Martin
charlie, the reason that an array name in expressions often is not an lvalue is because it's converted to a pointer. that pointer expression then is not an lvalue. but the array still is an lvalue. an example of an lvalue array is a string literal: "123" is an lvalue array having type char[4]
Johannes Schaub - litb
it's more correct to say an 'l-value represents a storage region's "locator" value' than to say it can appear on the left side of an assignment. as your link also explains, there are non-modifiable lvalues too. c99 explains it in footnote 53 (C99/TC2). anyway, just my 2cents :) heading to bed now :)
Johannes Schaub - litb
thanks for the response by the way, it really helped.
devin
From ISO/IEC 9899:1999 6.3.2.1#1 -- "An lvalue is an expression with an object type or an incomplete type other than void [snip due to comment size limit] A modifiable lvalue is an lvalue that does not have array type" An array in C is an lvalue according to the C standard, it's not modifiable.
Chris Young
i'm impressed how long this wrong assertion of yours can survive in that answer without other people besides Chris and me moaning about it.
Johannes Schaub - litb
I'm impressed how long you and Chris can continue to obsess over it. Incorrectly. The notion of "modifiable lvalue" is an innovation after introduction of const, but the original and common definition is "left".
Charlie Martin
the original true, the common maybe (certainly not common among experts), but the right no.
Johannes Schaub - litb
Look. litb, I'm sorry, but you're just wrong. See, eg, the Wiki article "n C, the term lvalue originally meant something that could be assigned to (coming from left-value, indicating it was on the left side of the assignment operator), but since 'const' was added to the language, this now is termed a 'modifiable lvalue'."
Charlie Martin
I've written an own answer, trying to draw my points. Place in comments is rather limited. Look below for my full text :)
Johannes Schaub - litb
Steve Jessop
@Charlie, there is something i didn't realize: An array name, except in sizeof and ". So if we say an array name is "most often an rvalue (except in sizeof and address-of)", do you agree? Of course it's still true that lvalue doesn't mean "assignable" :) I didn't know this difference of C++ and C - and it's not that way in C++. In C++, it would keep being an lvalue. I deleted my answer below until it's fixed :)
Johannes Schaub - litb
+4  A: 

Why even return arrAddr? Your passing a[10] by reference so the contents of the array will be modified. Unless you need another reference to the array then charlies suggestion is correct.

Phaedrus
+2  A: 

Hmm, I know your question's been answered, but something else about the code is bugging me. Why are you using the test against '\0' to determine the end of the array? I'm pretty sure that only works with C strings. The code does indeed compile after the fix suggested, but if you loop through your array, I'm curious to see if you're getting the correct values.

Tim D
+1  A: 

I'm not sure what you are trying to do but the assignment of a pointer value to an array is what's bothering the compiler as mentioned by Charlie. I'm curious about checking against the NUL character constant '\0'. Your sample array is uninitialized memory so the comparison in arrayGen isn't going to do what you want it to do.

The parameter list that you are using ends up being identical to:

int* arrayGen(int *arrAddr, int maxNum)

for most purposes. The actual statement in the standard is:

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.

If you really want to force the caller to use an array, then use the following syntax:

void accepts_pointer_to_array (int (*ary)[10]) {
    int i;
    for (i=0; i<10; ++i) {
        (*ary)[i] = 0; /* note the funky syntax is necessary */
    }
}

void some_caller (void) {
    int ary1[10];
    int ary2[20];
    int *ptr = &ary1[0];
    accepts_pointer_to_array(&ary1); /* passing address is necessary */
    accepts_pointer_to_array(&ary2); /* fails */
    accepts_pointer_to_array(ptr);   /* also fails */
}

Your compiler should complain if you call it with anything that isn't a pointer to an array of 10 integers. I can honestly say though that I have never seen this one anywhere outside of various books (The C Book, Expert C Programming)... at least not in C programming. In C++, however, I have had reason to use this syntax in exactly one case:

template <typename T, std::size_t N>
std::size_t array_size (T (&ary)[N]) {
    return N;
}

Your mileage may vary though. If you really want to dig into stuff like this, I can't recommend Expert C Programming highly enough. You can also find The C Book online at gbdirect.

D.Shawley
A: 

The way your using it arrayGen() doesn't need to return a value. You also need to place '\0' in the last element, it isn't done automatically, or pass the index of the last element to fill.

jeffD
A: 

@jeffD Passing the index would be the preferred way, as there's no guarantee you won't hit other '\0's before your final one (I certainly was when I tested it).

Tim D