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


Groups > comp.lang.c > #56958

Re: what is data type 'int *' ?

From Richard Heathfield <rjh@cpax.org.uk>
Newsgroups comp.lang.c
Subject Re: what is data type 'int *' ?
Date 2015-02-05 03:06 +0000
Organization go, ion artisan!
Message-ID <maumml$m0o$2@dont-email.me> (permalink)
References <mauauc$p5v$1@dont-email.me>

Show all headers | View raw


On 04/02/15 23:45, bilsch wrote:
 > > A Sams book on C programming

You want to be careful of those.

 > > has a program that demonstrates how pointers
 > > work, similar to the listing below.

Reading through that code, I see that they've chosen to demonstrate how
pointers work in the same way that a zoo-keeper might explain an
elephant by saying "those are the legs, that's the trunk, there are the
big ears, and it's grey". All true, but you don't really feel,
afterwards, that you've /understood/ the elephant. Why the rather odd
gait? Why the trunk? What, in short, is an elephant /for/?

Same with pointers. The code you show doesn't look like it'll be much
help in understanding them. Never fear! Help is here. After a few weeks
of interminable debate here in comp.lang.c, you should understand them
just fine.

 > > I'm using Ubuntu and GNU gcc
 > > compiler.

Excellent choices.

  > For the last two printf lines the gcc compiler gives the error:
 > >
 > > expects argument of type ‘int’, but argument 2 has type ‘int *’

Okay, we'll get there in due course.

 > >
 > > Presumably, the compiler used with the book does not produce this 
error.

Don't count on it. Book code is notorious for not working as well as it
should, not working at all, or sometimes not even compiling.

 > > My question is what format specifier (%i) should I use for
 > > type 'int *' ?  I dont know of a format specifier for type ‘int *’.

Ben covered this. There isn't one. Use %p for "pointer", and cast the
pointer to (void *), whatever its type (although beware of function
pointers). This is one of the EXTRAORDINARILY RARE times when you should
use a cast. If in doubt, NEVER cast, and then rely on comp.lang.c to
tell you when you should have done, until you learn what casting is for
and why you should hardly ever use it and why it is massively over-used
in the Real World and why this is a Bad Thing that will result in The
End Of All Things and We'll All Be Murdered In Our Beds. (Well, okay,
maybe not, but it's still not a good thing.)

 > >
 > > Also, if the compiler used with the book doesnt produce the error, 
why is
 > > gcc so finicky.

Finicky is good. Besides, you can't assume that book code is any good.
(Trust me, I know this.)


 > > /* pointer.c */
 > >
 > > #include <stdio.h>

Okay, so we're pulling in all kinds of useful information for the
compiler - function prototypes for a fair chunk of the standard library,
type synonyms, a few handy #defines...

 > >
 > > /*  declare and initialize variable of type int  */
 > > int var=1;

Good comment (despite the US spelling of "initialise"). This line
actually achieves no fewer than four things:

1) it's a declaration of var as an int;
2) it's a definition of var as a real live object;
3) it's an initialisation of var as having value 1;
4) it's a reminder to think at some point about code formatting. Don't
just adopt the layout style used by the book. Think it through and come
up with a style that suits your thinking. My own style seems to drive
other people nuts around here, but they tolerate it because they're Good
People...

The comment, as I said, is good. The following line is just rubbish.
What on earth is that object doing outside a function? Legal? Sure.
Sensible? Hell no!

 > > /*  declare a pointer to int  */
 > > int *ptr;

Not such a good comment. Complain to your author. This *is* indeed a
declaration of a pointer to int, but it is also a tentative definition.
Although you shouldn't worry too much about this at the moment, it is
something to bear in mind for the future. In the absence of any
subsequent (or indeed prior) non-tentative definitions, this will be the
definition of ptr. What's more, because it's at file scope, it has
static storage duration, and /that/ means that it will, in the absence
of explicit initialisation, take on the default static initialiser value
which, for pointers, is the null value - so it's like saying: int *ptr =
NULL;
Note that this is only true for objects with static storage duration. It
is not true for auto objects.
Note, too, that this object also belongs inside a function. The author
is trying to teach you bad habits, but you don't have to listen.

 > >
 > > int main()

Keith Thompson would argue that this is better:

int main(void)

