COMPGROUPS.NET | Search | Post Question | Groups | Stream | About | Register

### Pointer to a 2 dimensional array?

• Email
• Follow

```Dear readers,

Full source code with data file at (50k):
http://www.sendspace.com/file/32ghfp

My C book says that an array is the same as a pointer to the array.

So I would really like to have fit_data.c to return a pointer to a 2
dimensional array, data_space.

How would you put char's into such an array?

That is what I am trying to do in the last for-loop in fit_data.c, but
doesn't seam to be valid.

Lots of love,
Louise =)

--- tit_data.c ---

char fit_data(double start_x, double slut_x,
double start_y, double slut_y,
double *x, double *y,
int n) {

char *data_space;

int size = X_BINS * Y_BINS * sizeof(char);
data_space = malloc(size);
if (data_space == 0) {
printf("Out of memory\n");
exit(EXIT_FAILURE);
}

/* Fill array with white space */
int i=0;
for(i=0; i<size; i++) {
*(data_space + i) = ' ';
}

/* check if a data point should be inserted, and in such case where
*/
i=0;
int ybin, xbin;
for (i=0; i<n; i++) {
if (x[i] >= start_x && x[i] <= slut_x &&
y[i] >= start_y && y[i] <= slut_y) {

/* where to put x */
xbin = (int) round( (x[i] - start_x)/(slut_x - start_x)
*X_BINS );
/* where to put y */
ybin = (int) round( (y[i] - start_y)/(slut_y - start_y)
*Y_BINS );

data_space[xbin][ybin] = '*';
}
}

return data_space;
}

--- tit_data.c ---
```
 0
Reply louise.hoffman (25) 12/15/2008 12:27:12 AM

See related articles to this posting

```Louise Hoffman wrote:
> [...]
> My C book says that an array is the same as a pointer to the array.

This means that the author of your C book has not
acquainted himself or herself with Question 6.9 of the
comp.lang.c Frequently Asked Questions (FAQ) list at
<http://www.c-faq.com/>.  It wouldn't surprise me to
learn that the rest of Section 6 had also escaped his
or her notice, which is too bad because a good deal of
that section contains information that would have been
any of it.  Alas! for an opportunity lost, a life wasted!

--
Eric Sosman
esosman@ieee-dot-org.invalid
```
 0
Reply esosman2 (3096) 12/15/2008 1:58:23 AM

```Louise Hoffman <louise.hoffman@gmail.com> writes:

> Full source code with data file at (50k):
> http://www.sendspace.com/file/32ghfp
>
> My C book says that an array is the same as a pointer to the array.

It is leading you astray, then!  An expression of array type is
converted to a pointer to the first element in all but three (very
important) cases[1].  This means that you can end up thinking that an array
is a pointer, but you will get bitten by this if don't keep reminding
your self that an array is an array and a pointer is something else
entirely even though there is a handy conversion from one to the
other in most cases.

See http://c-faq.com/aryptr/aryptrequiv.html

> So I would really like to have fit_data.c to return a pointer to a 2
> dimensional array, data_space.

Have a look at http://c-faq.com/aryptr/dynmuldimary.html

Rather than pick over your code now, read that FAQ, and come back if you
have questions.  You need to decide what sort of 2D array you want first.

[1] the exceptions are when the array is an operand of sizeof, when it is
the operand of & and when it is a string literal used to initialise an
array.  E.g. given

char c[1000] = "hello";

it is unlikely that sizeof c == sizeof (char *).  Also, the type of &c
is the rather odd-looking type char (*)[1000] and not char ** as it
would be if c were converted to a pointer to char as it normally is.
Lastly, the array denoted by the string "hello" is not converted to a
pointer to char, but is simply used to initialise the array.

--
Ben.
```
 0
Reply ben.usenet (6790) 12/15/2008 2:12:17 AM

```Louise Hoffman <louise.hoffman@gmail.com> writes:
>
> Full source code with data file at (50k):
> http://www.sendspace.com/file/32ghfp
>
> My C book says that an array is the same as a pointer to the array.
[...]

Which C book is that?

If it says that, it's wrong, but you should also consider the
possibility that you've misunderstood what it says.  Can you quote the
relevant passage from the book?

As others have suggested, section 6 of the comp.lang.c FAQ,
<http://www.c-faq.com>, does an excellent job of explaining this
stuff.  The relationship between arrays and pointers in C can be
confusing, but it's not that bad once you understand the underlying
concepts.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
```
 0
Reply kst-u (21963) 12/15/2008 2:55:39 AM

```Firstly it might help to think of multi-dimensional arrays as "an
array of arrays", because that is exactly how the language treats
them.

So if you have an object as follows:

int array[5][3];

Then it's the same as:

typedef int IntArrayThree[3];

IntArrayThree array[5];

Secondly, as Ben Bacarisse has already mentioned, there are three
places in which an array stays as an array. In other places, the array
undergoes an implicit conversion to a pointer to its first element.

In the case of the array, "array", it's an array containing 5 elements
and each element is an "IntArrThree". Therefore, if you do something
like:

CallSomeFunction(array);

Then you're passing as an argument to that function a pointer to the
first element of "array". Since an element of "array" is of type
IntArrayThree, that means a pointer to the first element will be of
the type IntArrayThree*. If we take away the decorative typedef, the
type is:

int (*)[3]

If you were to dereference this pointer, such as:

CallSomeFunction(*array);

Then the argument would be of type:

int[3]

but of course, because it's an array, it will undergo an implicit
conversion to a pointer to its first element:

int*

That's pretty much all there is to it: Multi-dimensional arrays are
arrays of arrays, and arrays undergo an implicit conversion to a
pointer to their first element (in all but three cases).
```
 0
Reply toe (740) 12/15/2008 4:18:02 AM

```One more thing, I forgot to mention about taking the address of an
array. Using the address-of operator on an array (i.e. the & operator)
is one of the three cases in which an array stays as an array. So if
you have an object as follows:

int arr[5];

then the following expression:

&arr

is of type:

int (*)[5]

int arr[5][6][7];

then the following expression:

&arr

would be of the type:

int (*)[5][6][7]

A pointer to an array gets the exact same treatment as any old
pointer, it won't undergo any funky implicit conversions. If you want
funky implicit conversions, then dereference it to yield an array
object. For instance:

*arr

would be of the type:

int [5][6][7]

But if you used this as an argument to a function, it would implicitly
convert to:

int (*)[6][7]
```
 0
Reply toe (740) 12/15/2008 4:27:05 AM

```On Dec 15, 11:27=A0am, Tom=E1s =D3 h=C9ilidhe <t...@lavabit.com> wrote:

> A pointer to an array gets the exact same treatment as any old
> pointer, it won't undergo any funky implicit conversions. If you want
> funky implicit conversions, then dereference it to yield an array
> object. For instance:
>
> *arr

That's incorrect, I should have written:

*&arr

arr is an array
&arr is a pointer to an array
When you dereference the pointer, you get the array back
```
 0
Reply toe (740) 12/15/2008 4:30:44 AM

```> Which C book is that?

My book is
K. N. King, C Programming - A modern approach, 2nd ed

> If it says that, it's wrong, but you should also consider the
> possibility that you've misunderstood what it says. =A0Can you quote the
> relevant passage from the book?

With all the arguments you all have come with, doubt I have qouted the
book right =3D)

I was pretty sure it was in chapter 17, but I can't find it...

> As others have suggested, section 6 of the comp.lang.c FAQ,
> <http://www.c-faq.com>, does an excellent job of explaining this
> stuff. =A0The relationship between arrays and pointers in C can be
> confusing, but it's not that bad once you understand the underlying
> concepts.

Yes, I didn't knew it, and I think I now have resolved the original
problem.

But I get a "segmentation fault". I am pretty sure it is either in
fit_data.c or in main.c from 50.

Can someone figure out what I am doing wrong?

Full source code with data file (~50kB) at:
http://www.sendspace.com/file/5ikqp7

With love,
Louise =3D)

```
 0
Reply louise.hoffman (25) 12/15/2008 5:26:14 AM

```Louise Hoffman said:

<snip>
>
> But I get a "segmentation fault". I am pretty sure it is either in
> fit_data.c or in main.c from 50.
>
> Can someone figure out what I am doing wrong?
>
> Full source code with data file (~50kB) at:
> http://www.sendspace.com/file/5ikqp7

Just a couple of warning flags to anyone who wants to have a crack at this:
uses at least one C99-only feature. (At this point, I gave up.)

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
```
 0
Reply rjh (10790) 12/15/2008 5:36:13 AM

```Louise Hoffman <louise.hoffman@gmail.com> writes:
>> Which C book is that?

like "Louise Hoffman <louise.hoffman@gmail.com> writes:" above);
knowing who said what makes it much easier to follow the discussion.

[...]

> But I get a "segmentation fault". I am pretty sure it is either in
> fit_data.c or in main.c from 50.
>
> Can someone figure out what I am doing wrong?
>
> Full source code with data file (~50kB) at:
> http://www.sendspace.com/file/5ikqp7

Try narrowing it down to a minimal program that exhibits the problem.
It's likely that you'll solve the problem in the course of doing this;
if not, you'll at least end up with something small enough for people
to look at.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
```
 0
Reply kst-u (21963) 12/15/2008 7:26:29 AM

```Louise Hoffman <louise.hoffman@gmail.com> writes:

<snip>
> Can someone figure out what I am doing wrong?

Just typing make showed four warnings -- all of them serious.  The
program can't work until you fix them.  Don't be fooled by gcc's kind
tone "warning: passing argument 5 of ‘fit_data’ from incompatible
pointer type" can (and in the case, does) mean "serious error:
entirely unsuitable data is being passed to fit_data".  Warnings may
be benign, but you need to know which are and which are not and when.

The third, "main.c:65: warning: assignment makes pointer from integer
without a cast", points to something that neeeds re-design.  Let me
sketch the function:

char *fit_data(<lost of args>)
{
char *p, data_space[Y_BINS][X_BINS];

/* Fill array with white space */
for (p = &data_space[0][0]; p<=&data_space[Y_BINS-1][X_BINS-1]; p++) {
*p = ' ';
}

/***************************************************
*                                                 *
*    remember to free p in main.c                 *
*                                                 *
***************************************************/
return p;
}

This doomed!  You say "remember to free" but there is nothing
malloced.  Even if you did, p points to the end of the space after the
initial loop.  The array space returned by this function must either
be of static storage duration or allocated with malloc -- local
variables (AKA automatic storage) like data_space disappear when the
function returns.

BTW, know your library.  That initial loop can be written:

memset(data_space, ' ', sizeof data_space);

--
Ben.
```
 0
Reply ben.usenet (6790) 12/15/2008 12:08:10 PM

```On Dec 15, 1:08=A0pm, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:
> Just typing make showed four warnings -- all of them serious. =A0The
> program can't work until you fix them. =A0Don't be fooled by gcc's kind
> tone "warning: passing argument 5 of =91fit_data=92 from incompatible
> pointer type" can (and in the case, does) mean "serious error:
> entirely unsuitable data is being passed to fit_data". =A0Warnings may
> be benign, but you need to know which are and which are not and when.

Glad you say so, because after I have redesigned the fit_data.c as you
point out in the next paragraf, I still get the error:

main.c:66: warning: assignment makes pointer from integer without a
cast

and that is the last line of:

p =3D *fit_data(start_x, slut_x, start_y, slut_y,
raw_s.x, raw_s.y, raw_s.n);

Isn't my raw_s.x and raw_y.y still pointers with type double? I assume
the problem is that it doesn't know that they are pointers to doubles?

> The third, "main.c:65: warning: assignment makes pointer from integer
> without a cast", points to something that neeeds re-design. =A0Let me
> sketch the function:
[snip]
> This doomed! =A0You say "remember to free" but there is nothing
> malloced. =A0Even if you did, p points to the end of the space after the
> initial loop. =A0The array space returned by this function must either
> be of static storage duration or allocated with malloc -- local
> variables (AKA automatic storage) like data_space disappear when the
> function returns.

I have now redesigned it to use malloc and got rid of the 2
dimensional array, as I assume I can't use 2-dimensional arrays to
access data in malloc'ed memory?

But I still this this
main.c:66: warning: assignment makes pointer from integer without a
cast

Can you tell where I should redesign now?

> BTW, know your library. =A0That initial loop can be written:
>
> =A0 memset(data_space, ' ', sizeof data_space);

Cool trick! Thanks =3D)

Full source code her:
http://www.sendspace.com/file/g7ps41

Hugs,
Louise =3D)
```
 0
Reply louise.hoffman (25) 12/15/2008 2:05:24 PM

```I just found a serious error. So here is a new source code:

http://www.sendspace.com/file/ugzb8j
```
 0
Reply louise.hoffman (25) 12/15/2008 2:33:31 PM

```Reply to own post. I still have the same problems, but I just fixed
that one function had its arguments typed in in the wrong order.

```
 0
Reply louise.hoffman (25) 12/15/2008 2:35:09 PM

```Louise Hoffman wrote:
....
> I have now redesigned it to use malloc and got rid of the 2
> dimensional array, as I assume I can't use 2-dimensional arrays to
> access data in malloc'ed memory?

No, it's quite feasible to do something like the following:

#include <stdlib.h>
#define ROWS 3
#define COLS 5

int main(void)
{
int (*array)[COLS] = malloc(ROWS * sizeof *array);

if(array)
{
// Use array

free(array);
}
return 0;
}

Note: ROWS could be a variable, rather than a macro, if you need to be
able to change the number of rows in your array. In C99, COLS can be a
variable, too.
```
 0
Reply jameskuyper (5639) 12/15/2008 3:00:45 PM

```Louise Hoffman <louise.hoffman@gmail.com> writes:

> On Dec 15, 1:08 pm, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:
>> Just typing make showed four warnings -- all of them serious.  The
>> program can't work until you fix them.  Don't be fooled by gcc's kind
>> tone "warning: passing argument 5 of ‘fit_data’ from incompatible
>> pointer type" can (and in the case, does) mean "serious error:
>> entirely unsuitable data is being passed to fit_data".  Warnings may
>> be benign, but you need to know which are and which are not and when.
>
> Glad you say so, because after I have redesigned the fit_data.c as you
> point out in the next paragraf, I still get the error:
>
> main.c:66: warning: assignment makes pointer from integer without a
> cast
>
> and that is the last line of:
>
>   p = *fit_data(start_x, slut_x, start_y, slut_y,
>               raw_s.x, raw_s.y, raw_s.n);

The problem is the *.  When I last saw the source, fit_data returns
char * so you just want p = fit_data(...);.  The * turns the pointer
into the char it points to.  The warning is that you can't assign an
integer type (char) to a pointer object with out a cast.  Of course,
you don't want to ass a cast (you almost never do, BTW) but you do
need to change the code.

--
Ben.
```
 0
Reply ben.usenet (6790) 12/15/2008 3:31:24 PM

```On Dec 15, 4:00=A0pm, jameskuyper <jameskuy...@verizon.net> wrote:
> No, it's quite feasible to do something like the following:
[snip]
> Note: ROWS could be a variable, rather than a macro, if you need to be
> able to change the number of rows in your array. In C99, COLS can be a
> variable, too.

That is cool! I haven't seen "(*array)[COLS]" before, so I will have
to check what it means =3D)

```
 0
Reply louise.hoffman (25) 12/15/2008 6:22:29 PM

