Shy
Shy

Reputation: 536

Understanding dereference operator and pointers in C, and logic of a small program

I got this code snippet from here:

int main(int argc, char *argv[])
{
    for (int i = 1; i < argc; ++i) {
        char *pos = argv[i];
        while (*pos != '\0') {
            printf("%c\n", *(pos++));
        }
        printf("\n");
    }
} 

I have two questions:

  1. Why are we starting the iterations of for loop at i=1, why not start it at i=0, especially when we are ending the iterations at i<argc and Not at i<=argc?

  2. The second, third and fourth last lines of code! In char *pos = argv[i];, we declare a pointer type variable and assign it a pointer to a commandline parameter passed when running the program.

    Then in while (*pos != '\0'), *pos dereferences the pointer stored in pos, so *pos contains the actual value pointed by the pointer stored in pos.

    Then in printf("%c\n", *(pos++));, we have *(pos++), and that is the actual question: (a) Why did he increment pos, and (b) what is the meaning of dereferencing (pos++) with the dereference operator *?

Upvotes: 0

Views: 275

Answers (4)

sjsam
sjsam

Reputation: 21965

Why are we starting the iterations of for loop at i=1, why not start it at i=0, especially when we are ending the iterations at i < argc and Not at i <= argc?

Note that the argc contains the name of the program being executed too which will be the first (given the number zero) thing to be counted. So the actual arguments starts from 1 and ends at total - 1


A note here, the command line arguments are stored in array of pointer to char, ie

argv[0] -> "YourFirstArguement"
argv[1] -> "YourSecondArguement"
.
.
argv[argc-1] -> "YourLastArguement" //Remember argc-1 is the last argument

and so. Note that each of the argument is a null terminated string


So in

char *pos = argv[i]; // Create another pointer to each string
while (*pos != '\0') {
  printf("%c\n", *(pos++)); // Note %c, you're printing char by char.
}

You're just printing character by character using the format specifier %c in printf. So you need to dereference character by character in the while loop and this answers

a) Why did he increment pos, and

b) what is the meaning of dereferencing (pos++) with the dereference operator *?

Upvotes: 0

Giorgi Moniava
Giorgi Moniava

Reputation: 28674

Why are we starting the iterations of for loop at i=1, why not start it at i=0, especially when we are ending the iterations at i

Because first parameter is name of the program - and it seems author is not interested in it.

Second case is basically similar to the following (argv[i] basically being a char *):

So you have something like this:

char * c = "Hello"

and then char * p = c;

Now you have

+------------------+
| H e l l o /0     |
| ^                |
| |                |
+------------------+
  |
  |
  +
  p

When you do p++ you have

+------------------+
| H e l l o /0     |
|   ^              |
|   |              |
+------------------+
    |
  +-+
  +
  p

If you do now *p - the value you get is 'e'.

*(p++) is basically same as above two steps, just due to post increment, first the value where p points will be retrieved (before increment), and then p will advance.

Then in printf("%c\n", *(pos++));, we have *(pos++), and that is the actual question: (a) Why did he increment pos, and (b) what is the meaning of dereferencing (pos++) with the dereference operator *?

So in the while loop the author is traversing through the whole string until he meets null terminator '\0' and printing each character.

This on the other hand is repeated for each parameter in argv using the for loop.

Upvotes: 2

Sourav Ghosh
Sourav Ghosh

Reputation: 134356

For the first part,

Why are we starting the iterations of for loop at i=1, why not start it at i=0, especially when we are ending the iterations at i<argc and Not at i<=argc?

Because, for hosted environment, argv[0] represents the executable name. Here, we're only interested in supplied command line arguments other than the executable name itself.

Quoting C11, chapter §5.1.2.2.1

If the value of argc is greater than zero, the string pointed to by argv[0] represents the program name; [....] If the value of argc is greater than one, the strings pointed to by argv[1] through argv[argc-1] represent the program parameters.

Point to note: using i<=argc as the loop condition would be wrong, as C arrays use 0-based indexing.

For the second part,

(a) Why did he increment pos, and (b) what is the meaning of dereferencing (pos++) with the dereference operator *?

*(pos++), can also be read as *pos; pos++; which, reads the current value from the memory location pointed to by pos and then advances pos by one element.

To elaborate, at the beginning of each iteration of the for loop, by saying

char *pos = argv[i];

pos holds the pointer to the starting of the string which holds the supplied program parameter and by continuous increment (upto NULL), we're basically traversing the string and by dereferencing, we're reading the value at those locations.


Just for the sake of completeness, let me state, that the whole for loop body

    char *pos = argv[i];
    while (*pos != '\0') {
        printf("%c\n", *(pos++));

can be substituted using

    puts(argv[i]);

Upvotes: 2

Gerhardh
Gerhardh

Reputation: 12404

  1. Why are we starting the iterations of for loop at i=1, why not start it at i=0, especially when we are ending the iterations at i

We start at 1 because argv[0] holds the name of the program itself which we don't care about. Ignoring the first element of an array does not move the index of the last array. We have argc elements stored in argv[]. Therefore we mustn't run until i==argc but need to stop one element earlier, just as with every other array.

  1. The second, third and fourth last lines of code! In char *pos = argv[i];, we declare a pointer type variable and assign it a pointer to a commandline parameter passed when running the program.

Correct. pos is a pointer and points to the first string passed via command line.

Then in while (*pos != '\0'), *pos dereferences the pointer stored in pos, so *pos contains the actual value pointed by the pointer stored in pos.

*pos contains the first character of the string we are currently inspecting.

Then in printf("%c\n", *(pos++));, we have *(pos++), and that is the actual question: (a) Why did he increment pos, and (b) what is the meaning of dereferencing (pos++) with the dereference operator *?

You have 2 things here: 1. (pos++): pos is a pointer to char and with ++ increment the pointer to point to the next element, i.e. to the next char after taking its value. 2. The value of pos (before the post-increment) is taken and dereferenced to read the char at that position.

As a result the while loop will read all characters, while the for loop handles all strings.

Upvotes: 3

Related Questions