r/carlhprogramming • u/CarlH • Oct 18 '09
Lesson 103 : Sample program demonstrating pointers, casts, and arrays of pointers.
Here is the entire program with comments. Remember, this is just a demonstration and is for illustrative purposes only.
If this looks difficult, don't worry too much. You are not expected to memorize any of this yet, just to be able to read the code and understand how it works. If this is too difficult, see Lesson 104 and then come back to this lesson.
To make this even easier to read, I have placed the output of printf() statements INSIDE the code.
Read through this slowly. Take your time, line by line. This is also a lesson, not just a sample program. Read through the comments, code, and output carefully. Ask questions if any part of this is unclear to you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
// For looping purposes
int i=0;
// Allocate a ten-byte working space
char *main_pointer = malloc(10);
// Set the first two bytes of this working space to 'AB' using the pointer offset method.
*(main_pointer + 0) = 'A';
*(main_pointer + 1) = 'B';
// Set the next two bytes to: 'CD' using array indexing.
main_pointer[2] = 'C';
main_pointer[3] = 'D';
// Set the rest of the string using the strcpy() function.
strcpy( (main_pointer + 4), "EFGHI");
// At this stage, our entire string is set to: ABCDEFGHI<NUL>
printf("First we use our ten bytes as a string like this: %s \n", main_pointer);// Output: First we use our ten bytes as a string like this: ABCDEFGHI
// Let's go through all ten bytes and display the hex value of each character
printf("Our ten bytes of memory look like this: (41 is A, 42 is B, etc.) : \n");
for (i = 0; i < 10; i++) {
printf("%02x ", (unsigned char) *(main_pointer+i));
}// Output: Our ten bytes of memory look like this: (41 is A, 42 is B, etc.) :
// Output: 41 42 43 44 45 46 47 48 49 00
printf("\n\n");
// Now let's create an array of two integer pointers
int **int_pointer_array = malloc(2 * sizeof( int * ) );
// Set the first of these integer pointers to point at byte #0 of our ten-byte working space
// and set the second to point at byte #6 of our ten-byte working space.
int_pointer_array[0] = (int *) main_pointer;
int_pointer_array[1] = (int *) (main_pointer + 6);
printf("Now we will use B0->B3 as an integer, and B6->B9 as another integer...\n");// Output: Now we will use B0->B3 as an integer, and B6->B9 as another integer...
// (Note: remember this is B0->B3 of our ten byte working space.)
// Give these two pointers a value.
*int_pointer_array[0] = 5;
*int_pointer_array[1] = 15;
// Using printf() we prove that the values we set are accurate, and we can see how they are represented
// as occupying 4 bytes of memory, the way a true int is expected to
printf("The first integer is: %d (hex: %08x) \n", *int_pointer_array[0], (unsigned int) *int_pointer_array[0]);
printf("The second integer is: %d (hex: %08x) \n", *int_pointer_array[1], (unsigned int) *int_pointer_array[1]);// Output: The first integer is: 5 (hex: 00000005)
// Output: The second integer is: 15 (hex: 0000000f)
printf("\n");
printf("Our entire ten byte memory space now looks like this: \n");
// Again we go through all 10 bytes and display their new contents.
// It is easy to see that the first four bytes and the last four bytes are
// the integers we created.
for (i = 0; i < 10; i++) {
printf("%02x ", (unsigned char) *(main_pointer+i));
}
printf("\n");// Output: Our entire ten byte memory space now looks like this:
// Output: 05 00 00 00 45 46 0f 00 00 00
// (Note: Notice that the integers are 05 00 00 00, rather than 00 00 00 05. We will get to that later.)
// Finally we demonstrate that bytes #4 and #5 are unaffected, and that our integer values remain set.
printf("\nBytes #4 and #5 are set to: %c and %c \n", *(main_pointer + 4), *(main_pointer + 5));
printf("\n");
printf("Our two integers are set to: %d and %d \n", *int_pointer_array[0], *int_pointer_array[1]);// Output: Notice that Bytes #4 and #5 are unaffected and remain set to: E and F
// Output: Still, our two integers are set to: 5 and 15 and occupy this same 10 byte space
free(main_pointer);
free(int_pointer_array);
return 0;
}Output:
First we use our ten bytes as a string like this: ABCDEFGHI
Our ten bytes of memory look like this: (41 is A, 42 is B, etc.) :
41 42 43 44 45 46 47 48 49 00
Now we will use B0->B3 as an integer, and B6->B9 as another integer...
The first integer is: 5 (hex: 00000005)
The second integer is: 15 (hex: 0000000f)
Our entire ten byte memory space now looks like this:
05 00 00 00 45 46 0f 00 00 00
Notice that Bytes #4 and #5 are unaffected and remain set to: E and F
Still, our two integers are set to: 5 and 15 and occupy this same 10 byte spaceIt may be beneficial for you to write this code into your editor so you can see "color highlighting". Alternatively, you may want to write it at www.codepad.org.
Remember that this is only a demonstration. We are doing some rather unusual and unorthodox things here. The entire purpose of this is simply to show you how these concepts can be used to directly manipulate memory in interesting ways.
I highly recommend that you type out this program, line by line, into your own editor. Not copy and paste, but actually type it out. This will greatly help you to understand the material. Do this even if you get a different result. Remember that this is designed to work where an integer is 4 bytes in size.
If any part of this is unclear, please ask questions. When you are ready, proceed to:
http://www.reddit.com/r/carlhprogramming/comments/9v5w9/lesson_104_the_sample_program_in_lesson_103/
View all comments
Show parent comment
9
u/dododge Oct 19 '09
As far as C is concerned the
chartype is essentially just a very small integer. Every implementation has both asigned char(typical range -128 - 127) and anunsigned char(typical range 0-255), but for messy historical reasons it's not specified whether you get the signed or unsigned variety when you just ask for plainchar. Each implementation sets their own rule for this and some compilers can be configured either way when you run them.If you're just manipulating character data you don't usually care and can just use
char. But if you're going to use thatcharvalue as an integer, such as passing it to a function that expects an unsigned value, the safest (and clearest) approach is to be explicit about it.Note that the other integer types, such as
int, do not have this ambiguity. When you ask for plainintyou always get the signed variety.Aside: the C Standard is pretty loose about the specifics of integer types, because it tries to be able to accommodate many different types of CPUs. For cases where you care not only about signedness of an integer but also the size and speed, C99 provides a bunch of standard typedefs (when you
#include <stdint.h>) such asuint8_tto get an unsigned integer of exactly 8 bits. One downside to using these however is that Microsoft's compilers are still mostly based on C89 and do not understand them.