Amiga-Development

Please login or register.

Login with username, password and session length
Advanced search  

News:

Created for developers of all Amiga camps

Author Topic: C Chapter 3: Pointer variables  (Read 2992 times)

0 Members and 1 Guest are viewing this topic.

SamuraiCrow

  • Administrator
  • Sr. Member
  • *****
  • Gender: Male
  • Posts: 372
  • Coolness is compiled
    • View Profile
C Chapter 3: Pointer variables
« on: April 26, 2016, 04:40:51 PM »

Welcome again to Chapter 3 to the tutorial that is increasingly leaning toward the title "Navigating the Warts of C Programming".  Today's issue is pointer variables.

There are several operators that define and indicate pointer operations.  Some of them are the address-of operator (notated by the unary ampersand: & ), the pointer traversal (indicated by the 2 character arrow:  -> ), the pointer dereference (indicated by the unary asterisk: * ), and the pointer definition (also indicated by the unary asterisk in another context: * ).

Let's start by allocating a pointer.  There are a number of valid ways to do that according to the 1989 ANSI/ISO standard:
  • *int varname;
  • int varname[];
  • int *varname;
  These indicate the same thing according to the standard:  a variable containing a pointer that points to an integer.

Let's discuss the first one.  Putting a unary asterisk in front of the int type is supposed to make the list of comma-separated variable names following it all pointers to the integer.  It is the rarest format and unfortunately, is so rare that many compilers didn't notice they were not supporting this part of the standard until their compilers had been in production for years!

Now for the second one.  The empty square-brackets at the end of the variable name indicate an unbounded-array.  In other words, it is a pointer to integers extending to infinity in the positive direction.  Let's call this an invitation to overrun buffers and although it just makes a pointer to an int, it is inconsistent with the purpose of a pointer to point to an item.  Avoid this syntax also.

Finally, this is a pointer definition attached to the variable definition.  This is the most common syntax.  Use it in good health.  Note that since the type is listed by itself, both integer variables and pointers to integers can be mixed together in one like of code.  It is the most flexible, most streamlined and most confusing syntax I've known in the C language... covered so far, anyway.   :P

To be continued.
Logged

SamuraiCrow

  • Administrator
  • Sr. Member
  • *****
  • Gender: Male
  • Posts: 372
  • Coolness is compiled
    • View Profile
Re: C Chapter 3: Pointer variables
« Reply #1 on: April 28, 2016, 04:27:50 PM »

Since we are on the subject of allocating pointers there is one more thing to consider about C, Pascal and other programming languages that allocate local variables on the stack:  They often contain garbage values when you first allocate them.  To get around this, you assign the NULL value to them when you allocate them.
Code: [Select]
int *varname=NULL;
How to assign pointers to variables

As I mentioned earlier, the "address of" operator is used to find the address of a variable.  To assign a value to varname using the allocation above, you could allocate an integer and put its address into it.
Code: [Select]
int value=0;
varname=&value;

Now that you have a pointer pointing at value you now can alias the contents of value variable like this:
Code: [Select]
(*varname)++;
printf("%i\n",value);
Will print 1 to the console.  Notice how I had to use the unary asterisk to access the value pointed to by varname.  I also had to use the grouping symbols to appease the pagan gods of the order of operations.  Had I done something like this:
Code: [Select]
*varname++; varname would now point at the address following value.  This is a special case of the increment operation that only happens when incrementing a pointer:  It always increments by the size of the type it contains.  Remember that C was never designed to be used to make applications.  It was designed to create the Unix operating system.  For that reason,
Code: [Select]
*ptr++; and
Code: [Select]
--*ptr; act as push and pop operations in a stack.  Those of you familiar with the 68000 Assembly will recognize them as post-increment and pre-decrement addressing modes.

To be continued again...
Logged

magorium

  • Full Member
  • ***
  • Posts: 184
  • Programming is an art form that fights back
    • View Profile
Re: C Chapter 3: Pointer variables
« Reply #2 on: April 29, 2016, 12:14:07 PM »

Thank you SamuraiCrow.

Pointers, being a relatively easy type in concept, can cause many hazards (at least i find myself more cursing at them then they do good for me) :-)

Although the following question is perhaps more related to operators (and their precedence), i found myself rather puzzled at the following snippet:

