clarification of pointers to multidimensional arrays
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
clarification of pointers to multidimensional arrays
In a C Programming text, the following code is provided:
Code:
#include <stdio.h>
int main(void)
{
int *pt;
int (*pa)[3];
int ar1[2][3];
int ar2[3][2];
int **p2; //a pointer to a pointer
pt = &ar1[0][0]; // both pointer-to-int
pt = ar1[0]; // both pointer-to-int
pt = ar1; // not valid
pa = ar1; // both pointer-to-int[3]
pa = ar2; //not valid
p2 = &pt; // both pointer-to-int *
*p2 = ar2[0]; // both pointer-to-int
p2 = ar2; //not valid:
return 0;
}
This is followed by this text:
Quote:
Notice that the nonvalid assignments all involve two pointers that don’t point to the same type. For example, pt points to a single int, but ar1 points to an array of three ints. Similarly, pa points to an array of two ints, so it is compatible with ar1, but not with ar2, which points to an array of two ints.---etc.
My general question is can anyone clarify "Why is ar1[0] considered as a pointer-to-int, rather than a pointer-to array-of 2 ints"?
Thanks in advance
Richard
Well ar1 is the address of a block of memory containing the addresses of specific memory locations of integers. So the first element in ar1, ar1[0], is the address of a memory location containing the address of an int.
I understand about pointing to the first element, an int: what is confusing me is that for the invalid assignments in the above code, I get terminal msgs such as:
pa = ar1; //*both*pointer-to-int[3]
pa = ar2; //not*valid:incompatible pointer types assigning to 'int (*)[3]' from 'int [3][2]'
ar1 and ar2 both have a 'first' integer element, so I'm not comprehending something regarding these multidimensional pointers. Can you figure where I'm getting lost?
Consider these to implementations of the same logic. Perhaps that will make it clearer.
Both of these programs produce the same output:
Code:
ar1:
1 2 3
4 5 6
inv:
1 2
3 4
5 6
First program, using int[r][c] form.
Code:
#include <stdlib.h>
#include <stdio.h>
void aprint(char* name, int *a, int r, int c) {
int i, j, d;
printf("\n%s:\n", name);
for (i=0;i<r;++i) {
for (j=0;j<c;++j) {
d=c*i+j;
printf("\t%d", *(a+d));
}
printf("\n");
}
return;
}
void main() {
int ar1[2][3];
int i, j;
for (i=0; i<2;++i) {
for (j=0;j<3;++j) {
ar1[i][j]=3*i+j+1;
}
}
aprint("ar1", *ar1, 2, 3);
printf("\n");
aprint("inv", *ar1, 3, 2);
exit(0);
}
Second form, using explicit memory allocation:
Code:
#include <stdlib.h>
#include <stdio.h>
void aprint(char* name, int **a, int r, int c) {
int i, j, d;
printf("\n%s:\n", name);
for (i=0;i<r;++i) {
for (j=0;j<c;++j) {
d=c*i+j;
printf("\t%d", *(*a+d));
}
printf("\n");
}
return;
}
void main() {
int **ar1;
int i, j, v;
ar1=(int **) malloc(2*3*(sizeof(int *)));
for (i=0; i<2*3;++i) {
*(ar1 + i)=(int *) malloc(sizeof(int));
}
v=0;
for (i=0; i<2;++i) {
for (j=0;j<3;++j) {
*(*ar1+v)=++v;
}
}
aprint("ar1", ar1, 2, 3);
printf("\n");
aprint("inv", ar1, 3, 2);
exit(0);
}
PT;
Thanks for extended explanation, which will require some study (on my part) to understand what you've said.
Interestingly, you said:
Quote:
Both of these programs produce the same output:
----while, in fact, they don't!
Quote:
First program output
ar1:
1 2 3
4 5 6
inv:
1 2
3 4
5 6
Quote:
Second program output
ar1:
0 1 2
3 4 5
inv:
0 1
2 3
4 5
Also had to switch to
int main(void)
for my compiler.
That probably won't change the intent of your explanation.
Now to peruse what you've written-----
PT;
looked over your last post, but unfortunately am not advanced enough to comprehend it as yet.
The very next subchapter in the text I'm going thru is about "Functions and Multidimensional Arrays", and starts off with "If you want to write functions that process two-dimensional arrays, you need to understand pointers well enough to make the proper declarations for function arguments."
Unfortunately, I'm not yet at that stage. Also have not yet learned about dynamic memory allocation, so the coding is way over my head.
Thanks, however, for the great attempt you made to help.
Think I'll try to get some grasp of that next section of text, and then return to your example.
Also had to switch to
int main(void)
for my compiler.
That probably won't change the intent of your explanation.
Now to peruse what you've written-----
That's strange. Might I ask which compiler you're using?
Those programs, for my compiler:
Code:
$ gcc --version
gcc (GCC) 4.8.1 20130920 (Red Hat 4.8.1-10)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
on this system (Fedora 21) they do produce the same output, and -- since that code is very basic 'C' -- the fact that they don't for you is somewhat disturbing.
<edit>
If you retyped the code, check the line where the value of ar1[i][j] is set in the second form. The output you posted is what I would have expected if you post-incremented v (v++) instead of pre-incrementing it.
</edit>
Last edited by PTrenholme; 10-06-2013 at 11:38 AM.
That's strange. Might I ask which compiler you're using?
Those programs, for my compiler:
on this system (Fedora 21) they do produce the same output, and -- since that code is very basic 'C' -- the fact that they don't for you is somewhat disturbing.
You have some code with undefined behaviour:
Code:
array-heap.c: In function ‘main’:
array-heap.c:25:23: warning: operation on ‘v’ may be undefined [-Wsequence-point]
*(*ar1+v)=++v;
O.K., here's a version the passes the -Wall test (and make the pointer manipulation somewhat clearer).:
Code:
#include <stdlib.h>
#include <stdio.h>
void aprint(char* name, int **a, int r, int c) {
int i, j, d;
printf("\n%s:\n", name);
for (i=0;i<r;++i) {
for (j=0;j<c;++j) {
d=c*i+j;
printf("\t%d", *(*a+d));
}
printf("\n");
}
return;
}
int main() {
int **ar1;
int *p;
int i, j, v;
ar1=(int **) malloc(2*3*(sizeof(int *)));
for (i=0; i<2*3;++i) {
*(ar1 + i)=(int *) malloc(sizeof(int));
}
v=0;
for (i=0; i<2;++i) {
for (j=0;j<3;++j) {
p=*ar1+v;
++v;
*p=v;
}
}
aprint("ar1", ar1, 2, 3);
printf("\n");
aprint("inv", ar1, 3, 2);
return 0;
}
<edit>
But I'm still curious about the compiler (or settings) the OP was using.
</edit>
<edit2>
If you were to add these four lines before the return in the above program:
Warning:test is a bash system command name. You can really mess things up if you put an executable named test in a directory in your search path.
In the aprint function, the d is an pointer increment value. Adding one to the computed value changes the code to reference the "next" value in the base array. That should have caused the code to refference an uninitialized value following the 6, and to have started with the second value, 2.
Can you post the actual code you used? What you said worked, should not have worked.
In fact, here's what I get for
Code:
$ cat alloc2.c
#include <stdlib.h>
#include <stdio.h>
void aprint(char* name, int **a, int r, int c) {
int i, j, d;
printf("\n%s:\n", name);
for (i=0;i<r;++i) {
for (j=0;j<c;++j) {
d=c*i+j;
printf("\t%d", *(*a+d));
}
printf("\n");
}
return;
}
int main() {
int **ar1;
int *p;
int i, j, v;
ar1=(int **) malloc(2*3*(sizeof(int *)));
for (i=0; i<2*3;++i) {
*(ar1 + i)=(int *) malloc(sizeof(int));
}
v=0;
for (i=0; i<2;++i) {
for (j=0;j<3;++j) {
p=*ar1+v;
++v;
*p=v;
}
}
aprint("ar1", ar1, 2, 3);
printf("\n");
aprint("inv", ar1, 3, 2);
printf("\n");
aprint("row", ar1, 1, 2*3);
printf("\n");
aprint("column", ar1, 2*3, 1);
return 0;
}
Code:
$ clang -O0 -std=c99 -Wall alloc2.c -o alloc2_1$ #Note: I have no idea what's in the cs50 library you referenced, but nothing in the code needs it, nor the math library.$ ./alloc2_1
ar1:
1 2 3
4 5 6
inv:
1 2
3 4
5 6
row:
1 2 3 4 5 6
column:
1
2
3
4
5
6
Last edited by PTrenholme; 10-07-2013 at 10:59 AM.
PT;
CS50 library is an inclusion for an online C Programming course (#CS50). Includes some basics like a getString program, along with many of stdio fns. I know so little about compilers that I don't know how to even delete it from the "make" cmd.
Quote:
Can you post the actual code you used? What you said worked, should not have worked.
Code:
#include <stdlib.h>
#include <stdio.h>
void aprint(char* name, int **a, int r, int c) {
int i, j, d;
printf("\n%s:\n", name);
for (i=0;i<r;++i) {
for (j=0;j<c;++j) {
d=c*i+j+1;
printf("\t%d", *(*a+d));
}
printf("\n");
}
return;
}
int main() {
int **ar1;
int i, j, v;
ar1=(int **) malloc(2*3*(sizeof(int *)));
for (i=0; i<2*3;++i) {
*(ar1 + i)=(int *) malloc(sizeof(int));
}
v=0;
for (i=0; i<2;++i) {
for (j=0;j<3;++j) {
*(*ar1+v)=++v;
}
}
aprint("ar1", ar1, 2, 3);
printf("\n");
aprint("inv", ar1, 3, 2);
exit(0);
}
I see what you mean about incrementing the pointer value, but the above consistently gives values 1-6 for array elements (unless I'm actually printing the index #s). I had previously tried pre-invrementing v, but that didn't work.
By the way, shouldn't malloc be freed. or does 'exit(0) take care of that?
richard
Last edited by atlantis43; 10-07-2013 at 01:35 PM.
Didn't notice the suggestion previously, but I have been looking at that also, but it doesn't make it any clearer to me. Not quite sure what the underlying basis of my confusion is. The multidimensions are killing me.
So ar1[0] is in fact an array-of(2 ints), but then "decays" into a plain pointer-to(int) when used.
Quote:
Originally Posted by atlantis43
I understand about pointing to the first element, an int: what is confusing me is that for the invalid assignments in the above code, I get terminal msgs such as:
pa = ar1; //*both*pointer-to-int[3]
pa = ar2; //not*valid:incompatible pointer types assigning to 'int (*)[3]' from 'int [3][2]'
ar1 and ar2 both have a 'first' integer element, so I'm not comprehending something regarding these multidimensional pointers.
The rule (see question 6.3) by which arrays decay into pointers is not applied recursively. (Once the rule has been applied once, the result is a pointer to which the rule no longer applies.) An array of arrays (i.e. a two-dimensional array in C) decays into a pointer to an array, not a pointer to a pointer. Pointers to arrays can be confusing, and must be treated carefully; see also question 6.13.
So the "outer" level of "arrayness" decays, but there is no further decay: ar1 is array-of(2 array-of(3 int)) which decays to pointer-to(array-of(3 int)), ar2 is array-of(3 array-of(2 int)) which decays to pointer-to(array-of(2 int)).
That statement still has undefined behaviour; it might be consistent with a particular version of a particular compiler but you can't rely on it.
---so I recognized after your first comment about the undefined behavior.
Quote:
So the "outer" level of "arrayness" decays, but there is no further decay: ar1 is array-of(2 array-of(3 int)) which decays to pointer-to(array-of(3 int)), ar2 is array-of(3 array-of(2 int)) which decays to pointer-to(array-of(2 int)).
YEAH-- that seems to clear things up! In FAQ, I had no explanation of what the 'decay' process was, so the details made no sense. I think that I'm now on the road to enlightenment.
Thanks so much.
(I'll have to see whether there's any preceding explanation of 'decay' in the FAQ, or suggest to the publishers to add what you've written)
follow-up----searched FAQ, and found no explanation there regarding their use of "decay". Your explanation is priceless!
Last edited by atlantis43; 10-07-2013 at 05:16 PM.
Reason: follow-up
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.