Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #24852 > unrolled thread

2D arrays, pointers, and pointer arithmetic: question

Started bygdotone@gmail.com
First post2012-08-24 08:28 -0700
Last post2012-09-07 06:28 -0700
Articles 13 on this page of 33 — 17 participants

Back to article view | Back to comp.lang.c


Contents

  2D arrays, pointers, and pointer arithmetic: question gdotone@gmail.com - 2012-08-24 08:28 -0700
    Re: 2D arrays, pointers, and pointer arithmetic: question Adrian Ratnapala <adrian.ratnapala@gmail.com> - 2012-08-24 08:41 -0700
    Re: 2D arrays, pointers, and pointer arithmetic: question James Kuyper <jameskuyper@verizon.net> - 2012-08-24 12:01 -0400
      Re: 2D arrays, pointers, and pointer arithmetic: question 88888 Dihedral <dihedral88888@googlemail.com> - 2012-08-24 11:10 -0700
    Re: 2D arrays, pointers, and pointer arithmetic: question gdotone@gmail.com - 2012-08-27 13:35 -0700
      Re: 2D arrays, pointers, and pointer arithmetic: question James Kuyper <jameskuyper@verizon.net> - 2012-08-27 16:46 -0400
        Re: 2D arrays, pointers, and pointer arithmetic: question Adrian Ratnapala <raka@scooter.fritz.box> - 2012-08-28 19:06 +0000
          Re: 2D arrays, pointers, and pointer arithmetic: question Eric Sosman <esosman@ieee-dot-org.invalid> - 2012-08-28 15:22 -0400
          Re: 2D arrays, pointers, and pointer arithmetic: question James Kuyper <jameskuyper@verizon.net> - 2012-08-28 15:34 -0400
            Re: 2D arrays, pointers, and pointer arithmetic: question Keith Thompson <kst-u@mib.org> - 2012-08-28 14:11 -0700
              Re: 2D arrays, pointers, and pointer arithmetic: question James Kuyper <jameskuyper@verizon.net> - 2012-08-28 17:26 -0400
              Re: 2D arrays, pointers, and pointer arithmetic: question "io_x" <a@b.c.invalid> - 2012-08-29 09:25 +0200
            Re: 2D arrays, pointers, and pointer arithmetic: question Adrian Ratnapala <raka@scooter.fritz.box> - 2012-08-29 07:20 +0000
              Re: 2D arrays, pointers, and pointer arithmetic: question James Kuyper <jameskuyper@verizon.net> - 2012-08-29 07:17 -0400
                Re: 2D arrays, pointers, and pointer arithmetic: question Adrian Ratnapala <raka@scooter.fritz.box> - 2012-08-29 11:41 +0000
              Re: 2D arrays, pointers, and pointer arithmetic: question Eric Sosman <esosman@ieee-dot-org.invalid> - 2012-08-29 08:21 -0400
                Re: 2D arrays, pointers, and pointer arithmetic: question Keith Thompson <kst-u@mib.org> - 2012-08-29 11:37 -0700
                  Re: 2D arrays, pointers, and pointer arithmetic: question Edward Rutherford <edward.p.rutherford79@REMOVETHIS.gmail.com> - 2012-08-29 20:05 +0000
                    Re: 2D arrays, pointers, and pointer arithmetic: question James Kuyper <jameskuyper@verizon.net> - 2012-08-29 17:27 -0400
                    Re: 2D arrays, pointers, and pointer arithmetic: question Keith Thompson <kst-u@mib.org> - 2012-08-29 18:05 -0700
                      Re: 2D arrays, pointers, and pointer arithmetic: question Les Cargill <lcargill99@comcast.com> - 2012-08-29 20:14 -0500
                        Re: 2D arrays, pointers, and pointer arithmetic: question Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-08-30 04:47 -0700
                          Re: 2D arrays, pointers, and pointer arithmetic: question Richard Damon <news.x.richarddamon@xoxy.net> - 2012-09-01 23:47 -0400
                            Re: 2D arrays, pointers, and pointer arithmetic: question 88888 Dihedral <dihedral88888@googlemail.com> - 2012-09-02 04:43 -0700
                              Re: 2D arrays, pointers, and pointer arithmetic: question Richard Damon <news.x.richarddamon@xoxy.net> - 2012-09-02 23:12 -0400
                      Re: 2D arrays, pointers, and pointer arithmetic: question ais523 <ais523@nethack4.org> - 2012-08-30 11:35 +0000
                  Re: 2D arrays, pointers, and pointer arithmetic: question ralph <nt_consulting64@yahoo.com> - 2012-08-30 11:17 -0500
                    Re: 2D arrays, pointers, and pointer arithmetic: question Keith Thompson <kst-u@mib.org> - 2012-08-30 13:52 -0700
                      Re: 2D arrays, pointers, and pointer arithmetic: question Anders Wegge Keller <wegge@wegge.dk> - 2012-08-30 23:13 +0200
                      Re: 2D arrays, pointers, and pointer arithmetic: question ralph <nt_consulting64@yahoo.com> - 2012-08-31 16:37 -0500
      Re: 2D arrays, pointers, and pointer arithmetic: question Barry Schwarz <schwarzb@dqel.com> - 2012-08-27 19:45 -0700
        Re: 2D arrays, pointers, and pointer arithmetic: question Keith Thompson <kst-u@mib.org> - 2012-08-27 20:40 -0700
          Re: 2D arrays, pointers, and pointer arithmetic: question Tim Rentsch <txr@alumni.caltech.edu> - 2012-09-07 06:28 -0700