Code: [Select]
while ((*ptr ++ = *orig ++));
Where orig is a * char (ergo null terminated) passed to a function and ptr holding a copy of that passed * char (memory was allocated for that using strlen + 1).

Seeing that, i am able to analyze (in pascal-ish form):
- ptr^ := orig^;  // copy single character from orig to ptr
- inc(ptr); // next ptr position in memory
- inc(orig);  // next orig position in memory

I do notice that the 'copy' statement is placed inside extra brackets, so that the statement produces a while condition that evaluates to be either true or false.

But, for the life of me, i can't seem to figure out when/why that while loop ends (yes i can run it and see, but am not able to evaluate it theoretically) :-S

Is that related to pointer, operator and/or while loop behaviour, or otherwise compiler/language specific behaviour  ?

How is one able to figure out the answer(s) to the questions that arises from such (relatively small) topics ?

F.i. i've tried to understand operator precedence, but the tables from existing documentation, only seems to contradict itself (imo that is). Mentioning  left-to-right, right-to-left is all nice, but when using larger statements, a simply soul like myself gets lost between choosing left or right :-S.

(if the above is not in sync with your tutor, then please ignore. no need to derail, although i do would like to understand the while loop condition, especially if related to pointer operation).
Logged

SamuraiCrow

  • Administrator
  • Sr. Member
  • *****
  • Gender: Male
  • Posts: 372
  • Coolness is compiled
    • View Profile
Re: C Chapter 3: Pointer variables
« Reply #3 on: April 29, 2016, 05:03:35 PM »

@Magorium

The Pascal equivalent would be something like:
Code: [Select]
procedure copy(src:^character,dest:^character)
var flag:boolean;
begin
  repeat
    dst^:=src^;
    flag:=(src^=0);
    inc(src);
    inc(dst);
  until (flag)
end;

The reason C doesn't need the flag variable is that any returned non-zero value is evaluated as true.  This is mainly because C doesn't have a separate boolean variable type.  Also, the value assigned in an assignment statement is returned to the previous operation as a value of the same type.  In C x=y=z copies z to both y and x.  This makes things especially confusing when migrating to C from Pascal or Basic because = is a comparison in those languages and an assignment in C.  If you try to use := in C or the Let keyword from Basic it will be flagged as an error because those symbols aren't used in C and an equality comparison in C is ==.
Logged

ALB42

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: C Chapter 3: Pointer variables
« Reply #4 on: April 29, 2016, 05:13:54 PM »

The flag variable is not needed ;)

Code: [Select]
procedure copy(src:^character,dest:^character)
begin
  repeat
    dst^:=src^;
    if src^=0 then
      Break;
    inc(src);
    inc(dst);
  until False
end;

(Thats the reason I hate C)
Logged

SamuraiCrow

  • Administrator
  • Sr. Member
  • *****
  • Gender: Male
  • Posts: 372
  • Coolness is compiled
    • View Profile
Re: C Chapter 3: Pointer variables
« Reply #5 on: April 29, 2016, 05:27:13 PM »

@ALB42

If src or dst was used after the until clause of the repeat command mine would be more accurate equivalence because the increments would still be performed in the C code before the condition code was evaluated.  I agree your version would be similar.  I'm also not fond of C but prefer AmigaE, Hollywood or Basic.

I've used Pascal in high school/secondary school and at the 2-year college I attended afterward.  I've never used Object Pascal, however.
Logged

magorium

  • Full Member
  • ***
  • Posts: 184
  • Programming is an art form that fights back
    • View Profile
Re: C Chapter 3: Pointer variables
« Reply #6 on: April 29, 2016, 06:41:05 PM »

ah, ok (epiphany moment). The words "Also, the value assigned in an assignment statement is returned to the previous operation as a value of the same type." makes the behaviour plausible (for me at least).

Plausible, but i was not aware of that. Most of the code i port(ed) does not seem to rely on this behaviour so much (or more probably, overlooked by me :-) )

Yeah, it is a copy routine, more specifically the function strdup from gnu.

Speaking of precedence, i see both of you using a small change in order of events, but (and yes i could probably check that myself) is that actually true ? or is that why the statement is (or must be) enclosed in (double) brackets to make it work the way it does ?