```On Dec 15, 4:31=A0pm, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:
> The problem is the *. =A0When I last saw the source, fit_data returns
> char * so you just want p =3D fit_data(...);. =A0The * turns the pointer
> into the char it points to. =A0The warning is that you can't assign an
> integer type (char) to a pointer object with out a cast. =A0Of course,
> you don't want to ass a cast (you almost never do, BTW) but you do
> need to change the code.

WOW! That was it! =3D) =3D) =3D)

It now works =3D)
http://www.sendspace.com/file/i0dzb2

The plot it wrong though, but I guess I most have made a math error
somewhere.

What my program is suppose to do is to:
* take the 4200 data points from the ovn.sim file
* throw some of the point away based on axis limits (start_x, slut_x,
start_y, slut_y)
* scale the rest of the points down so they fit in a 10x20 coordinate
system

The output should be a curve, but I don't quite get that =3D)

Have you experience on this field as well, where the problem could be?

```
 0
Reply louise.hoffman (25) 12/15/2008 6:29:43 PM

```On Dec 15, 10:00=A0am, jameskuyper <jameskuy...@verizon.net> wrote:
>
> No, it's quite feasible to do something like the following:
>
> #include <stdlib.h>
> #define ROWS 3
> #define COLS 5
>
> int main(void)
> {
> =A0 =A0 int (*array)[COLS] =3D malloc(ROWS * sizeof *array);
>
> =A0 =A0 if(array)
> =A0 =A0 {
> =A0 =A0 =A0 =A0 // Use array
>
> =A0 =A0 =A0 =A0 free(array);
> =A0 =A0 }
> =A0 =A0 return 0;
>
> }
>
> Note: ROWS could be a variable, rather than a macro, if you need to be
> able to change the number of rows in your array. In C99, COLS can be a
> variable, too.

As Louise Hoffman writes elsethread, "That's cool". I have wondered,
and considered asking, how (on DOS systems) to write to screen memory
directly, treating it as a 2 dimensional array of type screen char.
This method would also make it easier for me to implement a curses-
like library.

If I understand you correctly, I could use,
struct screen_char {
char c, attr;
} ;
struct screen_char (*screen)[80] =3D get_screen_base();
and each spot on the screen is accessible as
screen[13][42].c =3D 'A';
screen[13][42].attr =3D REG;

Previously I had thought to do it by hiding the screen addressing in a
function, for example
void main_program(struct screen_char[25][80]);
void *screen_base =3D get_screen_base;
main_program(screen_base);
which I found not optimal because I was lying to the compiler.

Remember that while this exact use my be platform specific, the ideas
herein are definitely not. (Which is why I hide the screen_base value
in a function.)

Thanks a bunch.

Marty Amandil (almost always prepared to learn something new)
```
 0
Reply mazwolfe (69) 12/15/2008 7:13:16 PM

```Okay, found at least one bug in fit_data.c

p[ybin*(X_BINS-1) + xbin] = '*';

should have been:

p[ybin*(X_BINS) + xbin] = '*';

But now I get segmentation fault, so somewhere do I write over a
limit...

http://www.sendspace.com/file/6nguxu
```
 0
Reply louise.hoffman (25) 12/15/2008 7:59:08 PM