Page 2 of 2 — ← Prev page 1 [2]


#25474

FromLes Cargill <lcargill99@comcast.com>
Date2012-08-29 20:14 -0500
Message-ID<k1mefd$e60$3@dont-email.me>
In reply to#25471
Keith Thompson wrote:
> Edward Rutherford <edward.p.rutherford79@REMOVETHIS.gmail.com> writes:
>> Keith Thompson wrote:
>>> `near` and `far`, which are of course non-standard, can result in
>>> different pointer types having different sizes.  Passing a `near` or
>>> `far` pointer to printf with a "%p" format is likely to give bad results
>>> in practice.
>>
>> Using near or far pointers in any way at all will invoke an undefined
>> behavior, so I think it's safe to say bad results are likely with or
>> without attempts to printf() such pointers!
>
> For a C implementation that supports `near`, `far`, `void*`, and
> printf's "%p" format, I would expect that casting a `near` or `far`
> pointer value to `void*` before passing it to printf would work
> "correctly".  Of course the standard doesn't guarantee that, but I'd
> expect it of any decent C or C-like implementation.
>
> (I've never used `near` or `far` myself.  It's plausible that an
> implementation old enough to support them would be too old to support
> `void*`.)
>


The C89 flavors of MSC supported both "void*" and "near"/"far". TINY 
MODEL FTW!

--
Les Cargill

[toc] | [prev] | [next] | [standalone]


#25524

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2012-08-30 04:47 -0700
Message-ID<01b58c31-8d92-4ebe-80aa-cb6f8d7c52db@googlegroups.com>
In reply to#25474
בתאריך יום חמישי, 30 באוגוסט 2012 02:09:02 UTC+1, מאת Les Cargill:
> Keith Thompson wrote:
> 
> The C89 flavors of MSC supported both "void*" and "near"/"far". TINY 
> MODEL FTW!
> 
The idea of the "models" was that you could write program without the
near/far non-standard extensions. Under "huge", if I remember rightly, 
all pointers were 32 bit and it did some inefficient magic to hide the
segments and give you what looked like flat memory. Under "large", 
pointers were 32 bits but you couldn't allocate a block of more than
64 K.
Under "tiny" all code and data had to fit within the same 64K segment,
which led to the most efficient machine code. But you could use far
pointers to allocate data in other segments. So you ended up rewriting
fucntions like "farmemcpy", because the standard library only worked 
with the standard pointers.



[toc] | [prev] | [next] | [standalone]


#25718

FromRichard Damon <news.x.richarddamon@xoxy.net>
Date2012-09-01 23:47 -0400
Message-ID<k1uksa$b2g$1@dont-email.me>
In reply to#25524
On 8/30/12 7:47 AM, Malcolm McLean wrote:
> בתאריך יום חמישי, 30 באוגוסט 2012 02:09:02 UTC+1, מאת Les Cargill:
>> Keith Thompson wrote:
>>
>> The C89 flavors of MSC supported both "void*" and "near"/"far". TINY 
>> MODEL FTW!
>>
> The idea of the "models" was that you could write program without the
> near/far non-standard extensions. Under "huge", if I remember rightly, 
> all pointers were 32 bit and it did some inefficient magic to hide the
> segments and give you what looked like flat memory. Under "large", 
> pointers were 32 bits but you couldn't allocate a block of more than
> 64 K.
> Under "tiny" all code and data had to fit within the same 64K segment,
> which led to the most efficient machine code. But you could use far
> pointers to allocate data in other segments. So you ended up rewriting
> fucntions like "farmemcpy", because the standard library only worked 
> with the standard pointers.
> 
> 
> 
> 

The models came about due to the memory structure of the 16 bit x86
architecture. Addresses were in general greater than 16 bits in length,
while address registers were only 16 bits long, and were combined with a
"segment register" to convert the value to a full address. (depending on
what mode the processor was in would change how the conversion was done).

Near pointers only stored the value of the address register, and the
segment register was assumed by the type of pointer (the Data Segment
Register for "data" pointers, and the Program Segment Register for
function pointers). In addition, data pointers had a huge type, which
was like a far pointer, but could point to an object that might be
bigger than a single segment, and the compiler would need to do
additional work on address arithmetic to handle this. It mostly was used
in "Real" mode, where the Segment register was just added to the address
register after shifting up the Segment register 4 bits (giving a 20 bit
final memory address).

The program model determined what were the default sizes for each type
of pointer.

Model  Data Code
Tiny   near near
Small  near near
Medium near far
Compact far near
Large  far  far
Huge   huge far

The difference between Tiny and Small was that in Tiny, the code and
data were in the same segment, while in Small they were in distinct
segments.

It was by far more common to have near/far pointers in code that had a
default near size of pointers, to handle a limited number of
objects/functions that would be placed outside the default near block to
make room for them, sometimes to access things outside the current program.

Note also that the 32 bit x86 family of processors still have these
memory models (and 48 bit "far" pointers), they are just mostly ignored
and most programs are just done in the Tiny or Small model, after all
who should need more than 4GB of address space ;) The resurgence of
memory models for programs was headed off (for now at least) with the
introduction of 64 bit processors.

[toc] | [prev] | [next] | [standalone]


#25750