e.g. The ++ operators are located at the right (so they come after the assignment), ergo the 'data' is copied first. Assuming the source pointer returned a #0 character then (without extra enclosed brackets) the while condition would become zero (= false) and exits the loop before even getting to the part of incrementing the pointers ? Or is the statement between the (first) while brackets always completely evaluated first (before determining what the while condition would become) ?

Truly sorry about the sidetrack, but very much appreciated for answering.
Logged

SamuraiCrow

  • Administrator
  • Sr. Member
  • *****
  • Gender: Male
  • Posts: 372
  • Coolness is compiled
    • View Profile
Re: C Chapter 3: Pointer variables
« Reply #7 on: April 30, 2016, 04:46:55 PM »

The post-increment operator is executed after the value of the statement is evaluated.  For that reason, the increment itself is generated as an additional opcode in the compiler.  If you have a choice between post- and pre-increment form of an instruction, the latter is usually simpler code.  Likewise for decrement operations.
Logged

SamuraiCrow

  • Administrator
  • Sr. Member
  • *****
  • Gender: Male
  • Posts: 372
  • Coolness is compiled
    • View Profile
Re: C Chapter 3: Pointer variables
« Reply #8 on: May 05, 2016, 08:06:19 AM »

Dot versus Arrow notation

In most modern languages the dot operator is used to indicate membership but in C it only indicates membership if you have a structure to refer directly to.  If you have a pointer to the structure you have two options:

  • *ptr.offset=value;
  • ptr->offset=value;

In option 1, you dereference the pointer with a unary asterisk as usual and use the dot operator to offset into the structure dereferenced by the pointer.  Unfortunately, the most common notation is option 2, the hyphen and greater-than symbol to make an arrow.  It's equivalent but more confusing.  What really gets confusing is when you have structures inside of structures and pointers to other structures with nested structures in them:

Code: [Select]
#include <stdio.h>

struct s1
{
  int a;
  int *b;
};

struct s2
{
  int c;
  struct s1 *d;
};

struct s1 e;
struct s2 f;
int g;

int main()
{
  g=10;
  e.a=0;
  e.b=&g;
  f.c=11;
  f.d=&e;
  printf("%i\n",f.d->*b);
  return 0;
}

Will print "10" and exit successfully to the prompt on the next line on the CLI.  Do you see any mistakes?  (I'm seriously asking, I think I got it right but it's so confusing I can barely tell.)

Notice I used "#include <stdio.h>" at the top to activate the printf command (and others) in the standard IO library linked at build time by the linker.  The preprocessor will be covered in a future chapter.

(Two edits later...)
Okay, NOW it looks right.
« Last Edit: May 05, 2016, 08:10:57 AM by SamuraiCrow »
Logged

itix

  • Newbie
  • *
  • Posts: 42
    • View Profile
Re: C Chapter 3: Pointer variables
« Reply #9 on: May 27, 2016, 11:25:27 PM »

or is that why the statement is (or must be) enclosed in (double) brackets to make it work the way it does ?

Double brackets are not required. It is just used to supress GCC warning.

Both versions work same:

Quote
while ((*ptr ++ = *orig ++));
while (*ptr ++ = *orig ++);

But if you hade something like this...

Quote
while (a = b)
{
    /* ... */
}

Here intended behaviour is not often obvious. Did programmer mean (a = b) or was it a typo and it should have been (a == b) instead.

So GCC warns about this and you should use double brackets ((a = b)) when assigning a variable in if/do/while test clause.
Logged

magorium

  • Full Member
  • ***
  • Posts: 184
  • Programming is an art form that fights back
    • View Profile
Re: C Chapter 3: Pointer variables
« Reply #10 on: May 28, 2016, 05:21:25 PM »

Thank you for the additional information itix.

Indeed the latter example using the double brackets is something i wondered about as well. It's obvious once you know it... as logic implies :-)

At least the behaviour of the comparison of the loop as showed, was certainly an eye opener for me and helped explain a few situations that i've been looking at in a strange way before.

It seems i still miss some fundamental understanding of how pointers work under certain circumstances and most of that flawed understanding seems to stem from default compiler/construct behaviour that is unknown to/for me (or have hard time finding/understanding documentation). And as murphy dictates, the moment you're starting to think that it would perhaps be ok to say "hey, i think i'm starting to grasp this stuff" .... something comes along that blows all your understanding/logic down the youtube channel :-)
Logged