LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   pointers and multidimensional arrays in C (https://www.linuxquestions.org/questions/linux-newbie-8/pointers-and-multidimensional-arrays-in-c-4175551205/)

flatang 08-19-2015 09:20 PM

pointers and multidimensional arrays in C
 
I was following a tutorial and got lost when my program wouldn't compile and it is exactly the same as the working program in the tutorial..

#include <stdio.h>
#include <stdbool.h>

int main() {

int array[3][4]= {1,2,3,4,5,6,7,8,9,10,11,12};

int *aPtr = &array;

for(;aPtr < array+4; aPtr++ )
{
printf("%d\n ", *aPtr);
}
return 0;
}

I gets a compile error that says the following:

warning: initialization from incompatible pointer type [enabled by default]

for the line : int *aPtr = &array;

I'm using gedit and no make file just gcc -o..

the program in the tutorial builds for the guy just fine.
do I need a header file??

wildwizard 08-20-2015 04:53 AM

Quote:

Originally Posted by flatang (Post 5408231)
for the line : int *aPtr = &array;

Should be (for gcc's annoying parser)
int *aPtr = &array[0][0];

Further EDIT

GCC also hates your for loop
Code:

for(;aPtr < array+4; aPtr++ )
Can make it happy by casting
Code:

for(;aPtr < (int *)array+4; aPtr++ )
GCC is pretty hard core on standards and a lot of old C tutorials will run afoul of the parser.

Peverel 08-20-2015 06:17 AM

Actually, the parser is doing its job! The point is that array is actually of type int*, that is, it is a pointer to the first element of the array. &array is a pointer to the location that contains the array pointer, and is therefore superfluous (and wrong).

int *aPtr = array

should work.

darkonc 08-20-2015 03:27 PM

Quote:

Originally Posted by flatang (Post 5408231)
I was following a tutorial and got lost when my program wouldn't compile and it is exactly the same as the working program in the tutorial..

the program in the tutorial builds for the guy just fine.
do I need a header file??

Note that those are simply warnings -- not errors. Just letting you know that you're doing kinda weird stuff.

C multidimensional arrays are essentially arrays of arrays (if that makes sense to you). and a single-dimensional array is treated much like a simple pointer.

As a result, gcc will also happily let you get away with array[0], instead of (int*)array, or &array[0][0]

rtmistler 08-20-2015 04:25 PM

I agree with the two style recommendations of:
Code:

int *aPtr = &array[0][0];
int *aPtr = array;

Both are equivalent.

Cautionary note: Be aware of how the pointer moves and what is considered to be a row versus a column in that two dimensional array. Further, another thing you could have, and should have done would be:
Code:

int array[3][4]= {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
Note also that my interpretation is that the loop code, while legal syntax is bounding the limit test on the start pointer of the array, plus 4 integers beyond that start. In short, "pointing at 5". aPtr++ moves the pointer up by one integer at a time. array+4 is base address of array, plus either an offset of 4 integers, 4 array entries, or 4 sub-array entries. I'd have to run and detail the addresses as the pointer progressed to know correctly.

I shan't do it, I'll let you the OP debug as you see fit. You could use gdb and step through it and examine the pointer value as the loop progresses.

Just cautionary. I tend to not use stuff that's "tricky" which I don't understand. Sorry, that sounds bad, like me saying 'code I don't understand is tricky and hence I avoid it' but ... well that's a harsh truth in my world. Make sure "you" understand it if you intend to use it as part of your regular coding efforts.

wildwizard 08-20-2015 05:53 PM

Quote:

Originally Posted by rtmistler (Post 5408713)
I agree with the two style recommendations of:
Code:

int *aPtr = array;
Both are equivalent.

I tested that one and GCC hated it as well, which is why I mentioned GCC's over the top parser as been annoying.

I should point out that according to an ANSI C book I have here that that method is perfectly legal so I have no idea why GCC is complaining about it.

GCC 4.8.2 used for testing (including the old -ansi switch)

millgates 08-21-2015 05:37 AM

Quote:

Originally Posted by wildwizard (Post 5408744)
I tested that one and GCC hated it as well, which is why I mentioned GCC's over the top parser as been annoying.

I should point out that according to an ANSI C book I have here that that method is perfectly legal so I have no idea why GCC is complaining about it.

GCC 4.8.2 used for testing (including the old -ansi switch)

gcc is not complaining about that one. That one is actually correct. Please note the difference between that and the syntax actually used in the original post:

Code:

int *aPtr = &array; /* incorrect */
int *aPtr = array;  /* correct  */

gcc is not "hard core". Conforming to standards is a good thing. It helps you write good code.

rtmistler 08-21-2015 06:47 AM

I usually keep an example Makefile copy around so that I can re-use flags. There are more, but these tend to work very well for me:
Code:

CFLAGS= -I. -O0 -ggdb -Wformat=2 -Werror -Wall -Wextra -Wswitch-default -Wswitch
-enum -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wmissing-
noreturn

And you edit the -0 based on your preferences at the time and whether or not you wish optimization.

DarrenDrapkin 08-21-2015 10:27 AM

Quote:

int *aPtr = &array;

for(;aPtr < array+4; aPtr++ )
This bit could be summarised as follows, to look more conventional. It also shows that only the first 4 elements of 'array' are to be operated on.
Code:

int *aPtr;
for(aPtr=array;aPtr < array+4; aPtr++ )


wildwizard 08-21-2015 06:00 PM

Quote:

Originally Posted by millgates (Post 5408920)
gcc is not complaining about that one. That one is actually correct. Please note the difference between that and the syntax actually used in the original post:

Code:

int *aPtr = &array; /* incorrect */
int *aPtr = array;  /* correct  */

gcc is not "hard core". Conforming to standards is a good thing. It helps you write good code.

Code:

tmp.c: in function 'main':
tmp.c:11:16: warning: initialization from incompatible pointer type [enabled by default]
int *aPtr = array;
            ^

I suggest you actually try GCC and not talk theory, because I have and it is complaining about that.

darkonc 08-22-2015 12:18 PM

Don't ever use that code in a real program
 
Quote:

Originally Posted by rtmistler (Post 5408713)
Cautionary note: Be aware of how the pointer moves and what is considered to be a row versus a column in that two dimensional array.
.....
I'd have to run and detail the addresses as the pointer progressed to know correctly.

The example code is great for showing the equivalences between pointers and array -- but I don't consider it to be either portable, nor particularly easy to understand. I can think of at least two different 'reasonable' results for that code; I'd have to (carefully) read that portion of "The 'C' Programming Language" to figure out which was the 'proper' way of doing things; and I wouldn't bet my life that some implementations wouldn't do it 'the other way'.


In short: If I saw those constructs in live code, I'd hunt down the responsible programmer with a paintball gun.


a much more sane way of doing the loop:
int i;

for(i=0; i<4; i++)
{
printf("%d\n ", aPtr[i] );
}

Or, (if you actually wanted to change aPtr as a side effect:
for(i=0; i<4; i++)
{
printf("%d\n ", *aPtr++ );
}

ntubski 08-22-2015 02:08 PM

Code:

int array[3][4]= {{1,2,3,4},{5,6,7,8},{9,10,11,12}};

int *aPtr = &array; /* incorrect */
int *aPtr = array;  /* incorrect */

int *aPtr = array[0]; /* correct */
int *aPtr = &array[0][0]; /* correct */

// similarly:

    for(;aPtr < array+4; aPtr++ ) /* incorrect */
    for(;aPtr < array[4]; aPtr++ ) /* incorrect (because it goes past end of array) */
    for(;aPtr < array[3]; aPtr++ ) /* correct */
    for(;aPtr < &array[3][0]; aPtr++ ) /* correct */
    for(;aPtr < &array[2][4]; aPtr++ ) /* correct */

Quote:

Originally Posted by wildwizard
I should point out that according to an ANSI C book I have here that that method is perfectly legal so I have no idea why GCC is complaining about it.

Due to array decay,
the expression array is equivalent to &array[0]. Since
array is 3 arrays of arrays of 4 ints, array[0] is an array of
4 ints, so &array[0] is a pointer to an array of 4 ints rather than a
pointer an int.

DarrenDrapkin 08-23-2015 06:18 AM

Quote:

Originally Posted by wildwizard (Post 5409250)
Code:

tmp.c: in function 'main':
tmp.c:11:16: warning: initialization from incompatible pointer type [enabled by default]
int *aPtr = array;
            ^

I suggest you actually try GCC and not talk theory, because I have and it is complaining about that.

Thank you, It is some months since I last wrote something in C. I have been re-learning APL, and it does array handling internally.

darkonc 08-24-2015 10:31 AM

Quote:

Originally Posted by ntubski (Post 5409657)
Code:

int *aPtr = &array; /* incorrect */
int *aPtr = array;  /* incorrect */

int *aPtr = array[0]; /* correct */
int *aPtr = &array[0][0]; /* correct */


Arrays and pointers in C are (somewhat) intechangable.
All of the above are legal -- but I would describe the first three as variable degrees of silly and stupid, because it's not very clear exactly what you're trying to do.
The first one is especially problematic because it is context dependant.
Since (in this case) array is a 'real' array, &array will return the address of the array.
However, if it were a passed-in variable, it would be implemented as a pointer, and &array would/should returrn the address of the pointer (possibly depending on the pedantic correctness of the implementation)

Because that construct is context and/or implementation dependant, I would declare it to be especially stupid.

ntubski 08-24-2015 10:53 AM

Quote:

Originally Posted by darkonc (Post 5410367)
The first one is especially problematic because it is context dependant.

Yeah, I meant all those statements specifically in the case where array has type int[3][4], I've now edited that in.

Quote:

However, if it were a passed-in variable, it would be implemented as a pointer, and &array would/should returrn the address of the pointer (possibly depending on the pedantic correctness of the implementation)
Indeed, this show that arrays and pointers are not interchangeable.


All times are GMT -5. The time now is 07:04 PM.