From88888 Dihedral <dihedral88888@googlemail.com>
Date2012-09-02 04:43 -0700
Message-ID<b7724e03-0f38-4d3e-94b7-ca549a1961ac@googlegroups.com>
In reply to#25718
On Sunday, September 2, 2012 11:47:23 AM UTC+8, Richard Damon wrote:
> On 8/30/12 7:47 AM, Malcolm McLean wrote:
> 
> > בתאריך יום חמישי, 30 באוגוסט 2012 02:09:02 UTC+1, מאת Les Cargill:
> 
> >> Keith Thompson wrote:
> 
> >>
> 
> >> The C89 flavors of MSC supported both "void*" and "near"/"far". TINY 
> 
> >> MODEL FTW!
> 
> >>
> 
> > The idea of the "models" was that you could write program without the
> 
> > near/far non-standard extensions. Under "huge", if I remember rightly, 
> 
> > all pointers were 32 bit and it did some inefficient magic to hide the
> 
> > segments and give you what looked like flat memory. Under "large", 
> 
> > pointers were 32 bits but you couldn't allocate a block of more than
> 
> > 64 K.
> 
> > Under "tiny" all code and data had to fit within the same 64K segment,
> 
> > which led to the most efficient machine code. But you could use far
> 
> > pointers to allocate data in other segments. So you ended up rewriting
> 
> > fucntions like "farmemcpy", because the standard library only worked 
> 
> > with the standard pointers.
> 
> > 
> 
> > 
> 
> > 
> 
> > 
> 
> 
> 
> The models came about due to the memory structure of the 16 bit x86
> 
> architecture. Addresses were in general greater than 16 bits in length,
> 
> while address registers were only 16 bits long, and were combined with a
> 
> "segment register" to convert the value to a full address. (depending on
> 
> what mode the processor was in would change how the conversion was done).
> 
> 
> 
> Near pointers only stored the value of the address register, and the
> 
> segment register was assumed by the type of pointer (the Data Segment
> 
> Register for "data" pointers, and the Program Segment Register for
> 
> function pointers). In addition, data pointers had a huge type, which
> 
> was like a far pointer, but could point to an object that might be
> 
> bigger than a single segment, and the compiler would need to do
> 
> additional work on address arithmetic to handle this. It mostly was used
> 
> in "Real" mode, where the Segment register was just added to the address
> 
> register after shifting up the Segment register 4 bits (giving a 20 bit
> 
> final memory address).
> 
> 
> 
> The program model determined what were the default sizes for each type
> 
> of pointer.
> 
> 
> 
> Model  Data Code
> 
> Tiny   near near
> 
> Small  near near
> 
> Medium near far
> 
> Compact far near
> 
> Large  far  far
> 
> Huge   huge far
> 
> 
> 
> The difference between Tiny and Small was that in Tiny, the code and
> 
> data were in the same segment, while in Small they were in distinct
> 
> segments.
> 
> 
> 
> It was by far more common to have near/far pointers in code that had a
> 
> default near size of pointers, to handle a limited number of
> 
> objects/functions that would be placed outside the default near block to
> 
> make room for them, sometimes to access things outside the current program.
> 
> 
> 
> Note also that the 32 bit x86 family of processors still have these
> 
> memory models (and 48 bit "far" pointers), they are just mostly ignored
> 
> and most programs are just done in the Tiny or Small model, after all
> 
> who should need more than 4GB of address space ;) The resurgence of
> 
> memory models for programs was headed off (for now at least) with the
> 
> introduction of 64 bit processors.

These are old tricks. Now there are 4 to 8 core cpus in the tablet computers,
or note book computers running Androids( LINUX+JAVA by a new name for marketing).

How to support the multi-core part in C is still not addressed very well?


[toc] | [prev] | [next] | [standalone]


#25797

FromRichard Damon <news.x.richarddamon@xoxy.net>
Date2012-09-02 23:12 -0400
Message-ID<k2177i$e3h$1@dont-email.me>
In reply to#25750
On 9/2/12 7:43 AM, 88888 Dihedral wrote:
> 
> How to support the multi-core part in C is still not addressed very well?
> 
> 
> 

Until the latest standard came out, "ISO Standard C" had no concept of
"threads", and without threads, the issues of a multi-core CPU are
irreverent. Any program that wanted to use threads had to rely on some
other standard of some sort to implement the threads and that standard
needed to define how to handle the various issues with multiple cores.

There is no inherent problem with this, most real programs actually are
going to depend on some standard beyond "ISO Standard C", if only the
documentation of the compiler, many times on something like POSIX or the
like.

With the new standardization of some basic thread supporting primitives
in ISO C, the capability to write more stuff in strictly conforming ISO
Standard C is available (once support becomes common), so perhaps some
programs that used to have a requirement on say POSIX, can now just
require C11 compliance, but most are still going to be dependent on
things beyond the ISO C standard.

I would suspect that in reality, most code for a program should be
fairly agnostic to the multi-core nature of the machine, as it should be
dealing with data that it currently "owns" and the interfaces that pass
data from one thread to another should deal with all the needed memory
barriers to make sure this "just works". It is only the sections that
need to deal with actually sending information between threads that
needs to worry about these aspects, and in most cases the threading
library will provide a "good enough" interface (if a bit heavy). It is
only the case where trying to improve efficiency that the applications
programmer is going to need to deal with these details, and in most
cases when dealing with improving efficiency, there is a tendency to
move into implementation defined/specific characteristics anyway (how
expensive things are tends to be a function of the implementation).

[toc] | [prev] | [next] | [standalone]


#25522

Fromais523 <ais523@nethack4.org>
Date2012-08-30 11:35 +0000
Message-ID<k1nj65$t03$1@dont-email.me>
In reply to#25471
Keith Thompson wrote:
> (I've never used `near` or `far` myself.  It's plausible that an
> implementation old enough to support them would be too old to support
> `void*`.)

16-bit versions of Borland C for Windows supported void* just fine
(we're talking well after 1989; they ran under Windows 95 to be able to
compile programs that would run under the still-then-in-use Windows
3.1), but also supported near and far because they existed on that
platform.

The fix used for standards compliance was to have compiler options to
specify whether function pointers were near/far if not specified, and
whether non-function pointers were near/far if not specified. (This
means, among other things, that it was not necessarily possible to
convert a void(*)() to a void* and back again, which makes for a nice
counterexample to give to people who think it is possible.) The system
headers marked every pointer with near or far in order to make them
conform to the library ABI, and implicit casts were added to the
language avoid this causing trouble.

There was actually a third option, huge, which could cope with objects
larger than one segment (by performing extra arithmetic upon segment
overflow), and was otherwise like far. (And was rarely used, because
objects that large were not so useful back then due to limited memory.)
I also remember the system-specific library function farmalloc(), which
was like malloc but which gave you a far pointer; very useful for
storing large amounts of data long-term in a program which otherwise
could do with near pointers for data.

-- 
ais523

[toc] | [prev] | [next] | [standalone]


#25546

Fromralph <nt_consulting64@yahoo.com>
Date2012-08-30 11:17 -0500
Message-ID<8g2v38tk3bvtgmctvq9mtd4j13u0cu2ugs@4ax.com>
In reply to#25414
On Wed, 29 Aug 2012 11:37:02 -0700, Keith Thompson <kst-u@mib.org>
wrote:

>Eric Sosman <esosman@ieee-dot-org.invalid> writes:
>> On 8/29/2012 3:20 AM, Adrian Ratnapala wrote:
>>> [... about converting int* to void* for "%p" conversion ...]
>>> BTW: I don't know if my misconception is "frequent" enough to warrant an
>>> FAQ change, but it doesn't look like the FAQ covers this.  Contra Eric,
>>> 5.17 is about something else;  4.17 / 19.40 are closer but not quite
>>> relevant.
>>
>>      5.17 is mostly about representations of null pointers, but
>> not entirely.  If you'll read the entire thing, you'll find two
>> specific mentions of different pointer formats, plus a link to
>> further examples.
>>
>>      14.17 and 19.40(d) are about `near' and `far', whose
>> connection to the matter at hand eludes me.
>
>`near` and `far`, which are of course non-standard, can result in
>different pointer types having different sizes.  Passing a `near`
>or `far` pointer to printf with a "%p" format is likely to give
>bad results in practice.

Actually in practice it was never an issue. 

Because of how the different models were implemented a different CRT
or "standard C Library" was always employed, thus each encountered a
"printf()" fully able to managed whatever "%p" formatted argument it
received.

-ralph

[toc] | [prev] | [next] | [standalone]


#25572

FromKeith Thompson <kst-u@mib.org>
Date2012-08-30 13:52 -0700
Message-ID<lnipc0umq1.fsf@nuthaus.mib.org>
In reply to#25546
ralph <nt_consulting64@yahoo.com> writes:
> On Wed, 29 Aug 2012 11:37:02 -0700, Keith Thompson <kst-u@mib.org>
> wrote:
[...]
>>`near` and `far`, which are of course non-standard, can result in
>>different pointer types having different sizes.  Passing a `near`
>>or `far` pointer to printf with a "%p" format is likely to give
>>bad results in practice.
>
> Actually in practice it was never an issue. 
>
> Because of how the different models were implemented a different CRT
> or "standard C Library" was always employed, thus each encountered a
> "printf()" fully able to managed whatever "%p" formatted argument it
> received.

Wasn't it possible to have both near and far pointers, with different
sizes, in the same program?