If you want to know why, ask Keith. There is a point to it, but I can
never remember what it is, so it's probably not /that/ important, but
Keith may disagree on that, and he's a chap that decent chaps listen to
(even if they can't always remember exactly what he said!).

 > > {
 > >
 > > ptr=&var;

Okay, let's take this apart a bit. Firstly, let's put in some SPACE!

    ptr = &var;

Spacing doesn't define precedence, but it can help to clarify our intent.

The first thing to notice is that this is an assignment statement, not
an initialisation. Initialisation happens when you define an object
*and* give it a value, all in the same line of code. It's a terminology
thing, but it's good to get the terminology straight at an early stage.

Secondly, the types on either side of an assignment statement must
match. They need not always be exactly the same type, but the types must
be "compatible". In this case, there is no problem matching the types,
as we shall see.

&var means: "var is an object whose address I can legally access". You
can legally take the address of most objects. One obvious exception is
objects that you have asked to be stored in registers, which doesn't
apply here. Since "var" is of type "int", "&var" has type "int *". That
is, &var is a pointer to an int.

Since ptr also has the type "pointer to int", there is no problem
assigning the value "&var" to the object named "ptr". (There *is* a
problem doing it the other way around, because you can't change an
object's address via assignment: &var = ptr; is not legal.)

Now, before we go any further, let's try to find out how this elephant
ticks, and what it's actually for.

C is a "pass-by-value" language. Whenever we try to pass anything to a
function, it is the /value/ of the thing that is passed. In this case,
var has the value 1, so an attempt to pass var to a function will
actually have the effect of passing the value 1 to that function. The
function will never know about var itself. Any change to the value
passed will have no effect whatsoever on var.

<WARNING: analogy ahead. Analogies are illustrative, but they are not
allegories, and there is not a 100% match between analogy and reality>

Passing an object to a function in C is like giving a photograph of your
house to an arsonist. He can burn the photograph all he likes, but your
house will remain standing. And, since one house looks pretty much like
another, he can't use the information in the photograph to get to your
actual house, so he still can't burn it down.

But we can get around this apparent limitation by sending the address of
the object instead. To continue the analogy, imagine writing your house
address on a piece of paper. Take a photograph of the piece of paper,
and hand the photograph to the arsonist. Well, a photograph of a
hand-written address is just as useful as the original, right? So now
the arsonist can find your home, and now he can burn it down. Or maybe
he can mow your lawn, if he's in a good mood. A photo of an ADDRESS is
just as good as the original address.

And that's the principal reason (although not the only one) that
pointers are useful - they allow us to pass enough information about an
object into a function such that the function can change the value of
the object itself, not just the value of a copy of that object.

Pass-by-value with values:

#include <stdio.h>

void change(int foo)
{
    foo = 6;
}
int main(void)
{
    int bar = 0;
    printf("bar: prior value = %d\n", bar);
    change(bar);
    printf("bar: new value = %d\n", bar);
    return 0;
}

Output:
bar: prior value = 0
bar: new value = 0

Pointer version:

#include <stdio.h>

void change(int *foo)
{
    *foo = 6;
}
int main(void)
{
    int bar = 0;
    printf("bar: prior value = %d\n", bar);
    change(&bar);
    printf("bar: new value = %d\n", bar);
    return 0;
}

Output:
bar: prior value = 0
bar: new value = 6


 > >
 > > /*  access directly and indirectly  */
 > >
 > > printf("\ndirect access var= %i",var);

Yes, %i will do instead of %d here. But what a stupid place for a
newline! Not your fault - the author's fault. The \n should go at the
end of the format string. A \n should be used to indicate the end of a
line, not the beginning. And this isn't just pickiness. C specifies that
a newline is one of those points at which standard output is 'flushed',
meaning it is definitely sent to the output device and not just sitting
in a cache somewhere. So it's a good idea to put it at the end of the
line, not the beginning.

Note, too, the rather inconsistent use of spacing. Better:

printf("direct access var = %i\n", var);

Now, let's actually look at what is happening here.

printf is a function, like any other (all right, not /quite/ like any
other, because the way it's prototyped is a bit strange; but it's still
just a function). And, like most functions, it takes parameters.

Argument: something you pass to a function
Parameter: something a function receives

Here, we pass printf two arguments. They are:

"direct access var = %i\n"

and

var

in that lexical order.

C now *evaluates* these arguments.

The string "direct access var = %i\n" is in fact an array of characters.
When you evaluate an array, what you get (in C, at least!) is a pointer
to the first element in that array. That's enough information for printf
to be able to find the rest of the array, and it knows when to stop
because C strings are null-terminated ('\0' at the end, automatically
inserted into 'string literals' like this one, in almost all cases, and
the only exception is one that you shouldn't have to worry about for now).

var is evaluated as 1.

So what the compiler sends to printf is actually the address of the 'd'
of "direct access var = %i\n", and a 1.

The printf function uses your first argument (its first parameter) to
work out how much more information you are (claiming to be) sending to
it. The % is the giveaway. % means "heads-up, something happening here".
(That is why you have to be wary when your program outputs percentages.
To tell printf to print a % sign, you have to write %% rather than just
% on its own.)

The character(s) following the % sign tell printf what to do. %i means
"print an int", so printf looks in its parameter list for the next
parameter, treats it as an int, and displays the value on stdout, the
standard output device, normally your screen. And that's why printf
prints 1.

Interestingly, if you forget to send it var as well (and we've all done
it), printf won't care. It'll grab what it /thinks/ is the next
parameter (which in practice will be some random gobs of RAM), and print
/that/ as an int. Fortunately, many compilers are wise to this nowadays,
and will squeal at you at compilation time.

 > > printf("\nindirect access var= %i",*ptr);

Apart from the terrible formatting, this line is fine. The string is
evaluated as before. *ptr is evaluated as: "the value of the object
pointed to by ptr". Since ptr points to var (i.e. holds the address of
var), *ptr means in this case "the value of var", i.e. 1. And so printf
actually receives 1 as its second parameter. It doesn't know anything at
all about ptr.

 > >
 > > /*  display the address of var two ways   */

What the author didn't tell you is that both these ways are wrong.

 > > printf("\nthe address of var is %i\n",ptr);
 > > printf("\nthe address of var is %i\n",&var);

ptr has type int *, but %i tells printf to expect an int.

In many cases, ptr and int have the same size (in bits), so printf
doesn't necessarily know or care that there's a problem here. But *we*
should care, because int * is not int, and int is not int *.

To print a pointer value, use %p. Since there are infinitely many
pointer types (for certain values of "infinitely"), it would be
impractical to have a different format specifier for every pointer type.
So the printf function offers just one (two if you count %s, which is
rather different in semantics): %p for void *.

In general, void * is a synonym for "any old object pointer type". But,
where variadic functions are concerned, it pays to be careful because
printf doesn't know in advance that you're sending a void * as your
second argument. In fact, the first and second times you called it, you
passed an int, not a void *. In other words, the type can change from
call to call. So printf can't tell until runtime what type to expect. So
it can't define its own parameter list in terms of void *, and that
means you can't expect an automatic conversion, so you have to supply
one explicitly, by means of a cast: (void *)ptr - hence we get:

printf("\nthe address of var is %p\n", (void *)ptr);
printf("\nthe address of var is %p\n", (void *)&var);

And there we have it.

I *hope* I have unpacked your question in sufficient detail that you can
now actually understand what is going on. But, if I haven't, please do
feel free to ask follow-up questions.


-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within

Back to comp.lang.c | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

what is data type 'int  *' ? bilsch <king621@comcast.net> - 2015-02-04 23:45 +0000
  Re: what is data type 'int  *' ? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-02-05 00:09 +0000
    Re: what is data type 'int  *' ? glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-02-05 01:24 +0000
      Re: what is data type 'int  *' ? James Kuyper <jameskuyper@verizon.net> - 2015-02-05 07:00 -0500
        Re: what is data type 'int  *' ? glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-02-05 14:09 +0000
          Re: what is data type 'int  *' ? Robert Wessel <robertwessel2@yahoo.com> - 2015-02-05 13:08 -0600
            Re: what is data type 'int  *' ? glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-02-06 00:33 +0000
              Re: what is data type 'int  *' ? Robert Wessel <robertwessel2@yahoo.com> - 2015-02-05 19:30 -0600
                Re: what is data type 'int  *' ? glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-02-06 10:17 +0000
                Re: what is data type 'int  *' ? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-02-07 13:21 -0800
  Re: what is data type 'int  *' ? Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2015-02-04 19:47 -0500
    Re: what is data type 'int  *' ? bilsch <king621@comcast.net> - 2015-02-05 09:40 +0000
      Re: what is data type 'int  *' ? Richard Heathfield <rjh@cpax.org.uk> - 2015-02-05 09:51 +0000
    Re: what is data type 'int  *' ? Keith Thompson <kst-u@mib.org> - 2015-02-05 08:04 -0800
      Re: what is data type 'int  *' ? glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-02-06 00:42 +0000
        Re: what is data type 'int  *' ? Keith Thompson <kst-u@mib.org> - 2015-02-05 19:09 -0800
  Re: what is data type 'int  *' ? Kaz Kylheku <kaz@kylheku.com> - 2015-02-05 01:17 +0000
  Re: what is data type 'int  *' ? Richard Heathfield <rjh@cpax.org.uk> - 2015-02-05 03:04 +0000
    Re: what is data type 'int  *' ? Richard Heathfield <rjh@cpax.org.uk> - 2015-02-05 03:06 +0000
  Re: what is data type 'int  *' ? Richard Heathfield <rjh@cpax.org.uk> - 2015-02-05 03:06 +0000
    Re: what is data type 'int  *' ? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-02-05 10:20 +0000
      Re: what is data type 'int  *' ? Richard Heathfield <rjh@cpax.org.uk> - 2015-02-05 10:47 +0000
        Re: what is data type 'int  *' ? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-02-05 12:18 +0000
          Re: what is data type 'int  *' ? Richard Heathfield <rjh@cpax.org.uk> - 2015-02-05 12:40 +0000
      Re: what is data type 'int  *' ? Keith Thompson <kst-u@mib.org> - 2015-02-05 08:24 -0800
        Re: what is data type 'int  *' ? James Kuyper <jameskuyper@verizon.net> - 2015-02-05 11:42 -0500
        Re: what is data type 'int  *' ? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-02-05 17:13 +0000
    Re: what is data type 'int  *' ? Keith Thompson <kst-u@mib.org> - 2015-02-05 08:43 -0800
  Re: what is data type 'int  *' ? bilsch <king621@comcast.net> - 2015-02-05 09:45 +0000
  THANKS FOR THE INFO bilsch <king621@comcast.net> - 2015-02-05 09:47 +0000

csiph-web