LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 10-05-2013, 09:30 AM   #1
atlantis43
Member
 
Registered: Feb 2013
Posts: 289

Rep: Reputation: Disabled
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
 
Old 10-05-2013, 10:48 AM   #2
PTrenholme
Senior Member
 
Registered: Dec 2004
Location: Olympia, WA, USA
Distribution: Fedora, (K)Ubuntu
Posts: 4,187

Rep: Reputation: 354Reputation: 354Reputation: 354Reputation: 354
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.
 
Old 10-05-2013, 11:58 AM   #3
atlantis43
Member
 
Registered: Feb 2013
Posts: 289

Original Poster
Rep: Reputation: Disabled
PT:

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?
 
Old 10-05-2013, 01:00 PM   #4
PTrenholme
Senior Member
 
Registered: Dec 2004
Location: Olympia, WA, USA
Distribution: Fedora, (K)Ubuntu
Posts: 4,187

Rep: Reputation: 354Reputation: 354Reputation: 354Reputation: 354
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);
}
 
Old 10-05-2013, 02:32 PM   #5
atlantis43
Member
 
Registered: Feb 2013
Posts: 289

Original Poster
Rep: Reputation: Disabled
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-----
 
Old 10-05-2013, 08:21 PM   #6
atlantis43
Member
 
Registered: Feb 2013
Posts: 289

Original Poster
Rep: Reputation: Disabled
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.

Richard
 
Old 10-06-2013, 11:29 AM   #7
PTrenholme
Senior Member
 
Registered: Dec 2004
Location: Olympia, WA, USA
Distribution: Fedora, (K)Ubuntu
Posts: 4,187

Rep: Reputation: 354Reputation: 354Reputation: 354Reputation: 354
Quote:
Originally Posted by atlantis43 View Post
[...]while, in fact, they don't!


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.
 
Old 10-06-2013, 11:41 AM   #8
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
The C FAQ: 6. Arrays and Pointers might be helpful here.


Quote:
Originally Posted by PTrenholme
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;
 
Old 10-06-2013, 12:02 PM   #9
PTrenholme
Senior Member
 
Registered: Dec 2004
Location: Olympia, WA, USA
Distribution: Fedora, (K)Ubuntu
Posts: 4,187

Rep: Reputation: 354Reputation: 354Reputation: 354Reputation: 354
Ah so. Yes, I should have compiled with -Wall.

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:
Code:
  printf("\n");
  aprint("row", ar1, 1, 2*3);
  printf("\n");
  aprint("column", ar1, 2*3, 1);
you should see this:
Code:
$ ./alloc2

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
which might make things a little clear as you read the second chapter.

Last edited by PTrenholme; 10-06-2013 at 12:16 PM.
 
Old 10-06-2013, 03:47 PM   #10
atlantis43
Member
 
Registered: Feb 2013
Posts: 289

Original Poster
Rep: Reputation: Disabled
I got 'same' results, by incrementing line 8 of program #2:
Code:
      d=c*i+j +1 ;//this +1 was added to give same vals as in 1st example
The revised code that you wrote looks like it might be easier for me to understand what's going on.

As to second question, I'm using clang as compiler, with following switches:
Quote:
clang -ggdb3 -O0 -std=c99 -Wall -Werror test.c -lcs50 -lm -o test
Yes: it's very picky!

Last edited by atlantis43; 10-06-2013 at 07:47 PM. Reason: addnl info
 
Old 10-07-2013, 10:58 AM   #11
PTrenholme
Senior Member
 
Registered: Dec 2004
Location: Olympia, WA, USA
Distribution: Fedora, (K)Ubuntu
Posts: 4,187

Rep: Reputation: 354Reputation: 354Reputation: 354Reputation: 354
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.
 
Old 10-07-2013, 01:19 PM   #12
atlantis43
Member
 
Registered: Feb 2013
Posts: 289

Original Poster
Rep: Reputation: Disabled
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.
 
Old 10-07-2013, 01:52 PM   #13
atlantis43
Member
 
Registered: Feb 2013
Posts: 289

Original Poster
Rep: Reputation: Disabled
[QUOTE=ntubski;5041005]The C FAQ: 6. Arrays and Pointers might be helpful here.

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.
 
Old 10-07-2013, 02:29 PM   #14
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
Originally Posted by atlantis43 View Post
Code:
...
*(*ar1+v)=++v;
...
I see what you mean about incrementing the pointer value, but the above consistently gives
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.

Quote:
Originally Posted by atlantis43 View Post
Quote:
Originally Posted by ntubski View Post
The C FAQ: 6. Arrays and Pointers might be helpful here.
Didn't notice the suggestion previously, but I have been looking at that also, but it doesn't make it any clearer to me.
I'll try to relate your specific questions to the FAQ.
Quote:
Originally Posted by atlantis43 View Post
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"?
Quote:
6.3 So what is meant by the ``equivalence of pointers and arrays'' in C?
A reference to an object of type array-of-T which appears in an expression decays (with three exceptions) into a pointer to its first element; the type of the resultant pointer is pointer-to-T.
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 View Post
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.
Quote:
6.18 My compiler complained when I passed a two-dimensional array to a function expecting a pointer to a pointer.

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)).
 
1 members found this post helpful.
Old 10-07-2013, 04:05 PM   #15
atlantis43
Member
 
Registered: Feb 2013
Posts: 289

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by ntubski View Post
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
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Correct behavior of void* pointers - Clarification needed thandermax Programming 8 03-04-2010 02:33 PM
Multidimensional pointers in C rubadub Programming 4 03-26-2008 07:47 AM
Question about outputing arrays with pointers, then just arrays... RHLinuxGUY Programming 1 04-12-2006 05:40 AM
resizing multidimensional arrays in C++ banerji Programming 2 07-12-2004 07:27 PM
help w/ pointers vs arrays PTBmilo Programming 3 04-10-2003 05:13 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 05:45 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration