question on 2D arrays using pointers

D

Durango2008

Hello,
I know some C but still learning pointers and I have a question regarding
arrays using pointers.

I compiled the following code but I am confused by it:

#include <stdio.h>
#include <stdlib.h>

int main()
{
int **a;
char **b;
int i;
a = malloc(2 * sizeof(int *));
for(i = 0; i < 2; i++)
a = malloc(13 * sizeof(int));

b = malloc(2 * sizeof(char *));
for(i = 0; i < 5; i++)
b = malloc(13 * sizeof(char));

a[0][0] = 44;
b[0][0] = 55;
printf("a[0][0] = %d\n",a[0][0]);
printf("(int)*(a) = %d\n", (int)*(a+4));
printf("b[0][0] = %d\n",b[0][0]);
printf("(char)*(b) = %d\n", (int)*(b+4));

return 0;
}

I compiled this in both Linux(Redhat) using GCC and Windows XP using
Code::Blocks.
In Linux it gave the following results:
a[0][0] = 44
(int)*(a) = 44
b[0][0] = 55
b[0][0] = 55

My first question is why do you need to add 4 to the pointer index to get
the correct result?

In Windows XP it gave the following results:
a[0][0] = 44
(int)*(a) = 44
b[0][0] = 55
(char)*(b) = 4079600

It clearly shows that the final value is wrong and pointer reference issue.

What I need to know is how can dereference this 2D array properly and what
are some easier ways of obtaining
the value of a 2D array using pointers without using indexing?

Thank you for your help.
 
M

myx

I've tried to compile this code, and (int)*(a+4) really contains value
of a first element in this 2d array. It's just an strange trick, that
will not work if you create, for example, a 5x13 array, so that the
fifth cell after the address, contained in "a" will not contain a
value of the first element, but will contain an address of the fifth
row in a 2d array.
 
A

Alan Curry

Richard Heathfield said:
Durango2008 said:
int **a;
char **b;
int i;
a = malloc(2 * sizeof(int *));
for(i = 0; i < 2; i++)
a = malloc(13 * sizeof(int)); ....
a[0][0] = 44;
b[0][0] = 55;
printf("a[0][0] = %d\n",a[0][0]);
printf("(int)*(a) = %d\n", (int)*(a+4));


a (which is a lousy name for an object - why do people do that?) is
an int **. a+4 is an expression that points to the int * that is
four int *s along from a.


And since there are only 2 int *'s at the location indicated by a, adding 4
is going beyond the end of the malloc'ed object.
The correct value from the array a is 44 and for array b is 55.
The result displays this but I am not sure why I have to use the (a+4)
expression to get this value to display?