```Amandil wrote:
> On Dec 15, 10:00=EF=BF=BDam, jameskuyper <jameskuy...@verizon.net> wrote:
> >
> > No, it's quite feasible to do something like the following:
> >
> > #include <stdlib.h>
> > #define ROWS 3
> > #define COLS 5
> >
> > int main(void)
> > {
> > =EF=BF=BD =EF=BF=BD int (*array)[COLS] =3D malloc(ROWS * sizeof *array)=
;
> >
> > =EF=BF=BD =EF=BF=BD if(array)
> > =EF=BF=BD =EF=BF=BD {
> > =EF=BF=BD =EF=BF=BD =EF=BF=BD =EF=BF=BD // Use array
> >
> > =EF=BF=BD =EF=BF=BD =EF=BF=BD =EF=BF=BD free(array);
> > =EF=BF=BD =EF=BF=BD }
> > =EF=BF=BD =EF=BF=BD return 0;
> >
> > }
> >
> > Note: ROWS could be a variable, rather than a macro, if you need to be
> > able to change the number of rows in your array. In C99, COLS can be a
> > variable, too.
>
> As Louise Hoffman writes elsethread, "That's cool". I have wondered,
> and considered asking, how (on DOS systems) to write to screen memory
> directly, treating it as a 2 dimensional array of type screen char.
> This method would also make it easier for me to implement a curses-
> like library.
>
> If I understand you correctly, I could use,
>     struct screen_char {
>         char c, attr;
>     } ;
>     struct screen_char (*screen)[80] =3D get_screen_base();
> and each spot on the screen is accessible as
>     screen[13][42].c =3D 'A';
>     screen[13][42].attr =3D REG;

You're relying upon there being no padding between c and attr, nor any
additional padding at the end of the struct. The first assumption is a
very good one, though not guaranteed by the standard. The second
assumption is not so good: many systems pad struct types to a size
which is a multiple of some important number like 8 or 16 bytes.

You can get around that problem by using a 2-element array, rather
than a structure type:
struct screen_char (*screen)[80][2] =3D get_screen_base();

screen[13][42][0] =3D 'A';
screen[13][42][1] =3D REG;

If '0' and '1' don't feel sufficiently descriptive, you can define
macros with meaningful names whose values are 0 and 1, respectively.

> Previously I had thought to do it by hiding the screen addressing in a
> function, for example
>     void main_program(struct screen_char[25][80]);
>     void *screen_base =3D get_screen_base;
>     main_program(screen_base);
> which I found not optimal because I was lying to the compiler.

However, if you managed to get code like that working, the compiler
you're using apparantly doesn't insert any padding. Still, I'd
recommend improving the portability of your code by not relying on
that fact.

```
 0
Reply jameskuyper (5639) 12/15/2008 8:03:11 PM

```I never found the bug, but worked around it =)
```
 0
Reply louise.hoffman (25) 12/16/2008 12:41:00 AM

```Louise Hoffman <louise.hoffman@gmail.com> writes:

> Okay, found at least one bug in fit_data.c
>
>       p[ybin*(X_BINS-1) + xbin] = '*';
>
> should have been:
>
>       p[ybin*(X_BINS) + xbin] = '*';
>
> But now I get segmentation fault, so somewhere do I write over a
> limit...

That was lucky in that it lets you know the problem is probably in
this code.  You might want to check out valrind and mudflap.  I have
found both to be very useful.

Lets look at the code you corrected (edited down):

memset(p, ' ', X_BINS * Y_BINS);

/* check if a data point should be inserted, and in such case where */
int i = 0;
int ybin, xbin;
for (i=0; i<n; i++) {
if (x[i] >= start_x && x[i] <= slut_x &&
y[i] >= start_y && y[i] <= slut_y) {

/* where to put x */
xbin = (int) round( (x[i] - start_x)/(slut_x - start_x)*X_BINS );
/* where to put y */
ybin = (int) round( (y[i] - start_y)/(slut_y - start_y)*Y_BINS );

p[ybin*(X_BINS) + xbin] = '*';
}
}

Check your boundary conditions.  x[i] can == start_x.  This makes xbin
== 0 and that is OK.  x[i] can be as large as slut_x and this makes

(x[i] - start_x)/(slut_x - start_x)

exactly 1.  Multiplying by X_BINS makes xbin == X_BINS and it must
range from 0 to X_BINS-1.  The same problem occurs for ybin.  Exactly
how you should solve this depends on exactly what you want to happen
at the boundaries.  One option would be to remove the "if" and scale
every point but then reject those whose scaled int value is < 0 or >=
X_BINS.  This relies on the scaled values being in the range of int
in all cases.  Alternatively you could just protect the assignment with
a test xbin and ybin are both < X_BINS and Y_BINS respectively.

There are lots of other fixes, but the key is to ensure that the
scaled result is exactly in range.  This is not helped bu the fact
that you are rounding the result.  Sketch out on a grid exactly what
you want to happen at the edges.

--
Ben.
```
 0
Reply ben.usenet (6790) 12/16/2008 12:54:00 AM

22 Replies
37 Views

Similar Articles

12/7/2013 1:01:55 AM
[PageSpeed]