Interactive Bootstraps“Introduction” →Pointers and loops

021e5bc2e68c2e381289556096a96420f27f77bf
🐶
Print program arguments
This serves as an introduction to both pointers and for-loops.

⟨hello.c⟩≡

@@ -1,6+1,7@@
1 1
 #include <stdio.h>

🐶

This is your first context line, the space instead of the plus means it is unchanged in this commit.

🐱

And presumably the minus below instead of the space or plus means that line is removed?

🐶

Correct, and note this file now has two line numbers, the one on the left hand side is the old line numbers, and the one on the right hand side is the new line numbers.

Also, the hunk header is now different too. It means that the hunk has 6 lines, starting from line 1 of the old file, and 7 lines starting from line 1 of the new file. This all lines up with the line numbers.

2 2
 
3 3
 int main(int argc, char **argv) {
4
-	// The classic C introduction program
5
-	printf("Hello, world\n");
4
+	for (int index = 0; index < argc; index++) {

🐶

This is a for loop, it loops with index from 0 to argc - 1.

🐱

I think you are going a bit too fast for me.

🐶

Yes, sorry, let’s break it down: the for loop has two parts, the header between the parentheses ( and ), and the body between the braces { and }.

The header itself has three parts, separated by semicolons:

  1. initial setup, in this case int index = 0 declares a variable called index of type int, with initial value zero;
  2. each time before running the body, it runs index < argc, and if it is true, then it runs the body. Hence the loop can run with index = 0, 1, 2, ..., argc - 1, but not with index = argc as the condition will be false.
  3. each time after running the body, it runs index++, which is shorthand for index += 1, itself shorthand for index = index + 1. This is why index is a variable, it can change.

Note, that a single equal sign as in index = index + 1 is actually assignment, not checking for equality. To check for equality you use two consecutive equal signs, such as index == index + 1, which is of course false.

5
+		printf("Argument %d is %s\n", index, argv[index]);

🐱

I have run the code, it printed Argument 0 is ./hello, so presumably this is formatted print, %d is decimal?

🐶

Yes, that’s right! And %s is string. They denote the type of the remaining arguments, so it’s saying: print “Argument␣”, print index as a decimal, print “␣is␣”, then print argv[index] as a string, and finally print a new line.

I’m using “␣” to visually denote spaces.

Incidentally, try running ./hello My name is Inigo Montoya.

🐱

It prints the following

Argument 0 is ./hello
Argument 1 is My
Argument 2 is name
Argument 3 is is
Argument 4 is Inigo
Argument 5 is Montoya

So presumably argv is something to do with the words after the program, and argv[index] accesses each of those arguments in turn?

🐶

Yes, exactly. Let me explain what pointers are, and what strings are, at least in C.

A pointer is first of all, a value with a size. All values in C have a size, the size of int is big enough to hold an integer, and the size of a pointer is big enough to hold an address to a memory location. We will get more specific about the exact sizes later.

So a pointer holds an address to a memory location, and that location itself has a type. We use the asterisk symbol * to denote a pointer, and char * is a pointer to a char, a character. A pointer to a character is what C considers a string, because C goes to each consecutive character until it finds a terminating character, which you would represent as the escape sequence \0 in C.

And yes, types in C are read right-to-left (mostly), if you ever need help figuring out what a type means in C, I recomment cdecl.org, for example char *hello tells you that hello is a pointer to a char.

But we have char **argv, which is a pointer to a pointer to char, or if you prefer, a pointer to a string. It is actually consecutive pointers to strings, that is what argc is there for, the count of arguments.

Let me draw you a picture:

+------+   +---------+---------+---------+---------+-----
| argv |-->| argv[0] | argv[1] | argv[2] | argv[3] | ...
+------+   +---------+---------+---------+---------+-----
                |         |         |         |
  +-------------+         |         |     +---+
  |    +------------------+         |     V
  |    |                +-----------+   +---+---+----+
  |    |                |               | i | s | \0 |
  |    V                V               +---+---+----+
  |  +---+---+----+   +---+---+---+---+----+
  |  | m | y | \0 |   | n | a | m | e | \0 |
  |  +---+---+----+   +---+---+---+---+----+
  |
  V
+---+---+---+---+---+---+---+----+
| . | / | h | e | l | l | o | \0 |
+---+---+---+---+---+---+---+----+

The route the arrows take doesn’t matter, the address could be anywhere. The point is, that argv[0], argv[1] and so on are consecutive, and the square brackets [ and ] access consecutive elements of the pointer.

Let’s take a breather and leave it here for now.

🐱

I’ll pop the kettle on, and put The Princess Bride on. I haven’t seen it in ages.

6
+	}
6 7
 }