unable to compile code for multi-dimensional array

M

moijes12

Hi

My program is shown below.It is basically to print out all the
elements of a 2-dimensional array using a pointer to the array.

*****************************
#include <stdio.h>

int main(){
int x[3][5] = {
{1,2,3,4,5},
{6,7,8,9,10},
{11,12,13,14,15}
};
int *n;
int i,j;

n = x;
for(i=0;i<3;i++)
for(j=0;j<5;j++)
printf("%d ",*(*(n+i)+j));

printf("\n");
return 0;
}

*****************************

However,I get a compilation error
exercise_f.c: In function ‘main’:
exercise_f.c:12: warning: assignment from incompatible pointer type
exercise_f.c:15: error: invalid type argument of ‘unary *’ (have
‘int’)


I am using gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)

I am unable to understand why this causes such an error.If i declare
the pointer as 'int **n' ,it compiles without errors but on running,it
throws segmentation fault.

Is this a compiler problem or a programming one ?
Please help me with this.

regards
Moses
 
S

Seebs

int main(){
int x[3][5] = { [...] };
int *n;
int i,j;

This is incompatible.
for(i=0;i<3;i++)
for(j=0;j<5;j++)
printf("%d ",*(*(n+i)+j));

And this is wrong, because you're assuming that the compiler will
magically know that "n" should really be viewed as a pointer to
array[5] of int, rather than a pointer to int. But you declared it
as a pointer to int.
However,I get a compilation error
exercise_f.c: In function ?main?:
exercise_f.c:12: warning: assignment from incompatible pointer type
exercise_f.c:15: error: invalid type argument of ?unary *? (have
?int?)
Right.

I am unable to understand why this causes such an error.

Because your code is wrong. You've declared a pointer to int.
You have then tried to assign it to point to an array[5] of int,
rather than to an int. That's wrong.

But let's say you did it "right":
n = &x[0][0];

.... Well, now what? "n" is a pointer to int. "n+i" will not go to
the i'th element of x, but to the i'th element of x[0]. There's no way
for the compiler to know that you want "n+i" to jump to the next item
in the array.

You could, of course, create a pointer to array[5] of int, then "n+i"
would point to the i'th element of n... But then you'd find that
"n+i+j" pointed to the n+i+j'th element of n, not to the j'th element
of the i'th element of n.
If i declare
the pointer as 'int **n' ,it compiles without errors but on running,it
throws segmentation fault.

That would be because you would be lying to the compiler.

"int **" and "int [][]" are TOTALLY different types.

Here's how it works.

int[3][5] = {
{ a, b, c, d, e },
{ f, g, h, i, j },
{ k, l, m, n, o },
}

This is an array of arrays. It's one contiguous block of memory.

For "int **", it's different.

Imagine three arrays:
int a1[] = { a, b, c, d, e };
int a2[] = { f, g, h, i, j };
int a3[] = { k, l, m, n, o };

Now, these three arrays MAY NOT BE CONTIGUOUS. They could be any old
arrays, anywhere.

Now imagine a fourth array:

int *a4[] = { &a[0], &a2[0], &a3[0] };

Now...

int **n = &a4[0];

**n is a pointer. It is an object *separate from* a4, although it holds
the address of a4[0]. Similarly, a4 is an array of three objects. Each
of these objects is *separate from* the array that it holds the address
of the first member of.
Is this a compiler problem or a programming one ?

Programming.

You might like to have a look at the comp.lang.c FAQ section on arrays
and pointers.

Basically, you're getting tripped up because there's a general pattern
that, in most contexts, if you use the name of an array, the compiler
magically turns it into the address of the first item of the array. That
makes pointers and arrays behave similarly in some expressions, but they
are NOT the same thing. An array is a block of objects; there's just
the array, and it has an address, but the address is not a separate
object that's stored somewhere, it's just that the block of objects
is stored somewhere. A pointer is a separate object from the thing it
points to.

-s
 
S

Shao Miller

moijes12 said:
Hi

My program is shown below.It is basically to print out all the
elements of a 2-dimensional array using a pointer to the array.

*****************************
#include <stdio.h>

int main(){
int x[3][5] = {
{1,2,3,4,5},
{6,7,8,9,10},
{11,12,13,14,15}
};
int *n;

'n' is thus an 'int *'; a pointer-to-int.
int i,j;

n = x;

Here's your warning, above. 'x' "decays" into an 'int(*)[5]', not an
'int *'. An 'int(*)[5]' is a pointer-to-array-of-int-with-five-elements.
for(i=0;i<3;i++)
for(j=0;j<5;j++)
printf("%d ",*(*(n+i)+j));

'*(n+i)' yields an 'int', because 'n' is 'int *'. Then you add 'j' to
that, which also yields an 'int'. There's your error where you attempt
to apply the unary '*' indirection operator to an 'int'.
printf("\n");
return 0;
}

*****************************

However,I get a compilation error
exercise_f.c: In function ‘main’:
exercise_f.c:12: warning: assignment from incompatible pointer type
exercise_f.c:15: error: invalid type argument of ‘unary *’ (have
‘int’)


I am using gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)