a[0] and a[1] exist, so you can add 0 or 1 to a and get a valid pointer.
(You can also add 2 to a, and get a special "trailing edge of the object"
pointer, which isn't good for anything except comparisons to the others.)

Aside from 0, 1, and 2, no other values may be legally added to a. You get
a wild pointer, which can point to anything, or could crash the program.

You somehow found the value 4 which made the wild pointer land on the number
44. That was just dumb luck. It's not very surprising that this magical value
would exist, and that it would be a small integer. That just means your first
2 mallocs returned a couple of close-together memory areas, and when you ran
past the end of the first one you ended up near the beginning of the second
one. The partial success of your method doesn't make it any less wrong. You
can't expect any consistent results from smashing past the end of an array.
I am trying to obtain the value 44 that I assigned the first element of
array a.

The thing you're starting with (a) is a pointer to a pointer. The thing
you're trying to get to (44) is not a pointer at all. Any way you choose to
get from here to there will involve 2 dereferencing operations, each of which
removes a level of pointerness. When you use a[0][0] the 2 sets of brackets
are doing the dereferencing. If you want to use *'s instead of brackets,
you'll need 2 of those also.

like this:
printf("**a = %d\n", **a);

You could also use 1 pair of brackets and 1 *. All of these are equivalent:
printf("*a[0] = %d\n", *a[0]);
printf("(*a)[0] = %d\n", (*a)[0]);
printf("*(a[0]) = %d\n", *(a[0]));

If you want addition to be explicitly involved, add 0 anywhere you like!
printf("*(*(a+0)+0) = %d\n", *(*(a+0)+0));
printf("(*(a+0))[0] = %d\n", (*(a+0))[0]);
printf("*(a[0]+0) = %d\n", *(a[0]+0));

If you add your 0's in the right places, you can easily adjust the expression
to be equivalent to a[1][2] instea of a[0][0]:
a[1][2] = 99;
printf("*(*(a+1)+2) = %d\n", *(*(a+1)+2));
printf("(*(a+1))[2] = %d\n", (*(a+1))[2]);
printf("*(a[1]+2) = %d\n", *(a[1]+2));

By now maybe you see why we usually prefer to just use the brackets. The
alternatives get ugly fast.
 
D

Durango2008

Richard Heathfield said:
Durango2008 said:

a[0][0] is the way to do it.
I understand this but the problem is I have to do this without using
indexing.
It is an assignment in the book I am following and it specifically asks not
to use indexing
to get the value.

thank you.
 
J

jameskuyper

Durango2008 said:
Richard Heathfield said:
Durango2008 said:

a[0][0] is the way to do it.
I understand this but the problem is I have to do this without using
indexing.
It is an assignment in the book I am following and it specifically asks not
to use indexing
to get the value.

You need to understand exactly what indexing means. I won't solve the
problem for you, but any decent C text book should tell you that a
is exactly equivalent to another expression that doesn't involve any
subscripts. Apply that rule twice to a[0][0], and if you do it
correctly you'll have your answer. Usually, it's the "correctly" part
that bogs people down.
 
K

Keith Thompson

Durango2008 said:
I know some C but still learning pointers and I have a question regarding
arrays using pointers.
[snip]

Others have given you some good advice, but I don't think anyone has
mentioned section 6 of the comp.lang.c FAQ, <http://www.c-faq.com>.
So I'll mention it. It's an excellent resource for this kind of
thing.

It's also fairly important to keep the terminology straight. In C, a
two-dimensional array is, strictly speaking, simply an array of arrays
(and likewise for higher dimensions). What you're building isn't
really a 2D array; it's an array of pointers, where each pointer
points to the first element of an array (of char or of int).

On the other hand, referring to such a data structure as a 2D array is
common, and I wouldn't say it's actually wrong as long as you keep the
distinction in mind. An array-of-pointers implementation like yours
is actually much more flexible than an array of arrays; for example,
you can adjust the size of each row and of the entire array
dynamically.

Confusingly, you can use the same indexing notation in either case.
Consider this demo program:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int main(void)
{
/*
* First, we create and initialize a simple 2D array.
* This is very straightforward, but it's inflexible;
* we have to choose the size when we write the program,
* and we can't change it later. (C99's VLAs add some
* flexibility, but at a cost.)
*/
int arr[2][2] = {{10, 20},
{30, 40}};

/*
* Now we create and initialize a data structure that acts
* like a 2D array, though strictly speaking it isn't one.
* This is more work, but it's much more flexible. We can
* even have different lengths for different rows if
* we like. (It would be even more work if we kept track
* of all the sizes rather than assuming it's 2 by 2.)
*/
int **ptr;
int i, j;

ptr = malloc(2 * sizeof *ptr);
if (ptr == NULL) exit(EXIT_FAILURE);

for (i = 0; i < 2; i ++) {
ptr = malloc(2 * sizeof *ptr);
if (ptr == NULL) exit(EXIT_FAILURE);
}
/*
* Now we initialize the elements (we can't use an
* initializer for this as we did for arr).
*/
ptr[0][0] = 100;
ptr[0][1] = 200;
ptr[1][0] = 300;
ptr[1][1] = 400;

/*
* Now we can look at the values. Note that we use
* the same notation for both, but it's not doing the
* same thing.
*/
for (i = 0; i < 2; i ++) {
for (j = 0; j < 2; j ++) {
printf("arr[%d][%d] = %d, ptr[%d][%d] = %d\n",
i, j, arr[j],
i, j, ptr[j]);
}
}

return 0;
}

arr[j] and ptr[j] mean very different things, even though they
look equivalent. The reason for this is that the [] operator really
takes a pointer as its first operand (pointer[index]). If you give it
an array rather than a pointer, the array is implicitly converted to a
pointer; there are two such conversions in arr[j]. If you give
something that's already a pointer, as in ptr[j], no such
conversion is necessary. (You can even have hybrid data structures,
so there are 4 possible interpretations for foo[j], and 8 for
foo[j][k].)

And the point all that looping, mallocing, and assigning we did to set
up ptr was to make ptr[j] work just like arr[j], even though
they do very different things.

(Since somebody will mention it if I don't, I am deliberately ignoring
the possiblity of writing index[pointer] or index[array]; see question
6.11 in the FAQ for an example of code not to write.)
 
D

Durango2008

Richard Heathfield said:
X[Y] is precisely equivalent to *(X + Y).

X[Y][Z] is precisely equivalent to (X[Y])[Z]

So X[Y][Z] is precisely equivalent to *((*(X + Y))+Z)

Thanks for this clarification, I realize I was doing it wrong but getting
the value that I was expecting
threw me off and got me confused. Anyway, thank you again :)
 
D

Durango2008

Thanks to everyone who took time to help me out, I am now a bit more
informed on the nature of pointers.
I'll probably be back with more newbie questions in the future :p
 
P

Phil Carmody

Richard Heathfield said:
X[Y] is precisely equivalent to *(X + Y).

X[Y][Z] is precisely equivalent to (X[Y])[Z]

So X[Y][Z] is precisely equivalent to *((*(X + Y))+Z)

So a[i >> 5] is precisely equivalent to *(a + i >> 5)? I think you need
some parenthesis if you're going to say "precisely":

You're thinking along the lines of textual replacement.
I'm sure Richard was not viewing it at such a shallow
level.
X[Y] is equivalent to (*((X) + (Y)))

As a sequence of tokens to be parsed, yes. My presumption
would be that if you're already processing the semantics
of X[Y] you've already parsed those two subexpressions.

Phil
 
K

Keith Thompson

Durango2008 said:
I know some C but still learning pointers and I have a question regarding
arrays using pointers.

Technically, arrays don't *use* anything. Have you read the FAQ?

(Please don't use the wrong year in your posting ID.)
 
B

Beej Jorgensen

Richard Bos said:

I identified the troll, and then laughed at what he said. Now I've been
to Amsterdam, and I know at least the customs officers have a sense of
humor.

-Beej
 
F

Flash Gordon

Beej said:
I identified the troll, and then laughed at what he said. Now I've been
to Amsterdam, and I know at least the customs officers have a sense of
humor.

Ah, so you think it is appropriate to encourage trolling.
 

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,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top