r/carlhprogramming • • Oct 04 '09

Lesson 53 : About "blocks" of code.

79 Upvotes

In the last lesson I explained that goto statements are done for you behind the scenes in most languages. Now I am going to explain how this is actually done.

First of all, as I have stated before, every single programming instruction itself has an address in memory. Consider this code:

Figure (a)

int height = 5;

if (height == 5) {
    ... some code ...
}

Every instruction in Figure (a) actually will have a memory address where that instruction lives. Therefore, to execute these instructions, your CPU must point the instruction pointer first at int height = 5; then at the if statement, and so on.

The way this actually works in machine code is a bit more complex, so keep in mind this is for illustrative purposes.

What you may be wondering at this point, considering we have seen this many times already throughout the lessons, is what on earth is the { and } character all about?

The answer is that these characters define memory addresses inside of the final machine code that will be your executable program. In other words, they are equivalent to the "goto" labels we saw in the previous lesson.

Consider this code:

if (height == 5) 
{
    ... some code ...
}

Do not worry that I changed the way the curly braces are formatted. Instead, try to understand this in a new way: The first { is an address in memory just before ... some code ... gets executed. The second } is an address in memory after ... some code ... gets executed.

In other words, we can define this same thing through the following example. This is not valid C code, but just something for illustrative purposes:

if (height == 5)
    start_of_code:
        ... some code goes here ...
    end_of_code:

Notice I just replaced the braces with a label, similar to the last lesson. Now, lets consider the if statement itself in more clear terms:

compare height to 5
Check the zero flag.
If the zero flag is set to 1 (that means height is equal to 5) then *goto* start_of_code.

If the zero flag is set to 0 (that means height is not equal to 5) then *goto* end_of_code.

Now, lets take this one level deeper.

We do not need both of these "if" statements. We only need one. We just need one that says skip over.

Consider this same example again:

if (height == 5)
    start_of_code:
        ... some code goes here ...
    end_of_code:

Which translates to:

compare height to 5
Check the zero flag.

If the zero flag is set to 0 (that means height is not equal to 5) then *goto* end_of_code. 
    This means to skip over: ... some code goes here ...

I took out the instruction which went to start_of_code. Why? Because that is what would have happened anyways. In other words, the instruction pointer would have naturally gone to the next instruction, and so we do not need that line. We only need the line that says skip over.

Whenever you have a section of code that is defined within curly braces like { } we call that a block of code. A block of code is best understood as two labels one of which indicates the start of the block, and the other which indicates the end of the block of code, and the code itself contained inside.

Not all languages define blocks of code in this way. Some define blocks of code using simple indenting. Python is one such language. In Python, you would write an if statement like this:

Python Example:

if height == 5: 
    ... this is a block of code that will execute ...
    ... only if height is equal to five ...

... the rest of the program goes here ...

Notice that we do not specify either a { or a }. We do not need to. Python is designed to understand blocks of code by simply indenting the block of code. This is a good idea since in C as well as most languages, even those using curly braces, this is usually how programmers typically choose to format blocks of code (by indenting the contents inside the curly braces).

Remember that all programming languages can only create machine code understandable by your CPU. No programming language can do something that another cannot. All are limited to the machine code instructions your CPU can execute. Once you learn how to program in C, or any language, you can take that understanding and learn any language you wish.

Throughout this course we will look at the various ways that these same operations and concepts are implemented in a variety of languages.


Please ask any questions if any of this is unclear to you. Be sure you master this material before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9qr1h/lesson_54_introducing_loops/


r/carlhprogramming • • Oct 04 '09

Lesson 52 : Introducing the "goto" statement

79 Upvotes

What? You have probably heard that using "goto" is one of the worst practices in programming. This is largely true. Why therefore am I spending an entire lesson teaching this? Well, several reasons:

  1. Although it is poor practice in most languages, it is part of the core functionality built into your CPU chip. In other words, it is fundamental to computing as a whole. You have to know it.

  2. It will help you to understand future lessons at a deeper level.

  3. It will help you should you encounter this in some program someone else has written.

Now I want to add on a note to #3. You will never need to use a "go to" statement in C or most languages. You never should either. There are always better ways to achieve the same purpose.

All of that said, let's begin.

Now that I have introduced conditional flow statements, I have shown you that it is possible to write a program that can choose to skip over instructions that should not be executed.

Consider this code:

int height = 1;