I am unable to understand why this causes such an error.If i declare
the pointer as 'int **n' ,it compiles without errors but on running,it
throws segmentation fault.

How about:

#include <stdio.h>

/* Handy for arrays. */
#define NUM_OF_ELEMENTS(array_) \
(sizeof (array_) / sizeof *(array_))
#define FOR_EACH_ELEMENT(index_, array_) \
for ((index_) = 0; (index_) < NUM_OF_ELEMENTS(array_); (index_)++)

/* Note 'void'. */
int main(void) {
int x[3][5] = {
{1,2,3,4,5},
{6,7,8,9,10},
{11,12,13,14,15}
};
int i, j;

FOR_EACH_ELEMENT(i, x)
FOR_EACH_ELEMENT(j, x)
printf("%d ", x[j]);

puts("");
return 0;
}
Is this a compiler problem or a programming one ?
Please help me with this.

Hope this helps.
 
S

Sebastian

int main(){
    int x[3][5] = {
                      {1,2,3,4,5},
                      {6,7,8,9,10},
                      {11,12,13,14,15}
                  };
    int *n;

make that

int (*n)[5];

It's a pointer to an array of 5 ints which is the correct type the
array x decays to. It neither decays to int* nor int**.
    int i,j;

    n = x;
    for(i=0;i<3;i++)
        for(j=0;j<5;j++)
            printf("%d ",*(*(n+i)+j));

Note that, if some t is a pointer or an array the following
expressions are equivalent: *(t+index) and t[index]. So, you could
write the following:

printf("%d ",n[j]);

HTH,
SG
 
B

Barry Schwarz

On Sun, 26 Sep 2010 06:17:07 -0400, Shao Miller

snip
How about:

#include <stdio.h>

/* Handy for arrays. */
#define NUM_OF_ELEMENTS(array_) \
(sizeof (array_) / sizeof *(array_))
#define FOR_EACH_ELEMENT(index_, array_) \
for ((index_) = 0; (index_) < NUM_OF_ELEMENTS(array_); (index_)++)

/* Note 'void'. */
int main(void) {
int x[3][5] = {
{1,2,3,4,5},
{6,7,8,9,10},
{11,12,13,14,15}
};
int i, j;

FOR_EACH_ELEMENT(i, x)
FOR_EACH_ELEMENT(j, x)
printf("%d ", x[j]);

puts("");
return 0;
}


How about an award for the most obnoxious way to confuse a newcomer.
 
B

Barry Schwarz

Hi

My program is shown below.It is basically to print out all the
elements of a 2-dimensional array using a pointer to the array.

*****************************
#include <stdio.h>

int main(){
int x[3][5] = {
{1,2,3,4,5},
{6,7,8,9,10},
{11,12,13,14,15}
};
int *n;
int i,j;

n = x;

With a few exceptions that don't apply here, when an expression with
array type is evaluated, it is converted to the address of the first
array element with type pointer to element type.

x is an array of 3 arrays of 5 int. The first element of x is
obviously x[0]. This is an array of 5 int. Therefore the expression
x is converted to the address of x[0] with type pointer to array of 5
int. This type is expressed in C code as
int(*)[5]

You defined n as an int*. int* and int(*)[5] are incompatible types,
hence the diagnostic. If you changed the declaration of n to
int (*n)[5];
the cause of both diagnostics would be corrected.

Side note: The parentheses above are mandatory. The declaration
int *n[5];
would declare n to by an array of 5 pointers to int which is something
completely different.
for(i=0;i<3;i++)
for(j=0;j<5;j++)
printf("%d ",*(*(n+i)+j));

Once you fix the declaration of n the last argument will be correct.
However, this style has absolutely nothing to recommend it over the
more popular and much easier on the eyes n[j].
printf("\n");
return 0;
}

*****************************

However,I get a compilation error
exercise_f.c: In function ‘main’:
exercise_f.c:12: warning: assignment from incompatible pointer type
exercise_f.c:15: error: invalid type argument of ‘unary *’ (have
‘int’)

This has been discussed in other responses.
I am using gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)