For example:

    char near *nearp = ...;
    char far *farp = ...;
    printf("nearp = %p, farp = %p\n", nearp, farp);

Maybe that wasn't a common thing to do, but wouldn't it cause problems?

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#25577

FromAnders Wegge Keller <wegge@wegge.dk>
Date2012-08-30 23:13 +0200
Message-ID<87pq68hymr.fsf@huddi.jernurt.dk>
In reply to#25572
Keith Thompson <kst-u@mib.org> writes:

> Wasn't it possible to have both near and far pointers, with
> different sizes, in the same program?

 It is. The 80186 compiler I use at work calls this "Mixed mode".
 
> For example:
> 
>     char near *nearp = ...;
>     char far *farp = ...;
>     printf("nearp = %p, farp = %p\n", nearp, farp);
> 
> Maybe that wasn't a common thing to do, but wouldn't it cause problems?

 One should think that this would give a funny-looking result for the
near pointer. But I've never had to log pointer values on that
platform, so I cannot say for sure what would happen.
 
-- 
/Wegge

Leder efter redundant peering af dk.*,linux.debian.*

[toc] | [prev] | [next] | [standalone]


#25675

Fromralph <nt_consulting64@yahoo.com>
Date2012-08-31 16:37 -0500
Message-ID<7m42485p88d735n2rt05jet2qjej1rbkb1@4ax.com>
In reply to#25572
On Thu, 30 Aug 2012 13:52:06 -0700, Keith Thompson <kst-u@mib.org>
wrote:

>ralph <nt_consulting64@yahoo.com> writes:
>> On Wed, 29 Aug 2012 11:37:02 -0700, Keith Thompson <kst-u@mib.org>
>> wrote:
>[...]
>>>`near` and `far`, which are of course non-standard, can result in
>>>different pointer types having different sizes.  Passing a `near`
>>>or `far` pointer to printf with a "%p" format is likely to give
>>>bad results in practice.
>>
>> Actually in practice it was never an issue. 
>>
>> Because of how the different models were implemented a different CRT
>> or "standard C Library" was always employed, thus each encountered a
>> "printf()" fully able to managed whatever "%p" formatted argument it
>> received.
>
>Wasn't it possible to have both near and far pointers, with different
>sizes, in the same program?
>
>For example:
>
>    char near *nearp = ...;
>    char far *farp = ...;
>    printf("nearp = %p, farp = %p\n", nearp, farp); 
>
>Maybe that wasn't a common thing to do, but wouldn't it cause problems?

Not in "common practice" since the keywords "far" and "near" were
themselves implementaton and conditionally defined. ie, "far" was
actually a defined macro "__far"*.

It was essentially difficult to create 'near' and 'far' pointers in
the same translation unit without going out of your way to contrive
something.

    char near *nearp = ...;
    char far *farp = ...;

I would expect the above to silent or deliver a strong Warning or even
Error, depending on model being compiled.

Of course we are talking about more than a vendor extension to the
language. Microsoft besides simply providing two different sized
pointer declarations also did thunking and other redefinitions behind
the scenes. (Both the preprocessor and linker were very busy little
beavers. <g>) For example, 'near' pointers magically became 'far'
pointers when calling something in a 'WinAPI' shared library. Well not
too much magic. They basically just prefixed the current defaut
segment to the near address. Hard to say what else might have been
going on. Can't remember all of it.

Do remember that it 'just worked'. <g>
 