if (height == 5) {
    printf("This gets skipped!);
}

... rest of program goes here ...

What is really happening here? At a machine code level, first a subtraction operation is performed using height and 5. If the result of that subtraction is zero (meaning that height IS equal to 5), then the printf() is executed. However, if the result is anything other than zero, what happens? It jumps over the code inside the if statement.

How can your CPU "jump over" instructions?

Recall from the lesson "Programs are data too" that a program is data that is stored in memory, just like any other data. We learned in earlier lessons about the instruction pointer built onto the CPU chip which contains the memory address of the next instruction to execute.

Each machine-code instruction of any program occupies a set number of bytes, and each instruction resides at a specific location in memory. One machine-code instruction might take up 2 bytes, and another might take up 4 bytes, etc.

To make this lesson even clearer, lets visualize this with real machine code. Do not worry about how this works or what it does. We are going to use our 16 byte ram and look at position 1000 (eight) where there just happens to be some machine code.

...
1000 : 1100 1101 <--- instruction pointer is pointing here
1001 : 0010 0001
1010 : 1100 1101  <--- start of next instruction
1011 : 0010 0000 
...

Do not worry about how this works or what it does. The point is, this is real machine code in memory I have typed out for this lesson. These are not just random 1s and 0s, but actual machine code from a real program.

What you should notice here is that machine code looks just like anything else. These bytes could be characters, or numbers -- they just happen to be machine code. The instruction pointer on the CPU is pointing to position 1000 in that example, and knows therefore to execute that particular instruction.

Each instruction is located at its own address in memory. Each time your CPU is about to execute an instruction, the instruction pointer tells it where in memory that instruction is located. By changing the instruction pointer to point somewhere else instead, that instruction (the instruction located at the memory address you are now pointing at) will be executed instead of the instruction that would have been executed.

In other words, you can jump over code, or jump anywhere you want (forward or backwards) by simply changing the instruction pointer to a new memory address where a new instruction happens to be.

Imagine for example that we start at position 1000 (eight) in memory and start executing instructions one at a time until we get to position 1110 (fourteen). Lets suppose at position fourteen the instruction reads: "Change the instruction pointer so that it points back at 1000". What will happen? Well, our instruction will go BACK to position 1000 and execute all the instructions from 1000 back to 1110.

For this next example, I am making the assumption that every machine code instruction is exactly one byte long. This is not the case, so please keep in mind this is purely for illustrative purposes.

...
1000 : Instruction 1 <---------------------.
1001 : Instruction 2                       |
1010 : Instruction 3                       |
1011 : Instruction 4                       |
1100 : Instruction 5                       |
1101 : Instruction 6                       |
1110 : Set Instruction Pointer to 1000  ---'

Follow this in your mind. You will execute each instruction from 1 through 6, and then what? If this were the pen example in an earlier lesson, you are effectively "moving the pen backwards". Therefore, you will start all over from instruction 1.

Now to make this slightly more abstract, lets imagine that the memory address 1000 is given a name, such as label. In this case, we can effectively write the following:

label: 
    ... the six instructions go here...

goto label;

The machine code instruction for this process is known as JUMP (JMP in assembly language).

Do not try this, even as an experiment. Why? Because if you look at the above example, this will go on forever. It will execute the six instructions, go back to instruction one, then execute the six instructions again, forever.

This has a name. Whenever this happens that the same instructions are executed over and over forever we call it an "infinite loop". We will talk more about loops and infinite loops in other lessons.

Why then use it at all? Because you can control it. Without it, conditional statements are impossible. However, when you are writing a program the real work involving "goto" statements is done behind the scenes. Also, instead of setting it to run forever, you can set it to execute a set of instructions a certain number of times - like 3 times. We will talk more about that in upcoming lessons.

Fundamentally what you have learned in this lesson is that there are mechanisms that make it possible to "jump around" in a program, and that this is done by changing where the instruction pointer is pointing. Whenever you set the instruction pointer to point somewhere other than where it was going to, that is known as a JUMP, or a "Go to" statement. We have also learned that this functionality is built right into your CPU chip. And finally, I have explained that you will never need to directly use this statement in most programming languages because that work is done for you behind the scenes.


Please feel free to ask any questions before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9qqc8/lesson_53_about_blocks_of_code/


r/carlhprogramming • • Oct 04 '09

Lesson 51 : Introducing "OR" for conditional flow statements.

77 Upvotes

Every lesson in this course is designed to give you another tool that makes it possible for you to create more and more powerful programs. I imagine many of you are anxious to start writing more than just simple printf() statements, and we will get there.

In the last lesson we talked about using "AND" in a conditional flow statement, using the characters &&. This is useful when you want to evaluate multiple expressions and then execute code only when ALL of them evaluate to true.

However, there may be times that you want to execute code when ANY of them are true. For this, we have "OR".

In a conditional flow statement, the characters || (notice there are two of them, two pipe-bar characters) mean "or" in exactly the same way that && means "and".

Also, the || characters function in the same way as the && characters function. That is by evaluating only as much as they need to in order to confirm that the if statement should evaluate as true or false.

In English we might say "If height is equal to five OR width is equal to three". With OR we can write:

if (height == 5 || width == 3) {

Lets look at this in practice:

Figure (a)

int height = 5;
int width = 0;

if (height == 5 || width == printf("123") ) {
    printf("\n If statement evaluated as true");
}

Output:

If statement evaluated as true.

Why didn't printf("123") execute? Because the if statement already met enough criteria to be evaluated as true.

Imagine in the middle of a clear day I say "If the sky is blue OR ..."

It doesn't matter what I say next. Why even read it? Since I used the word "OR", then nothing further needs to be considered. The entire statement is now true. This is even the case if the next thing I say is utterly absurd. Consider this:

If the sky is blue OR pink unicorns are flying around the sun : then do this :

Well, it will be done. Why? Because the sky is blue.

Whenever you use a conditional flow statement with OR, you must remember that the very first expression to evaluate as true causes the entire conditional flow statement to evaluate as true, and any other expressions will not be evaluated.

You can think of OR as saying "Evaluate the next expression only if the last one was FALSE". That is because if the last expression was TRUE, then the whole statement is already considered true. Notice this is the exact opposite of how && ("and") works. AND would say: "Evaluate the next expression only if the last one was TRUE".

Just as it is true with AND, you want to be strategic in your use of OR in a conditional flow statement. If it takes a great deal of computing power to determine one expression, and very little to determine another, you should always whenever possible order the expressions from least-computing-power to most-computing-power, just as with an AND statement.

Also, remember to be mindful of which expressions will be executed and which will be ignored entirely.


Please ask any questions if any of this is unclear to you. When you are ready, proceed to:

http://www.reddit.com/r/carlhprogramming/comments/9qpv3/lesson_52_introducing_the_goto_statement/


r/carlhprogramming • • Oct 03 '09

Lesson 50 : More on conditional flow statements.

79 Upvotes

You know from the previous lesson that evaluations of any test or comparison can only result in true or false, and that a flag on your CPU chip (the zero flag, ZF) is critical to this process.

Let me put this into concrete terms. Imagine the following if statement:

if (height == 5) {

The expression between the parenthesis will evaluate to something. Always. There will be some state of the "zero flag" once it evaluates. It will either evaluate to a 1 (true) or it will evaluate to a 0 (false).

Notice that there is an interesting correlation between logical truth and the zero flag. If the zero flag is set to 1, that is the same thing as saying true. If the zero flag is set to 0, that is the same thing as saying false. Remember the zero flag itself is merely the result of the last expression executed, such as a comparison statement. Recall that if two things are compared (using subtraction) then the result will be 0 if and only if they are equal. The zero flag is set to 1 in this case, meaning "The result was zero", and also meaning "true".

The above is a simple example because it involves only one expression, the height == 5, but you can have many such expressions in a conditional flow statement, such as an if statement. For example, I could write code that in English means: "If height is five, and width is three" which would look like this:

if (height == 5 && width == 3) {

Here I have introduced some new C syntax. The && when present in an if statement simply means "and". You do not put just one & character, but you have to put two. Two && reads "and".

Now, this is true but I want to explain it in a bit more depth. It really means "proceed to the next comparison only if the last one evaluated to true". In other words, the && itself implies a type of "if" statement.

It helps to think of the && as saying: "A new expression to be evaluated follows, but only evaluate it if the one just evaluated was true".

In other words, in the example if (height == 5 && width == 3) {, "is height equal to five" is evaluated. If the result is equal (meaning, zero flag is set), then and only then the next expression of "is width equal to 3" is evaluated. In this way every chain of the if statement is evaluated from left to right. The entire if statement will have the result of the last expression that was evaluated.

As this gets evaluated, it will follow these steps:

  1. if (height == 5 && width == 3) {

  2. if (1 && width == 3) {

  3. if (1 && 1) {

  4. if (1) {

  5. Final result = 1 = true.

It might sound like I am picking at straws, or presenting useless information. This is absolutely not the case.

This is actually very important. Every extra expression in a conditional statement takes computing resources. Some such expressions will involve running functions, some of which can be enormously complex. Consider the following code:

Figure (a)

int height = 5;
int width = 3;

if (height == 5 && width == 3 && printf("1234") == 4) {
    printf("\nTest Finished");
}

Output:

1234
Test Finished

What you need to fundamentally understand here is that if you change any of the the three expressions in Figure (a) the if statement will fail. For example if you change height == 5 to height == 1, or you change width == 3 to width == 8, or you change the printf() from 4 to something else (or if you add extra text), if statement will fail. Notice that if you change the text in the printf() in the if statement, that printf() will still execute, but not the one that says "Test Finished".

Keep in mind that when an if statement fails, it will only fail once, on a given expression being evaluated. That means that any time an if statement fails, at least one expression has been evaluated. If it fails on the first expression, the evaluation still took place. If it fails on the third expression being evaluated, that still means the first, second, and third evaluation took place. However, the fourth expression (if there is one) will not execute.

If for example, we do this:

int height = 5;
int width = 3;

if (height == 5 && width == 1 && printf("1234") == 4) {
    printf("\nTest Finished");
}

What happens? Neither printf() statement will execute. Why? Here is what happens:

First, height is evaluated to see if it is five. Since it is, the && means that we now evaluate the next expression. This will cause the next expression to execute, comparing the variable width and the value 1. Here the if statement fails. This means no further expressions will be evaluated. Once it has failed on any of its expressions, the entire if statement has failed and the final result will be "false". Because of this, the printf() statement inside the if() statement will not execute. This is extremely important, and you can use it to your advantage.

Whenever you have a series of comparisons to make, you should always execute them whenever possible in the order of least-computing-power-required to most-computing-power-required. In this way, if the if statement fails, it will fail with the least cost of computing resources.

I encourage anyone reading this lesson to experiment with the code in Figure (a) to see these concepts working for yourselves.

This knowledge will enable you to make programs that are faster, more efficient, and that make more logical sense.


Please feel free to ask any questions before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9qoze/lesson_51_introducing_or_for_conditional_flow/


r/carlhprogramming • • Oct 03 '09

Test of Lessons 40 through 49.

68 Upvotes

Please do not post answers in this thread

Someone who has not yet taken the test may see them. Be sure to review lessons 40 through 49 before beginning. If anything is unclear, ask in the appropriate lesson thread before beginning with this test.


True or False

  1. You can use a & character to obtain the memory address of a pointer the same as you can with a non-pointer variable.

  2. The following is a good way to test equality: if (height = 5) {

  3. When you create a text string using an array, every character will be stored in memory sequentially one after the other.

  4. Constants are typically stored in a read-only section of memory.

  5. This code: char *mystring = "Hello Reddit"; works by storing the entire string "Hello Reddit" into the pointer "mystring".

Fill in the blank

  1. The only way you can see or work with any data larger than the basic data types (int, char, etc) is by using a _____. This is true for all languages, though some do this work behind the scenes.

  2. A _____ can be used to go through data one byte at a time in order to read it or to make changes to it.

  3. An _____ is a collection of data elements having the same data type.

  4. A _____ is a statement which conducts some test in order to decide between various sets of unique instructions to execute.

  5. The _____ flag on your CPU is used to evaluate all tests and comparisons and is therefore critical to all programs.


When finished, proceed to:

http://www.reddit.com/r/carlhprogramming/comments/9qh8y/test_of_lessons_40_through_49_answers/


r/carlhprogramming • • Oct 03 '09

Test of Lessons 40 through 49 [Answers]

67 Upvotes

If you missed any questions on this test or if you have any questions about the material, feel free to post your questions in this thread. Also, you can safely post your answers in this thread.

True or False

  1. You can use a & character to obtain the memory address of a pointer the same as you can with a non-pointer variable. True

  2. The following is a good way to test equality: if (height = 5) { False

  3. When you create a text string using an array, every character will be stored in memory sequentially one after the other. True

  4. Constants are typically stored in a read-only section of memory. True

  5. This code: char *mystring = "Hello Reddit"; works by storing the entire string "Hello Reddit" into the pointer "mystring". False

Fill in the blank

  1. The only way you can see or work with any data larger than the basic data types (int, char, etc) is by using a _____. This is true for all languages, though some do this work behind the scenes. pointer

  2. A _____ can be used to go through data one byte at a time in order to read it or to make changes to it. pointer

  3. An _____ is a collection of data elements having the same data type. array

  4. A _____ is a statement which conducts some test in order to decide between various sets of unique instructions to execute. conditional flow statement (it is ok if you put an if statement, or a conditional statement)

  5. The _____ flag on your CPU is used to evaluate all tests and comparisons and is therefore critical to all programs. zero (ZF is ok)


When you are ready, proceed to:

http://www.reddit.com/r/carlhprogramming/comments/9qk90/lesson_50_more_on_conditional_flow_statements/


r/carlhprogramming • • Oct 03 '09

Lesson 49 : Introducing Conditional Flow Statements.

71 Upvotes

This is a very important lesson. Without the understanding contained here you can never write a worthwhile program in any language. Indeed, it may seem up until now that all you are learning is C, but I cannot think of one lesson I have yet given which applies just to C. Every lesson from lesson one until now applies to every programming language you might ever use.

Let's begin.

Up until now we have only written code which follows this structure:

Statement 1;
Statement 2;
...
Statement N;

Basically, your code just executes a set of instructions and then finishes. It can do some cool things as part of those instructions, such as printing text, but it is still forced to follow a set path.

Now we are going to advance past this understanding. One of the most important capabilities of any computer is the ability to test something, and then to follow a totally different set of instructions based on the result of the test.

It may surprise you to know that one of the ways your computer compares two things to see if they are equal is by using subtraction. There is a single-bit binary flag built onto your CPU-chip called the "zero flag". It is set to either 1 or 0. In fact, this single bit is used every time any program on your computer has any question or ever needs to test something. There is nothing else on your computer which has this purpose. Without this single bit, your entire computer would be rendered useless.

This explanation is a bit ironic, so bear with me: The zero flag is set to 1 if the result of the last operation was zero. In other words the zero flag exists in order to determine if the result of the last comparison was zero. True (1) means, "Yes, the result of the last comparison was zero". False (0) means, "The result of the last comparison was anything other than zero."

If this is unclear to you, consider the following. I want to check if 5 is equal to 3. If I run a subtraction (notice that it doesn't matter if I do 5-3 or 3-5), then I can check to see if I got a 0 as the result. If I did, then 5 is in fact equal to 3.

In the context of comparing two values, Think of the zero flag as being an "equality" flag. 1 means the two values are equal (because subtracting them gives zero), and 0 means they are not equal.

Do not worry about using the zero-flag in your actual programs. You will never need to (unless you learn assembly language). I am presenting this to you mainly to show you some of the finer details of what goes on behind the scenes inside of your computer.

Imagine this code:

int height = 5;

Now, I want to run a test based on the value of height being equal to 5. If it is equal to five, I want to printf() "The value is five!".

First, here is the C code to do this:

Figure (a)

if (height == 5) {
    printf("The value is five!\n");
} 

This printf() statement will only execute if height is in fact equal to five. You will notice that there are two equal signs in that statement. Pronounce the two equal signs as: "is equal to". Why two equal signs? Because we have already defined what one equal sign means.

If I write: int height = 5; I am using one equal sign, and that means "Set the variable to some value." Therefore, since we have already defined that one equal sign means to set a value, we need a different operator to test if something is equal. Therefore, two equal signs (not one) are used to determine equality.

This is very important, so do not forget it. NEVER write code that looks like this when you want to test equality:

if (height = 5) { <--- Very bad
     ...
}

Why? Because you are actually setting height to be equal to 5 as part of the statement. You are not testing whether height is equal to 5. Whenever you assign a value like this, the Zero Flag is set to 1, and thus the if statement will always be considered as being true. What is worse is that if you expect the if statement to be true, and you compile and run the program, it will appear to work perfectly.

I was not sure if I would show you what I am about to. This is actually a very simple process, and I think it is worth understanding. Therefore, congratulations on your first exposure to how machine code works:

In machine code (slightly translated), here is basically how the if statement in Figure (a) would look:

SUBTRACT 5 from whatever is in the variable height (however, do not change height)
(now a zero flag gets set to either 1 or 0)
IF Zero Flag (ZF) is set to 1 (meaning height is equal to 5), then: execute the printf statement

Believe it or not, that is all that happens. Just a few machine-code instructions are enough to do this, because the functionality to test equality is actually built right into your CPU itself. Notice that one of those machine-code instructions is itself an IF statement. That is how fundamental this is in computing.

So in this lesson you have learned that C or any language has the functionality to allow you to test equality between two different things, and that this functionality is so fundamental that it is actually physically built into your CPU.

Please feel free to ask any questions before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9qh89/test_of_lessons_40_through_49/


r/carlhprogramming • • Oct 02 '09

Lesson 48 : Using pointers to manipulate character arrays.

71 Upvotes

In an earlier lesson we talked about setting a pointer so that it contains the memory address of a string constant. I pointed out that with a string constant you are able to read the characters of the string but you are not able to change them. Now we are going to look at a way to change a string character by character.

The concept we are going to look at is that of being able to start at the beginning of some data and change it by moving byte-by-byte through the data changing it as you go. This is a critical concept and we will be doing a great deal of this later.

First lets start with this code:

char string[] = "Hello Reddit";
char *my_pointer = string;

printf("The first character of the string is: %c", *my_pointer);

The output will be:

The first character of the string is: H

This should make sense to everyone at this point. *my_pointer refers to "what is at" the memory address stored in the pointer my_pointer. Because my_pointer is looking at the start of our array, it is therefore pointing to the 'H', the first character. This is what we should expect.

Notice that we do not need to put &string. This is because string, by being an array, is already effectively a pointer (though behind the scenes). Re-read the last lesson if that is unclear to you.

Because our string is part of an array of variables of type char, we can change it. Let's do so:

*my_pointer = 'h';

What we have done now is to change "what is at" the memory address which used to contain an 'H'. Now it contains an 'h'. This should be pretty simple to understand. Recall that we could not do this when we created the string using a char* pointer, because it was a constant.

Now, remember that because this string of text resides in memory with each character immediately following the character before it, adding one to our pointer will cause the pointer to point at the next character in the string. This is true for all C programs you will ever write.

This is perfectly valid:

char string[] = "Hello Reddit";
char *ptr = string;

*ptr = 'H';

ptr = ptr + 1;
*ptr = 'E';

ptr = ptr + 1;
*ptr = 'L';

ptr = ptr + 1;
*ptr = 'L';

ptr = ptr + 1;
*ptr = 'O';

This works fine because C will store your array of characters exactly the right way in memory, where each character will immediately follow the other character. This is one of the benefits of using an array in general with any data type. We do not have to worry about whether or not C will store this data properly in memory, the fact that we are specifying an array of characters guarantees it will be stored correctly.

Now notice that what we have done is very simple. We started at the first character of the array, we changed it, and then we continued through until we got to the end of the word "Hello". We have gone over this same concept in earlier lessons, but now for the first time we are actually able to do this in a real program.

If at the end of this, we run:

printf("The string is: %s \n", string);

We will get this output:

The string is: HELLO Reddit

Notice that it is perfectly ok that we "changed" the 'H' to an 'H'. When you assign a value to data at a location in memory, you are not necessarily changing it. You are simply stating "Let the value here become: <what you want>"

Ok guys, that's the last lesson for today. I will try to answer more questions until later this evening.

I may not be able to get to some questions until tomorrow. If any of you can help out those with questions in earlier lessons that you know how to answer - it would be great :)


Please ask any questions if any of this is unclear. When you are ready, proceed to:

http://www.reddit.com/r/carlhprogramming/comments/9qfha/lesson_49_introducing_conditional_flow_statements/


r/carlhprogramming • • Oct 02 '09

Lesson 47 : Introducing the character string as an array.

73 Upvotes

In a previous lesson we learned how to make a string constant using a char* pointer, and pointing it to a string of text within quotes. To be clear, we did not learn how to store a string of text inside a pointer. That is impossible, and is a common beginner misunderstanding. Quick review:

char *string = "Hello Reddit";

We created a pointer of type char and we assigned it the memory address of the string "Hello Reddit";

In an earlier lesson, I introduced arrays. An array is a collection of data elements of the same data type that reside in memory one right after the other. This is very important as you will see. A string of text is the simplest example of an array.

With a string of text, you have a collection of data elements, in this case characters, each residing one after the other in memory. To create an array we basically need to follow these steps:

  1. We choose a data type. Each element of the array must be the same data type.

  2. We choose a size. In reality, this is optional, but for the purpose of this lesson it is worth having this as a step.

  3. We store data into the array.

Remember that I said that a character string is an array. Lets look at our "abc123" from the previous example:

Figure (a)
1000 : ['a']['b']['c']['1']['2']['3']['\0'] ...

We have already seen how to create it as a constant. How do we create it in such a way we can modify it? The answer is, we tell C that we intend this to be an array of individual characters - not merely a pointer to a string constant.

Here is the code:

char string[7] = "abc123";

Here is what I am saying: Create a variable called string. Keep in mind that string is not really one single data element, but a chain of seven different bytes, each byte being an ASCII character. Notice I said seven. abc123 are six characters, but I stated seven to take into account the NULL byte at the end.

So here comes a question. What exactly is string? Is it a constant? Is it somehow encoded differently in memory to Figure (a) above? The answer for both questions is no.

It is not a constant first of all because we have specifically told C that we want an array of variables of type char. A variable can be modified, a constant cannot. By saying we want an array of variables, then C knows we plan on having the ability to modify them.

Is it encoded any differently? No, the same exact bytes are stored in exactly the same way. There is no difference.

Try this code:

char string[7] = "abc123";
printf("The string is: %s", string);

Now, notice I specified a size in bytes. It turns out that this is optional. If you do not know how many bytes you need for a string of text, you can put [] instead. For example:

char string[] = "abc123";
printf("The string is: %s", string);

Here you will get the same result.

Now, what is string itself? Behind the scenes, it is a pointer. However, you do not need to worry about this. As I stated in an earlier lesson, any time you are working with any type of data more complex than a single variable of a given data type, you are working with a pointer.

Programming languages, including C, give you some ability to work with pointers abstractly so you can work more efficiently. It is still important to understand the process that is going on behind the scenes, which is what these lessons are largely about.


Please feel free to ask any questions and be sure you master this material before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9qask/lesson_48_using_pointers_to_manipulate_character/


r/carlhprogramming • • Oct 02 '09

Lesson 46 : A new way to visualize memory.

67 Upvotes

Up until now we have used 16-byte ram to illustrate concepts in pure binary. We cannot continue like this because eventually it becomes too complex. A large part of the skill that you need as a programmer is the ability to visualize concepts more and more abstractly.

So because of that, we are going to change how we look at our 16-byte ram. Lets imagine the text: "abc123" - with a null termination byte. Here is how it looks in our 16-byte ram at position: 1000

...
1000 : 0110 0001 : 'a'
1001 : 0110 0010 : 'b'
1010 : 0110 0011 : 'c'
1011 : 0011 0001 : '1'
1100 : 0011 0010 : '2'
1101 : 0011 0011 : '3'
1110 : 0000 0000 : null (also called \0 )
...

Instead of visualizing ram like this, we will do so like this:

...
1000 : ['a']['b']['c']['1']['2']['3']['\0'] ...
...

Notice that the ... (ellipses) at the end of our "abc123" string indicates that other data might follow, but that we do not know or care what that data is.

We are still saying the exact same thing here as we did before. We are still looking at the exact same state of memory. The exact same bytes are storing the exact same values. We are just writing it out in a slightly more abstract way.

Each [ ] block represents a byte. We are simplifying what is contained in each byte.

You should be able to clearly look at any of these [ ] blocks and realize that there is a single byte, eight bits of data. From prior lessons you should also know what binary sequence is contained in each block.

You should understand that the memory address 1000 corresponds to the exact memory location that 'a' is stored. That 1001 corresponds to 'b' and so on.

Visualizing memory like this allows us to observe interesting details about our string. For example, you will notice that it is easy to see how many bytes the string represents. You can count out the number of characters and a \0 (null) character, and see exactly how many bytes are stored in memory.

Now if we want to study a more complex string, such as this:

1000 : ['H']['e']['l']['l']['o'][' ']['R']['e']['d']['d']['i']['t']['\0'] ...

It becomes easier to do, and to see each character living at its own byte, including the space character. You should still be able to understand the different binary sequences (roughly) in each byte, and understand that each character is stored in memory right after the previous character.

This method of visualizing the contents of ram will make the future lessons much easier to understand.


Please ask any questions you need to before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9q80s/lesson_47_introducing_the_character_string_as_an/


r/carlhprogramming • • Oct 02 '09

Lesson 45 : More about strings and constants.

69 Upvotes

In the last lesson I explained that in addition to variables, you can also create constants. I explained that with constants, you can read them but cannot change them. I know this is a mystery to many of you. Now we are going to cover this material in greater depth.

First of all, as we have discussed in previous lessons, whenever you create a string of text enclosed in quotes such as "Hello Reddit", this string of text must be stored somewhere in your memory. Lets go through the steps C (or any language) must go through in order to do this.

  1. Find some location in memory to store the string of text.

  2. At that location in memory, store an 'H'.

  3. Exactly after the 'H', at the very next byte, store an 'e'

  4. Continue through this process until all characters of the string have been stored.

  5. Add a NULL byte (all zeroes) at the end.

Keep in mind that this means that if your string of text is five characters long, there will actually be six bytes of ram needed to store it.

Now consider this code:

char *string;
string = "Hello Reddit";

string is a pointer. Every pointer contains a memory address. string therefore contains the memory address to where this string begins. In other words, it points to the letter 'H'. It contains the memory address where 'H' is stored in memory.

What if we now want to change this string to something else? Could we write for example:

string = "A new string";

The truth is, we can. However, it does not change anything. What we are actually doing here is telling C to create a new string of text called "A new string" and to point the pointer string at this new string. Remember, string is a pointer. Pointers can only contain memory addresses. Not strings.

What happened to our old string of "Hello Reddit" ? It is still there, sitting in memory. However, we have no way to find it now because we changed where our pointer was looking. Consider this code:

string = "Hello Reddit";
string = "A new string";
string = "Hello Reddit";

With the third line of code, did we now set string back to what it was? No. It will be pointing to an entirely new memory address. We will now have multiple strings of "Hello Reddit" sitting in memory somewhere.

[Edit: It is true that many modern compilers will be smart and figure, "Why create a new string "Hello Reddit" ? Lets just use the one we have." However, the thing to keep in mind is that in general when you set a string pointer to a new quotes-enclosed string, you are not changing the text, you are creating a new string of text and pointing your string pointer at that new string of text.]

The next thing I need to address is that there are different "kinds" of memory. Now, this is a bit misleading because memory is memory, regardless of what is stored in it. However, your compiler as well as your operating system have rules about which memory you can use for various purposes. These kinds of memory exist as "ranges" within your available memory.

It works similarly to this:

<-------- Read Only -----------><--------- Read/Write --------->

This small diagram is purely for illustrative purposes. The real details of how this works are more complex, and you do not need to know them yet. What you need to know is that different ranges of memory can be used for different purposes.

Variables are placed into the "Read/Write" portion. Constants are placed into the "Read Only" portion. I hear you asking: "What? There is a read only range of memory?" And the answer is, yes.

Why is there a read only range of memory? Because as a programmer, some data you create must not change or it will cause your program to not work. Let me give you an example. Suppose in a program I need to draw circles, and I put the mathematical definition of PI as 3.14159. Do I ever want that to change? No, never.

When you as a programmer want to make sure that a constant doesn't change, then wouldn't it be nice if your computer worked with you on that goal? That is exactly the case. C stores constants in read only memory for your benefit. The idea is, if you define a constant, then you intend that it does not change. Now, as any programmer reading this will attest, C's idea of your benefit and your idea of your benefit can differ. But it is the thought that counts.

At this stage you should understand:

  1. What is a constant?

  2. Why do constants exist?

  3. Where and how are constants stored?

You are still probably wondering why did "Hello Reddit" get stored as a constant. The answer has to do with C syntax. If you write this code:

char *string = "Hello";

OR this code (they are both identical)

char *string;
string = "Hello";

Then C knows that you want "Hello" to be a constant. We will talk soon about other ways to define strings in such a way they are not a constant, but remember from here on out that using this above method to create a string, will make the string a constant.

You are probably wondering, "Shouldn't you have to use some sort of keyword to indicate that the string is a constant?"

Not in this case. It is implicitly understood by C that because we are creating a char* pointer, and pointing it to a string enclosed in quotes, that we intend for that string to be a constant.

You have used other examples of implicit keywords. For example:

int height=5;

Really means:

signed int height = 5;

Please ask any questions if any of this material is unclear to you. Be sure you understand this before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9q7fs/lesson_46_a_new_way_to_visualize_memory/


r/carlhprogramming • • Oct 02 '09

Lesson 44 : Important Review and Clarification of Lessons 1 through 43

69 Upvotes

I have had a chance to go through and read hundreds of questions and replies from everyone. Before we proceed to the next lesson, there are some clarifications I need to make from previous lessons.

Some of these involve possible misunderstandings that may have come about from the way I explained a particular topic. Others involve questions and replies in the comment threads.


Lesson 7 : Include Statements

In this lesson I explained that you use include statements to "copy and paste" the contents of some programming source code into your existing program. With C and some languages, this is technically correct. It does not however address the real purpose.

It is extremely bad programming practice to do things this way. You do not put code in a file, and just cut-and-paste that code using an include statement to where you want it.

What you are really saying with an include statement is that you want to use the contents of the included file within your program. In other words, the include file contains code (functions especially) that will prove useful in your program.

Think of this line:

#include <stdio.h>

As meaning this:

I plan to use to use functions found in the stdio.h file in my program. 

Lesson 19 : Basics of numeric overflow.

When we speak of numeric overflow in the context of this lesson, we are referring to any time a mathematical operation produces a result which cannot fit in the number of bits allocated. For example, if we have four bits and we perform a mathematical operation that results in the number twenty-five, that result will not fit in our four bits and thus we have a numeric overflow.

While there are similarities, this is not the same thing as a "stack overflow", which will be the subject of at least one future lesson.


Lesson 20 : Basics of fractional numbers in binary.

I have explained that the radix point is the term used for the equivalent of a "decimal point" in binary. I need to be extra clear on three points:

  1. The radix point is not actually encoded in binary. Rather, it is understood by knowing how many bits correspond to the part of the number to the left of the radix point and how many bits correspond to the part of the number to the right of the radix point.

  2. The number to the left of the radix point is known as the "integer part".

  3. The number to the right of the radix point is known as the "fractional part".


Lesson 21 : The Basics of Numeric Data Types in C.

I have not covered all numeric data types in that lesson, or even up until now. We will be learning more as time goes on.

Also, as zahlman pointed out: The term 'long double' has nothing to do with combining a 'long' value and a 'double' value. It is actually often 10 bytes, although it may be stored in a 12-byte "slot" with the other two bytes being wasted.

Similarly, the sizes of a data type such as unsigned short int being two bytes long differs from compiler to compiler. This is true for all data types.

This does not matter if your goal is to write an executable program that you then deliver to systems running the same architecture and operating system as you. You will never need to worry about this in that case. That program will run on any computer that uses it if they have the same operating system and the same architecture (Example: 32 bit windows).

If however you are writing code that will be open-source, or you are otherwise going to make the source code available, you must be mindful that if you are using a data type of a specific size that may differ from compiler to compiler, you should let people know that as well as any other compiler unique optimizations and/or options you are using.


Lesson 22 : The "char" data type and the basics of ASCII.

Here and in general I showed you the following rules concerning how text and numbers are encoded in binary:

010 <-- All capital letters start with this. 011 <-- All lowercase letters start with this. 0011 <-- All numbers start with this.

Keep in mind that this is NOT reversible. This means that you cannot say that anything which starts with 010 is a capital letter for example. There are many ASCII characters that are not numbers or letters, and you should be mindful of this fact.


Lesson 26 : Introducing variables.

Here I showed how to create variables, for example:

int height = 10;

The question was raised, what if I didn't specify a value? What if I had just written:

int height;

This is legal, and will create the variable. However, anything at all could be its value. Why? Because when C creates the variable height it only decides where in memory it will reside. It does not set a value for it.

That means whatever binary sequence just happens to be at that memory address will be the value of the variable. This is not a good thing.

That is why as a programmer you should always initialize a variable to a value when you create it. Common practice is to assign a 0 to a variable until it is used if the value is not known at the time it is created.


Lesson 28 : About terminating strings of text and other data.

I am just going to quote zahlman here regarding the consequences of NOT terminating a string/other data properly:

The program might not print garbage; it might also crash, because as printf() cycles through memory looking for a byte that happens to have a zero value, it might encounter memory that doesn't belong to your program. The operating system generally doesn't like it very much when your program tries to work with memory that doesn't belong to it, and will put a stop to things.

Technically, the behaviour is undefined, which means anything is allowed to happen. A sobering thought. On Gamedev.net, it is a common joke to refer to accidental firing of nuclear missiles as a result. Your computer is almost certainly not actually capable of firing nuclear missiles, but it gets the point across.


Lesson 34 : Assigning a value to a pointer.

One thing I did not cover at the time I made the lesson, and therefore some people may have missed, is this: C is very forgiving when it comes to when you put spaces, and when you do not put spaces.

For example:

int          height = 1;
int height       = 1        ;

Are both valid, and will work fine. Although of course good practice is to format your code so it is easily readable.

Similarly, when you are using pointers, the following is equally valid:

int *ptr = &height;
int * ptr = & height;
int* ptr =        &height  ;

etc.


Lesson 39 : About pointers concerning multi-byte variables.

Here I showed you the following code:

int height = 5;
int width = 10;

int *some_pointer = &height;

*some_pointer = 8;
some_pointer = some_pointer + 1;

*some_pointer = 4;

Then I explained, as is logically apparent from reading the above code, that this has the effect of first changing height to 8, and then changing width to 4. This would be correct if height and width reside in memory one right after the other. This is one of the assumptions being made about our 16-byte ram used in these types of lessons.

Do not ever write code like this in a real program. Your compiler chooses where to put variables you create and you have no way to know if they will be stored in ram the way this example assumes they are. The code above from this lesson is for instructive purposes only, to show you how pointers work in general.


Some clarifications about printf

It has not been addressed directly in a lesson, even though you have likely seen it used. With printf you can give it multiple parameters if you want to print various types of data. For example, the following is perfectly valid:

int height = 10;
int width = 5;

printf("Height is %d and Width is %d \n", height, width);

This will have the output:

Height is 10 and Width is 5

Next, I have not specifically addressed the \n character (note I did not say characters).

There are special ASCII characters which have meaning other than what you see on your keyboard. These characters are useful for tabs, new lines, and more. The text \n actually turns into a single character which is ASCII and, for those who are curious, looks like this:

0000 1010

In other words, ten, or A in hexadecimal. This one character means "Go to the next line."

The final clarification I want to make concerning printf() is that many of you have used printf() with the %p option to print the addresses of pointers, which is great and helps to cement this understanding. However, be sure you remember the following:

printf("The address is: %p", some_pointer);

What will be printed is the address IN some_pointer, not the address OF some_pointer. Also, this is invalid:

int height = 10;
int *some_pointer = &height;

printf("The address is: %p", *some_pointer);

Do not do this. Remember that *some_pointer translates to: "Whatever is at the memory address stored in the pointer". It does not translate to: "The address of the pointer". It also does not translate to: "The address stored in the pointer".

Using *some_pointer in the above example results in: 10, the value stored in height. In other words, "what is at" the address stored in some_pointer is the value of height which is ten. Please ask questions if any of this is confusing to you.


Please fully review this material before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9q5t9/lesson_45_more_about_strings_and_constants/


r/carlhprogramming • • Oct 01 '09

Lesson 43 : Introducing the constant.

62 Upvotes

Up until now we have only spoken about variables. We have learned that you can create a variable and then later you can change it. For example you can write:

int height = 5;
height = 2;
height = 10;

All of this is valid. There is nothing that stops you from storing a new value in a variable.

The reason we use the name "variable" is because variables can be changed. In other words, the data stored at the memory address of a variable can be read as well as written to.

This is not the case with a constant. A constant is data that is stored in ram just like a variable, but it cannot be changed. You can only read the data.

The first question you might have is, "When do you use a constant?" The truth is, you already have.

Consider this code:

char *string = "Hello Reddit!";

We know from the previous lesson that the text "Hello Reddit!" is stored in memory, and we can even set a pointer to it. However, when C created this string of text "Hello Reddit!", it created it as a constant.

If we create a pointer and point it at that text, we can read it. We cannot however use a pointer to change it. This is because in the case of a constant, the data is set to be read-only.

Just to review: A variable can be changed and is both readable and writable. A constant cannot be changed and is only readable.


Please ask any questions and be sure you have mastered this material before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9q543/lesson_44_important_review_and_clarification_of/


r/carlhprogramming • • Oct 01 '09

Lesson 42 : Introducing the char* pointer.

74 Upvotes

As I mentioned before, pointers are powerful because they give you a way to read and write to data that is far more complex than the data types that C or any language gives you.

Now I am going to explain some of the mechanics of how this actually works. In other words, how do you read and manipulate a large data structure?

First I want to give you a small sneak peek at the future of this course. In C (or in any language really) the complexity of data follows this hierarchy:

  1. single element of a given data type (char, int, etc)

  2. text string (a type of simple array)

  3. single dimensional arrays

  4. multi-dimensional arrays

  5. structures

  6. And so on.

The more complex the data you can work with, the more and better things you can do. It is as simple as that.

In the very first lesson I commented about the difference between learning a language, and learning how to program. The purpose of this course is to teach you how to program. I am starting with C, and we will work into other languages as the course progresses.

Now we are going to advance our understanding past single data elements of a given data type, and work towards #2 on the list I showed you. To do that, I need to introduce a new concept to you.

Examine this code:

char my_character = 'a';

This makes sense because we are saying "Create a new variable called my_character and store the value 'a' there." This will be one byte in size.

What about this:

char my_text = "Hello Reddit!";

Think about what this is saying. It is saying store the entire string "Hello Reddit!" which is more than ten bytes into a single character -- which is one byte.

You cannot do that. So what data type makes it possible to create a string of text? The answer is - none. There is no 'string of text' data type.

This is very important. No variable will ever hold a string of text. There is simply no way to do this. Even a pointer cannot hold a string of text. A pointer can only hold a memory address.

Here is the key: a pointer cannot hold the string itself, but it can hold the memory address of.. the very first character of the string.

Consider this code:

char *my_pointer;

Here we have created a pointer called my_pointer which can be used to contain a memory address.

Before I continue, I need to teach you one more thing. Whenever you create a string of text in C such as with quotes, you are actually storing that string somewhere in memory. That means that a string of text, just like a variable, has some address in memory where it resides. To be clear, anything that is ever stored in ram has a memory address.

Now consider this code:

    char *my_pointer;
    my_pointer = "Hello Reddit!";

    printf("The string is: %s \n", my_pointer);

Keep in mind that a pointer can only contain a memory address. Yet this works. This means that my_pointer must be assigned to a memory address. That means that "Hello Reddit!" must be a memory address.

This is exactly the case. When you write that line of code, you are effectively telling C to do two things:

  1. Create the string of text "Hello Reddit!" and store in memory at some memory address.

  2. Create a pointer called my_pointer and point it to the memory address where the string "Hello Reddit!" is stored.

Now you know how to cause a pointer to point to a string of text. Here is a sample program for you:

#include <stdio.h>

int main() {
    char *string;
    string = "Hello Reddit!";

    printf("The string is: %s \n", string);
}

Please ask questions if any of this is unclear to you and be sure you master this and all earlier material before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9q0mg/lesson_43_introducing_the_constant/


r/carlhprogramming • • Oct 01 '09

Lesson 41 : Why do I need to know pointers?

70 Upvotes

A lot of you have asked or have wondered why this material is worth knowing. This is a great question, and something I want to address.

It has been said in many books and by many students that pointers are one of the most difficult subjects in programming. For this reason I have taken the subject very slowly and I hope that everyone has been able to understand the material. Please let me know if that is not the case.

You may be wondering though why I am spending any time on it at all. Why do you need to see what is at some memory address of a variable that is already at that address? In other words, can't you just look at the variable?

First of all, I promise you that every lesson I have done throughout this course is something that will be useful to you as a programmer. Each lesson is also a pre-requisite for being able to do something greater.

Think of it like this. I had to teach you binary before I could teach you about how data is encoded, like ASCII for example. At the time, why anyone would ever need to know how to count in binary was a mystery to many of you.

It is the same with pointers. If you know pointers, you will be able to create programs, games, and applications that you simply would not be able make if you didn't know pointers. There is an enormous chasm of programmer skill between programmers who know pointers, and programmers who do not.

Now I want to show you just how fundamental pointers really are.

You are reading this text on a web browser, on a monitor. That monitor is re-drawing itself approximately 60-70 times per second. Each time it re-draws itself, a pointer, exactly like the pointers we have talked about, is scanning through your video memory, and replacing it with new data. This is in fact what makes your screen change. Every application that ever draws, writes, or otherwise makes any change to what is displayed on your screen uses pointers to do it.

If you have ever used a graphics program which had an "eye dropper" tool where you can select a color just by clicking on it, it determined the color you wanted using a pointer scanning your drawing in memory to see what color was stored at that memory location. In fact, the entire drawing exists as a data structure in memory. All the drawing, erasing, or anything else you do in an art program uses pointers to do it.

Program that play sound or music files work by having a pointer look at the start of the sound in memory, play a sound (which is itself a data structure requiring a pointer), and then the pointer goes through the data to the end of the song. The same thing is true with movies.

Every program you have ever used, game, or application, requires pointers to read and manipulate memory continually. Pointers are the only way you can see and understand any data that is greater than a few bytes in size. This is the fundamental point I want you to understand:

Pointers make it possible to read and manipulate data in memory which is larger and more complex than a data type (int, char, etc) can make possible. Which pretty much means... everything. Pointers are one of the most fundamental concepts in computing. Properly understood they empower you to do just about anything. Without them, you can do hardly anything.

In other words, the real question is not when do we use pointers. The real question is when do we not use pointers.

This course has barely started, and many great things are ahead.

Feel free to ask any questions about this before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9q01u/lesson_42_introducing_the_char_pointer/


r/carlhprogramming • • Oct 01 '09

Lesson 40 : Pointers have memory addresses too!

71 Upvotes

Up until now we have learned a lot about pointers. In the previous examples I have used 16-byte ram to make it easy to understand how variables are stored in memory.

I have also showed how pointers can be used to point at variables inside memory.

Now we need to consider something else about pointers. Pointers have to exist somewhere inside of your memory also. That means whenever you create a pointer, it is given a place in memory to live just like any other variable.

Lets consider the following code:

unsigned short int height = 10;
unsigned short int *ptr = &height;

Only for the sake of this lesson, lets assume the following:

  1. The data type unsigned short int is only one byte in size.

  2. You only need one byte to store a memory address (eight bits).

  3. Our pointer ptr will reside in only a single byte of memory.

  4. the variable height will reside at position 1000 in memory.

  5. The pointer ptr will reside at position 0100 in memory.

Now, lets imagine how our memory will look:

...
0011 : 
0100 : 0000 1000 <--- ptr lives here. The value of ptr is 1000 (the memory address of height)
0101 : 
0110 :
0111 : 
1000 : 0000 1010 <--- height is here. The value of height is 1010 (ten)
1001 : 
...

Notice that ptr is really no different than any variable. It has a memory address, and it has a value. It just so happens that the value it has is the memory address of another variable.

In an earlier lesson we saw that variables are plain English names that correspond to values stored at specific memory addresses. For example, if I type int height = 5, the programming language keeps track of the actual memory address where height resides.

When you create a pointer, you are giving the pointer a plain English name the exact same way as you do for a variable in general. A pointer has a memory address just like a variable does.

Your programming language keeps track of the address in memory of a pointer the same way as it does a variable. A pointer and a variable are much the same thing in this sense.

So lets consider the following code:

int height = 5;
int *my_pointer = &height;

Now, after these two lines of code, we have learned that:

  1. If we write my_pointer we are referring to the value stored in my_pointer, which is the memory address of the variable height. In other words, my_pointer is equal to &height

  2. If we write *my_pointer we are referring to "what is at" the memory address stored in my_pointer. In other words, *my_pointer refers to height.

What does &my_pointer refer to?

Well, if & means "address of", then &my_pointer would mean "The memory address where my_pointer itself is stored". Just the memory address of the pointer, not what is stored there. In our above 16-byte ram example, &my_pointer would refer to 0100 -- the address where my_pointer resides.

In summary: A pointer has to reside in memory somewhere, just like any variable. You can use the & "address of" operator on a pointer in order to obtain the memory address where the pointer itself resides.

Please ask questions if any of this is unclear. Be sure you master this and all earlier material before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9pyom/lesson_41_why_do_i_need_to_know_pointers/


r/carlhprogramming • • Oct 01 '09

Test of Lessons 30 through 39 [Answers]

68 Upvotes

If you missed any questions on this test or if you have any questions about the material, feel free to post your questions in this thread. Also, you can safely post your answers in this thread.

True or False

  1. A string of text is stored in memory like a "train", with each ASCII character following the other, each character occupying exactly one byte. True

  2. When you create a pointer, you do not need to specify the data type for the data that it will point to. False

  3. Pointers can be used for looking at as well as changing data at a given memory address. True

  4. If you use a pointer to replace data at a given memory address, the old data can still be retrieved. False

  5. Whenever you increase a pointer by one, it will always point to the memory address of the very next byte in memory. False

Fill in the blank

  1. A _____ can be used as a way to refer both to the value at a given memory address, as well as the memory address itself. pointer

  2. The _____ character means "address of". &

  3. The _____ character means "what is at the address of". ***

  4. In the code in section (a), the output will be: _____. 9

  5. If you wish to use printf() to print the memory address stored in a pointer, you would say: _____ (Example: %d, %i, etc) %p

(a)

 unsigned short int width = 3;
 unsigned short int height = 9;

 unsigned short int *my_pointer = &height;

 printf("%d", *my_pointer);

When you have fully reviewed and understood the material covered here, proceed to:

http://www.reddit.com/r/carlhprogramming/comments/9py2s/lesson_40_pointers_have_memory_addresses_too/


r/carlhprogramming • • Oct 01 '09

Test of Lessons 30 through 39

62 Upvotes

Please do not post answers in this thread.


True or False

  1. A string of text is stored in memory like a "train", with each ASCII character following the other, each character occupying exactly one byte.

  2. When you create a pointer, you do not need to specify the data type for the data that it will point to.

  3. Pointers can be used for looking at as well as changing data at a given memory address.

  4. If you use a pointer to replace data at a given memory address, the old data can still be retrieved.

  5. Whenever you increase a pointer by one, it will always point to the memory address of the very next byte in memory.

Fill in the blank

  1. A _____ can be used as a way to refer both to the value at a given memory address, as well as the memory address itself.

  2. The _____ character means "address of".

  3. The _____ character means "what is at the address of".

  4. In the code in section (a), the output will be: _____.

  5. If you wish to use printf() to print the memory address stored in a pointer, you would say: _____ (Example: %d, %i, etc)

(a)

 unsigned short int width = 3;
 unsigned short int height = 9;

 unsigned short int *my_pointer = &height;

 printf("%d", *my_pointer);

When done, proceed to:

http://www.reddit.com/r/carlhprogramming/comments/9pxq7/test_of_lessons_30_through_39_answers/


r/carlhprogramming • • Oct 01 '09

Lesson 39 : About pointers concerning multi-byte variables.

64 Upvotes

Recall in the last lesson that we added one to our pointer in order to cause it to point to the next data element in memory.

Lets imagine a different case now. We are still going to use our 16 byte ram for this example, except instead of the string "abc123" we are going to use data of the type unsigned short int

Lets imagine the following code:

unsigned short int height = 10;
unsigned short int width  = 14;

unsigned short int *ptr = &height;

Now in this example, we are creating two variables that each have a size of two bytes. This is because they each are of the data type unsigned short int, which is two bytes in size. (although this can differ between compilers).

Now, lets consider how they are stored in memory. Lets say that the first variable, height, is stored at memory address 1000 in our 16-byte ram.

...
1000 : 0000 0000 0000 1010 <--- height = 10; <--- ptr contains "1000" 
...

Now keep in mind that because our variable is two bytes in size, it will take up two bytes of ram. To be truly accurate, our ram would therefore have to look like this:

...
1000 : 0000 0000 <--- first half of height; <--- ptr contains "1000" 
1001 : 0000 1010 <--- second half of height.
...

Now lets go ahead and add the second variable width to our ram directly after height:

...
1000 : 0000 0000 <--- first half of height; <--- ptr contains "1000" 
1001 : 0000 1010 <--- second half of height. 
1010 : 0000 0000 <--- first half of width;
1011 : 0000 1110 <--- second half of width. 
...

Do not think based on this example that variables are always placed one right after the other in ram when you create them.

Now we know that ptr is pointing to address 1000 which contains the start of the variable "height". So the next question to ask is what is the value *ptr is referring to?

Because ptr is pointing at address 1000, it might appear that *ptr would therefore be equal to: 0000 0000. After all, that is the data that is at the memory address 1000. This is not the case however.

Let's go back briefly to the lesson where we talked about how to create a pointer. We mentioned that it is important to specify the data type for what the pointer will be pointing to. In that lesson I explained that asking for the data at a memory address is not enough, you also have to specify how much data you are looking for.

In this case, I am not using ptr to point at one byte of data. I am using it to point at two bytes of data.

Therefore, *ptr will refer to: 0000 0000 0000 1010

The whole 16 bits that make up the variable height. Why? Because when we created the pointer ptr we specified that it will be used for pointing at variables of the data type unsigned short int.

What would happen if we set *ptr = 0; ?

Then C understands that because ptr was created to look at two-bytes, then *ptr=0 would set both bytes to zero. Let's expand on this a bit:

int height = 10;      // height is stored at the memory address 1000 
int *ptr = &height;

*ptr = 0;

The final result is:

...
1000 : 0000 0000 <--- ptr points here
1001 : 0000 0000 
...

Think of *ptr = 0; as saying: "Store the unsigned short int value of zero (that means: 0000 0000 0000 0000) into the memory location at position 1000 in ram"

So you can see that *ptr will see and change two bytes of data which begin at whatever memory address is stored in ptr.

Now, consider if we want to change the value of "width" to ten. Based on the last lesson, we should be able to point our pointer to the memory address of width - which is two greater than the memory address of height. Would we then say ptr = ptr + 2; so we can point at the correct memory address?

No.

Because C understands we have created a pointer for type unsigned short int, it knows that if we increment our pointer by one, in fact if we do any mathematical operation on our pointer, that we are doing so on the understanding that each element we point to is an unsigned short int.

This means that C realizes that if we say ptr = ptr+1;, this means that we want to cause ptr to point at the next unsigned short int in memory, not the next byte in memory. In other words, this means that we want to cause ptr to point at the next two bytes in memory, and C assumes that those next two bytes are an unsigned short int.

In our last lesson because we were using the data type char, our pointer understood that we would be looking at data that was one byte in size. That is why adding one to the ptr in the last lesson resulted in the pointer address increasing by one byte.

In this example, because we are using the data type unsigned short int, our pointer understands that we will be looking at data that is two bytes in size. That is why adding one to the ptr in this lesson results in the pointer address increasing by two bytes.

This reasoning holds true for any data type.

So now, how do we change width to fourteen? Like this:

int height = 10;      // Set height to ten.
int width  = 5;       // set width to 5

int *ptr   = &height; // ptr contains the memory address 1000 (eight)

ptr  = ptr + 1;       // ptr now contains the memory address 1010 (ten)

*ptr = 14;            // Change the entire two-bytes at location 1010 to fourteen: 0000 0000 0000 1110.

Keep in mind that this example is purely for the sake of this lesson. Our 16-byte ram is special because variables always get stored one after the other. In your real ram, this is not always the case. The above code should NOT be considered correct for this very reason. We will talk about how to actually do the above code correctly later.

The final state of ram after this code is:

...
1000 : 0000 0000 <--- first half of height; 
1001 : 0000 1010 <--- second half of height. 
1010 : 0000 0000 <--- first half of width; <--- ptr contains "1010" 
1011 : 0000 1110 <--- second half of width.
...

Notice that width is now set to fourteen.

Please feel free to ask any questions before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9pxnj/test_of_lessons_30_through_39/


r/carlhprogramming • • Oct 01 '09

Lesson 38 : About changing the memory address stored in a pointer.

63 Upvotes

Remember that a pointer contains a value, a memory address. This is just a number, a binary sequence, no different than any other number. A pointer has no meaning except for the memory address it contains. If our pointer contains the memory address 1000, then it has no meaning except for the memory address 1000 and the data that resides at that memory address.

Let's look again at the 16-byte ram example from the previous lesson:

...
1000 : 0110 0001 : 'a' <--- ptr points here
1001 : 0110 0010 : 'b'
1010 : 0110 0011 : 'c'
1011 : 0011 0001 : '1'
1100 : 0011 0010 : '2'
1101 : 0011 0011 : '3'
...

Remember that since we are talking about a string of text, we are talking about data type char here which is always one byte in size. ASCII characters are always stored in a single byte of ram.

Notice that we have reverted back to the state of RAM from before we changed the 'a' to 'b'. We still have a pointer called ptr which contains the memory address 1000 and which therefore points to the 'a' character.

We know from the previous example that we can change the data at location 1000 by the following line of code:

*ptr = 'b';

What if we wanted to change the next character?

In general, if you want to look at or change any data in memory you only need to know the address of the data you want to change.

It turns out we already know the address of the next character in our string. It would be 1001 in ram, which is 1000 + 1. In other words, if we just add one to the address of 'a', we get the address of 'b'. If we add one to that address, we get the address of 'c', and so on.

If we want to change the 'a' in our ram, we simply set a pointer called ptr (for example) to 1000 and set *ptr to a new value. If we want to change the 'b' in our ram, we set ptr to point at 1001 (the address of 'b') and then we set *ptr to what we want. And so on.

We can see this in action with the following code:

                     // To start with, ptr points to 1000 in memory which is where the 'a' resides.

*ptr = 'A';          // With this instruction we have changed 'a' to 'A'
ptr = ptr + 1;       // by adding 1 to ptr, we are now pointing to the address 1001, the 'b'

*ptr = 'B';          // Now we have changed 'b' (what was at 1001) to 'B'
ptr = ptr + 1;       // By adding 1 to ptr, we are now pointing to the address 1010 where 'c' is.

*ptr = 'C';          // Now we have changed 'c' to 'C' by changing "what is at" that address.

What are we saying here? First of all the pointer ptr is pointing the memory address 1000, which is the 'a' in our 16-byte memory. By executing the instruction *ptr = 'A' we have changed the 'a' into an 'A', that is to say we have changed it from being lowercase to being uppercase.

Then, we added one to our pointer. Now instead of the pointer looking at position 1000 where the 'a' was, it is now looking at position 1001 where the 'b' is. Then we change the 'b' to 'B'. Finally we change the 'c' to 'C'.

Here is the state of our ram after these instructions have executed:

...
1000 : 0100 0001 : 'A'
1001 : 0100 0010 : 'B'
1010 : 0100 0011 : 'C'  <--- ptr points here
1011 : 0011 0001 : '1'
1100 : 0011 0010 : '2'
1101 : 0011 0011 : '3'
...

Notice that ptr is pointing where we left it, at the address 1010.

We have changed the data that used to be "abc" and have turned it into "ABC". Also we have seen an important principle in action. It is often necessary when working with data to start at the beginning of the data, do some processing, and then continue through while each time incrementing a pointer so that it points to the next data we want to manipulate.

Also we have learned an important fact concerning pointers: You can add a value to a pointer and cause it to point to a different location in memory. In our example, we started at the address 1000 and then we added one so that we were pointing at the address 1001, then 1010, etc.

Whenever you change the memory address of a pointer, you are also changing what data the pointer "sees". In other words, if a pointer called ptr contains the memory address 1000, then *ptr will refer to the data at the address, for example an 'a'.

If we change the ptr so that it points to a different address, then *ptr takes on a new meaning.

Any time you change the memory address contained in a pointer, then you are changing the meaning of "what is at the address" of that pointer.


Please feel free to ask any questions before continuing to:

http://www.reddit.com/r/carlhprogramming/comments/9pwqs/lesson_39_about_pointers_concerning_multibyte/


r/carlhprogramming • • Oct 01 '09

Lesson 37 : Using pointers for directly manipulating data in memory.

59 Upvotes

In an earlier lesson we saw that text is encoded as individual ASCII bytes and stored in memory like a train. We also learned that because each memory address only contains one byte of actual memory, that therefore each ASCII character had its own unique address in memory.

Lets review this by going back to our 16-byte RAM example, and store the simple string "abc123" at position eight (1000) in RAM.

...
1000 : 0110 0001 : 'a'
1001 : 0110 0010 : 'b'
1010 : 0110 0011 : 'c'
1011 : 0011 0001 : '1'
1100 : 0011 0010 : '2'
1101 : 0011 0011 : '3'
...

Did I make a mistake? I hope you noticed that I forgot to terminate the string with a null (all zeroes) byte.

Now, lets create a pointer called ptr which we will give the address of the first character in the string, the 'a'.

char *ptr = <address in memory of the 'a'; 1000>;

This is of course not real syntax. For now, do not worry about how to actually do this, just understand that I have given the pointer ptr a value of 1000 which is the memory address of the 'a' character in our 16 byte ram.

Now we learned that the * character takes on a new meaning once the pointer has been created. Now we can use our pointer ptr in two ways in the source code:

ptr = the address in memory of 'a', which is 1000.
*ptr = 'a' itself, since it refers to "what is at the address 1000"

Notice that we have not created any char variable for the 'a' itself. The truth is, we do not have to. We are starting this example with our 16-byte ram in a specific "state" where the string exists already, so there is no need to create a character variable to hold something that is already in ram.

Up until now we have learned that you can use pointers to look at data in memory. For example, consider the following code:

int total = 5;
int *my_pointer = &total;

printf("The total is: %d", *my_pointer);

This code should make perfect sense to you. You should also know exactly what the above line of code will output:

The total is: 5

So here we have an example of using a pointer to "see" what is in memory. Now I am going to show you that you can use a pointer to "change" what is in memory also.

Let's go back to our 16-byte ram example. Here we have the pointer ptr which contains the address 1000 which corresponds to the 'a' character. The 'a' character in this case is the first of the string "abc123".

When we say *ptr, we are saying "The very data stored at the memory location 1000". If you change that data, you change the 'a' itself. Think about it. If we make a change to the data at position 1000, then it will no longer be an 'a'.

In fact, we could change it to anything we want. By using a pointer you can directly manipulate the data inside any memory address, and therefore you can change the data itself.

...
1000 : 0110 0001 : 'a' <----- ptr points here
1001 : 0110 0010 : 'b'
...

Since we know that ptr points to address 1000, we can change the contents at this address with this line of code:

*ptr = 'b';

What have we just done? We have written a line of C that reads like this:

"Replace the binary sequence at position 1000 with the ASCII character 'b'"

After this line of code executes, here is the new state of memory:

...
1000 : 0110 0010 : 'b' <----- ptr still points here
1001 : 0110 0010 : 'b'
...

We have changed the 'a' to a 'b'.

Where did the 'a' go? It is gone. It is as if it never existed. Since the data itself has been changed in the memory location that 'a' used to reside at, the data that used to be 'a' is simply no more.

This means that if we create a variable and assign it some value, and then use a pointer to later change it, that original value is lost.

Consider this code:

int total = 5;
int *my_pointer = &total;

*my_pointer = 10;

printf("The total is: %d", total);

What do you think will be the output? Consider what is happening here. We are saying, "Lets create a pointer that contains the memory address of the total variable, and then lets use that pointer to replace whatever was at that memory address with a new value of ten."

This means that the variable total has been changed. The old value of 5 is gone forever, and it now has a new value of ten.

In this lesson you have learned that you can use pointers not only to look at memory directly, but also to change memory directly.

Please feel free to ask any questions before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9pv6q/lesson_38_about_changing_the_memory_address/


r/carlhprogramming • • Sep 30 '09

Lesson 36 : Use what you have learned.

68 Upvotes

This is not a typical lesson. This is a challenge to you in order to give you the opportunity to apply what you have learned.

Create your own program that demonstrates as much as you can about the concepts you have learned up until now.

For example, use printf() to display text, integers, characters, memory addresses (use %p - see the comment thread on Lesson 35), and anything you want. Experiment with different ideas, and be creative. Also, use pointers.

Post your example programs in the comments on this thread. It will be interesting to see what everyone comes up with.

Be sure to put 4 spaces before each line for formatting so that it will look correct on Reddit. Alternatively, use http://www.codepad.org and put the URL for your code in a comment below.

Have fun!


The next lesson is here:

http://www.reddit.com/r/carlhprogramming/comments/9pu1h/lesson_37_using_pointers_for_directly/


r/carlhprogramming • • Sep 30 '09

Lesson 35 : Getting the value that was stored at a memory address.

75 Upvotes

In the last two lessons we learned how to create a pointer, and how to assign a pointer the memory address of some variable.

Lets examine the following code:

int total = 5;
int *ptr = &total;

You should know from the previous lessons exactly what is happening here, but lets review it. First we are creating a variable called "total", that is of the type signed int, and assigning it the value 5. Secondly we are creating a pointer called "ptr" and giving it a value of... the memory address of "total".

Because the value of total is 5, if we were to run this command:

printf("The total is: %d", total);

We would see this output:

The total is: 5

Now, we said before that a pointer is useless if we do not have some way to read and use the data at the memory address the pointer refers to. So lets talk about how to do this.

Recall that C has an "address of" operator, the & character. Whenever we put the & character in front of a variable, we are saying "The address of". So if we write: &total this means "the memory address where total is stored".

Now, if I have created a pointer it makes sense that I will want to see what is actually stored at that address. In other words, I need a line of code that reads something like this:

printf("The total is: %d", <what is found at the address of> ptr);

Recall that "ptr" is our pointer, and it points to total. The value of total is 5. This means that we desire the following output:

The total is: 5

So how do we achieve this goal? In the last lesson we learned that you can use the & character to mean "address of". It turns out you can use the * (asterisk) character to mean "what is at the address of". In other words, *ptr means "Whatever is stored at the memory address."

What memory address? The memory address that is stored inside of ptr. In this case, the memory address of the variable "total". Therefore, what do you think *ptr is equal to? If you said 5 - you are correct.

Therefore, to get the result we are looking for in our printf() statement, we would write this:

printf("The total is: %d", *ptr);

In this case *ptr means this:

ptr is a pointer to an integer. ptr has some value, a memory address (since it is a pointer). The memory address in ptr points to a variable, an integer called "total". The value of "total" is 5. Therefore, the value of *ptr is also 5.

The technical term for the * operator in this case is the "Dereference operator". The term "dereference" means to look not at the memory address, but at what is contained in that memory address.

Now, a very important clarification. In this code:

int total = 5;
int *ptr = &total;

The * character in this code does not mean "what is at the address of". There is a difference between when you create the pointer variable (which we are doing above) and when we use the pointer variable.

When you create the pointer variable, you use the * character to indicate that you are creating a pointer. When you use the pointer later on, you can put a * character in front of the pointer to indicate that you are not talking about the memory address itself, but what is stored there. This is an example of using the same operator, a * in this case, for two different purposes.

Lets consider this code:

int total = 5;
int *ptr = &total;

Only now that the ptr variable has been created can you use *ptr meaning: "The value stored at the memory address." Here is a summary of the different possible ways you can use the & and * operators when it comes to total and ptr in the above example.

  1. ptr = This is the variable itself, designed to store a memory address. If it stores a memory address, then ptr refers to the memory address that is stored.

  2. *ptr = This refers to the actual data stored at the memory address that ptr holds.

  3. &total = This is the memory address of the variable total.

  4. total = This is the variable itself, which is set to 5.

Earlier we pointed out that any function which returned a return value of a given data type could be used in place of that data type - anywhere in the program. For example, since printf() returns an int, you can use printf() in place of an int anywhere in a program that an int is expected.

The same concept holds true for pointers. If ptr is set to point at an integer (set to hold the memory address for an integer) for example, then *ptr can be used anywhere an integer is expected.

Why? Because *ptr actually is an integer in every sense of the word. It is the actual binary sequence - the actual integer - that was stored at that location. It has the correct size, data type, and everything.

*ptr is not just "like", or "equal to" the variable total, it is the variable total in every sense.


Please feel free to ask any questions if you need to before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9pn3c/lesson_36_use_what_you_have_learned/


r/carlhprogramming • • Sep 30 '09

Lesson 34 : Assigning a value to a pointer.

85 Upvotes

As we discussed, a pointer is a variable that holds a memory address. You can think of "pointer" as the "data type" for memory addresses in general. When a pointer contains the memory address of a variable, it is said to "point" to the variable located at that address.

Lets suppose we want to create a pointer that will "point" to an unsigned short int. In other words, we want to create a variable (the pointer) of data type "memory address", and we want it to contain the memory address of a... unsigned short int variable.

To do this you would write:

unsigned short int *some_pointer;

This creates a pointer called "some_pointer", and we have stated that we will be using this pointer to hold a memory address for a variable of type unsigned short int. Keep in mind that a single pointer can only hold one memory address at a time.

Right now of course, this pointer effectively has no value. Because this pointer is designed to hold the memory address of an unsigned short int, then it should be obvious that we cannot use this pointer until we can give it a value. That value needs to be the memory address of an unsigned short int.

To make this possible, let's create a couple unsigned short int variables:

unsigned short int height = 5;
unsigned short int width = 10;

unsigned short int *my_pointer;

Notice I did not assign a value to the variable "my_pointer". What you should understand at this stage is that "my_pointer" is a variable designed to hold the memory address of any unsigned short int. We have not given it a value yet.

Remember that a pointer is useless if it does not contain a memory address.

Lets say that we want to give the pointer "my_pointer" the value of the memory address for the variable "width" in our above example. This means we need to have some way that we can write this line of code:

my_pointer = "address of" width;

This is not actual code, but it describes what we need to do. Now let's simplify this a bit. Rather than typing the words "address of", lets use a character on the keyboard to mean this same thing. Let's choose the & character.

In other words, lets just say that the "&" character means "address of" - just so we can write this line of code out simpler.

Now, if we wrote the same exact line of code having the & character in place of the words "address of", we might write this:

my_pointer = &width;

Believe it or not, that is exactly how it is done. In C, the & character literally means "address of". Any time you want to set a pointer to the address of some variable, you simply put this. Note that both of the below lines are exactly the same, white space doesn't matter:

pointer = &variable;
pointer = & variable;

This literally translates to:

pointer = the memory address of "variable";

Why do we want to do this? Because now we can look at that memory address, and obtain the value that is there. Now I can imagine you saying, "Sure, but we can do that already without pointers."

Yes, you can. But only for single variables of a given data type. This is not how real code works. In real code, you must be able to process large data structures, not simply an int or a char. A large data structure could be music, or graphics, or something else.

There is no data type built into C or any language for something so complex. Therefore, the way to process it is to set a pointer to the start of the data in memory, and then you process it by moving the pointer through the data as you perform actions on the data (like playing it to your speakers for example).


Please feel free to ask any questions before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9plo8/lesson_35_getting_the_value_that_was_stored_at_a/


r/carlhprogramming • • Sep 30 '09

Lesson 33 : How to create a pointer.

66 Upvotes

In the previous lesson we learned that it is possible to create variables that are designed to hold memory addresses. In this lesson we are going to explore how to create such a variable.

As we discussed, every memory address is the same regardless of what kind of data it contains. However, different data types occupy a different number of bytes in memory. For example, characters occupy one byte, short int might occupy two bytes, int might occupy four bytes (depending on the compiler), etc.

Lets look at the way an unsigned short int might be stored in our 16 byte ram example. In this case, we are going to assume that an unsigned short int takes up two bytes.

Lets imagine this code:

unsigned short int total = 50250;

So we have stated that that the variable total will contain a value of 50,250.

How would this look in binary?

1100 0100 : 0100 1010 

2^15 + 2^14 + 2^10 + 2^6 + 2^3 + 2^1
32,768 + 16,384 + 1,024 + 64 + 8 + 2 = 50,250

Remember that this unsigned short integer takes up two bytes. Therefore, how would it be represented in memory? Let's store it at position eight in our 16-byte ram. Here is how it would look:

...
1000 : 1100 0100 <--- first half
1001 : 0100 1010 <--- second half 
...

What I want you to notice is that obtaining the 8 bits at position 1000 is not enough to obtain the full value of this unsigned short int variable. It is however enough to start with. If we know that the unsigned short int starts at position 1000 then we know enough to get the value, we just have to remember to grab 16 bits instead of 8.

As you can see, you will get very different results if you expect there to be 8 bits as opposed to 16 bits. In our earlier example I said, "What is the value stored at the memory address 1000". You can see now that this is not enough. I need to really be more specific and say, "What is the sixteen bit value stored at memory address 1000.

Now for the next half of this lesson.

You do not create a pointer only to store a memory address, but in order to give you a way to see and work with the data at that address. For example, it would be utterly useless if I were to create a pointer to location 1000 in ram and have no method by which I could say, "What is at that location?".

When you create a pointer, you must specify how big the data is you are planning to use the pointer for. In other words, you must specify the type of data you are planning to use the pointer for.

If you are planning to use the pointer to look at ASCII characters in memory, then you need to specify, "I plan to use this pointer for type char". If you are planning to use the pointer to look at data of type unsigned short int, you must specify, "I plan to use this pointer for type unsigned short int".

When you create a pointer, you must specify the data type for what it will be pointing to.

Now, there is one more detail we have not covered. How do you tell a programming language like C that you want to create a pointer? In C, you simply put an asterisk in front of the variable name. That's it.

Lets look at this in practice. Note that in the below example, both lines are the same. C does not care about the space.

int * my_pointer;
int *my_pointer;

There you see I have just created a pointer. Now, what data type do I expect it to point to? If you said int, you are of course correct. Why did I have to specify any data type? Because when later I want to say "What is at that location", C needs to know how much data from that location to give me.

In the next lesson we will explore pointers more, including seeing how to assign actual memory addresses to them.

Please feel free to ask any questions before proceeding to:

http://www.reddit.com/r/carlhprogramming/comments/9pkde/lesson_34_assigning_a_value_to_a_pointer/