I am unable to understand why this causes such an error.If i declare
the pointer as 'int **n' ,it compiles without errors but on running,it
throws segmentation fault.

If it compiles without error, you have the diagnostic settings on your
compiler set wrong. The type int(*)[5] is just as incompatible with
int** as it was with int*. Fix your compiler parameters so you get
the same diagnostic as you did with the first case so that it doesn't
mislead you in future projects.

As for the seg fault: When you declare int **n, you are telling the
compiler that n points to a pointer. That is what pointer to pointer
to int means. So when the compiler generates the code to evaluate
*(n+i) (or the eqauivalent n), it will assume that it can find a
pointer to int at that location. Since that location contains an int
and does not contain the address of anything, you have lied to the
compiler and invoked undefined behavior. (In all likelihood, the
generated code is treating the value at that address as another
address and is attempting to access memory you don't own.)

Consider yourself fortunate. A seg fault is one of the better
manifestations of undefined behavior.
Is this a compiler problem or a programming one ?

It is not impossible to find compiler errors. However, in the
overwhelming majority of cases the problem is with your code.
 
M

Malcolm McLean

Hi

My program is shown below.It is basically to print out all the
elements of a 2-dimensional array using a pointer to the array.
The main thing you need to understand is that thopugh almost every C
primer introduces 2d and higher arrays the page after 1d arrays, this
glosses over the fact that, in C, the multi-dimensional array is an
advanced feature. The syntax for using them is difficult. They also
cannot be used in many situations where you would normally expect them
to be used, because the dimensions are fixed. Allocating
multidimesnional arrays also leads to complications.
 
S

Shao Miller

Barry said:
On Sun, 26 Sep 2010 06:17:07 -0400, Shao Miller

snip
How about:

#include <stdio.h>

/* Handy for arrays. */
#define NUM_OF_ELEMENTS(array_) \
(sizeof (array_) / sizeof *(array_))
#define FOR_EACH_ELEMENT(index_, array_) \
for ((index_) = 0; (index_) < NUM_OF_ELEMENTS(array_); (index_)++)

/* Note 'void'. */
int main(void) {
int x[3][5] = {
{1,2,3,4,5},
{6,7,8,9,10},
{11,12,13,14,15}
};
int i, j;

FOR_EACH_ELEMENT(i, x)
FOR_EACH_ELEMENT(j, x)
printf("%d ", x[j]);

puts("");
return 0;
}


How about an award for the most obnoxious way to confuse a newcomer.


There were other parts of my response, too. If you or a newcomer or
anyone else either doesn't appreciate the aesthetic in the code above or
doesn't understand how it works, feel free to discard it or to inquire
about it; discussion is welcome.

I'm sorry that you appear not to enjoy it, Mr. B. Schwarz. Have a nice
day anyway.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,114
Members
46,702
Latest member
VernitaGow

Latest Threads

Top