-ralph
[__far* Originally it was "_far", one under-score. Later it become
"__far" to be ANSI compliant for vendor implementation defines. The
final definition was often buried in a stack of #defines. <g>]

[toc] | [prev] | [next] | [standalone]


#25171

FromBarry Schwarz <schwarzb@dqel.com>
Date2012-08-27 19:45 -0700
Message-ID<d8ao38l6qg6gsnrvhfecom6bc4cs6er9n9@4ax.com>
In reply to#25134
On Mon, 27 Aug 2012 13:35:35 -0700 (PDT), gdotone@gmail.com wrote:

snip

>I created a simple program, creating a 2X3 array and explored the address of the expressions, in piece and whole.
>
>#include <stdio.h>
>#include <stdlib.h>
>
>#define SPACE_BETWEEN_LINES "\n\n"
>
>int main(void)
>{
>   int a[2][3];
>   int i,j;
>
>   printf ( SPACE_BETWEEN_LINES );
>
>   for ( i = 0; i < 2; i++ )
>      for ( j = 0; j < 3; j++ )
>         a[i][j] = 0;

10*i+j might have been a better value so when you print any element of
the array you can tell it is the correct one.
   
snip

>   printf ( "The value at *(a+0) is %d\n", **(a+0) ); /*   *(*(a+0))    */

*(a+0) is by definition the same as a[0].  a[0] is an array of 3 int.
It doesn't make sense to talk about a single value for such an array.

**(a+0) is same as a[0][0] (from recursive application of the above
definition).  a[0][0] is the single int you print.  But it is not the
value of a[0].

>
>   printf ( "\n" ); 
>
>   return 1;

This is a non-portable return value from main.  Usually successful
completion returns 0.  If you really wanted a non-zero value,
EXIT_FAILURE is portable and always non-zero.

>}
>
>Output:
>
>
>The address for a[0][0] is   0x7fff67ca8bf0
>The address for a[0][1] is   0x7fff67ca8bf4
>The address for a[0][2] is   0x7fff67ca8bf8
>The address for a[1][0] is   0x7fff67ca8bfc
>The address for a[1][1] is   0x7fff67ca8c00
>The address for a[1][2] is   0x7fff67ca8c04
>
>
>The address for ((*(a + 0)) + 0) is  0x7fff67ca8bf0
>The address for ((*(a + 0)) + 1) is  0x7fff67ca8bf4
>The address for ((*(a + 0)) + 2) is  0x7fff67ca8bf8
>The address for ((*(a + 1)) + 0) is  0x7fff67ca8bfc
>The address for ((*(a + 1)) + 1) is  0x7fff67ca8c00
>The address for ((*(a + 1)) + 2) is  0x7fff67ca8c04
>
>
>The starting address of a is:     0x7fff67ca8bf0
>
>The second row starting address:  0x7fff67ca8bfc
>
>The a[1][0] address is :          0x7fff67ca8bfc
>
>
>
>*(a+0) address is:          0x7fff67ca8bf0
>
>*(a+0) + 1 address is:      0x7fff67ca8bf4
>The value at *(a+0) is 0
>
>Ok, *(a+0) returns and address, *(a+0) + 1 returns an address.
>
>So, given a[][], a two dimensional array, *(a+i) will return the address of the starting row, *(a+i) + j, returns the address of row,column, &a[i][j]. 

* is not a function so return is not the best term to use.  The
expression *(a+i) and its identical twin a[i] will, with a few
exceptions that don't apply here, both EVALUATE to the address of the
i-th row, not the starting row.  If you meant the start of row i, that
would be correct.

>The i term added to a is being added to the base address of the array and itself, i, representing the size of a row. j then adds to that address giving the column position.

When a pointer and an integer are added, the value of the integer is
scaled by the size of the object pointed to, or if you prefer, the
size of the object type pointed to.

     Given a pointer p to type T and an integer k, the C expression
          p + k
     is mathematically equivalent to
          p + k * sizeof(T) 
     or the synonymous
          p + k * sizeof *p

Furthermore, discounting the exceptions alluded to above, an
expression with array type is converted to the address of the first
array element with type pointer to element type.

     So, the expression 
          a
     is converted to &a[0] with type pointer to array of 3 int,
     syntactically written as int(*)[3].  Since sizeof(int) is 4 on
     your system, an array of 3 int has size 12.

Combining these two facts tells us that the expression a+i will
evaluate to the address i*12 bytes beyond the start of the array and
still have type pointer to array of 3 int.  The net effect is that a+i
evaluates to the address of the i-th row

The expression *(a+i) dereferences this pointer and the result is an
array of 3 int.  Consequently, this expression is also converted as
described above.  The result is the address of the first element of
the i-th row &a[i][0] with type pointer to int.  In other words,
&a[i][0].

Adding j to this expression will evaluate to the address j*4 bytes
beyond the start of the row and still have type pointer to int.  In
other words, &a[i][j].

-- 
Remove del for email

[toc] | [prev] | [next] | [standalone]


#25176

FromKeith Thompson <kst-u@mib.org>
Date2012-08-27 20:40 -0700
Message-ID<ln62831y7d.fsf@nuthaus.mib.org>
In reply to#25171
Barry Schwarz <schwarzb@dqel.com> writes:
> On Mon, 27 Aug 2012 13:35:35 -0700 (PDT), gdotone@gmail.com wrote:
[...]
> * is not a function so return is not the best term to use.  The
> expression *(a+i) and its identical twin a[i] will, with a few
> exceptions that don't apply here, both EVALUATE to the address of the
> i-th row, not the starting row.  If you meant the start of row i, that
> would be correct.

The usual term is "yield": functions return values, and expressions
yield values.

[...]

>>The i term added to a is being added to the base address of the array
>>and itself, i, representing the size of a row. j then adds to that
>>address giving the column position.
>
> When a pointer and an integer are added, the value of the integer is
> scaled by the size of the object pointed to, or if you prefer, the
> size of the object type pointed to.

Another way to look at it is that the value is *not* "scaled" by the
size of the object pointed to; rather, the addition yields a pointer
that points N *objects* past the object that the original pointer
points to.  (There has to be an array for this to make sense, possibly
the 1-element array that's equivalent to a single object.)

The standard's description doesn't talk about scaling (N1570 6.5.6p8):

    When an expression that has integer type is added to or
    subtracted from a pointer, the result has the type of the
    pointer operand. If the pointer operand points to an element
    of an array object, and the array is large enough, the result
    points to an element offset from the original element such that
    the difference of the subscripts of the resulting and original
    array elements equals the integer expression.  In other words, if
    the expression P points to the i -th element of an array object,
    the expressions (P)+N(equivalently, N+(P)) and (P)-N(where N
    has the valuen ) point to, respectively, the i+n-th and i−n-th
    elements of the array object, provided they exist.

Referring to addition being "scaled" implies that pointers are
*really* pointers to bytes.  That's likely true on the machine code
level, but it's not true in the C abstract machine; rather pointers
*really* point to whatever type they're defined to point to.

>      Given a pointer p to type T and an integer k, the C expression
>           p + k
>      is mathematically equivalent to
>           p + k * sizeof(T) 
>      or the synonymous
>           p + k * sizeof *p

I understand what you mean, but the fact that you're using "+"
with two very different meaning could be confusing.

[...]

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#26047

FromTim Rentsch <txr@alumni.caltech.edu>
Date2012-09-07 06:28 -0700
Message-ID<kfnipbqklmk.fsf@x-alumni2.alumni.caltech.edu>
In reply to#25176
Keith Thompson <kst-u@mib.org> writes:

> Barry Schwarz <schwarzb@dqel.com> writes:
>> On Mon, 27 Aug 2012 13:35:35 -0700 (PDT), gdotone@gmail.com wrote:
> [snip]
>
>>>The i term added to a is being added to the base address of the array
>>>and itself, i, representing the size of a row. j then adds to that
>>>address giving the column position.
>>
>> When a pointer and an integer are added, the value of the integer is
>> scaled by the size of the object pointed to, or if you prefer, the
>> size of the object type pointed to.
>
> Another way to look at it is that the value is *not* "scaled" by the
> size of the object pointed to; rather, the addition yields a pointer
> that points N *objects* past the object that the original pointer
> points to.  (There has to be an array for this to make sense, possibly
> the 1-element array that's equivalent to a single object.)
>
> The standard's description doesn't talk about scaling (N1570 6.5.6p8):
> [snip quoted paragraph]

But, talking about the [] array indexing operator, the Standard
does say in a footnote

    Then i is adjusted according to the type of x, which
    conceptually entails multiplying i by the size of the
    object to which the pointer points

I'm not arguing for or against either explanation;  I think both
have some support (as an explanation) in the Standard.

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.lang.c


csiph-web