Skip to main content

Udemy - advanced c programming pointers - Addresses and Indirection

Udemy - Advanced c programming pointers - Addresses and Indirection What is the relationship between a pointer and an array (or string)? Transcription : Arrays in C are actually just sequential data items stored at some location in memory the address of the array is the same as the address of the first item in the array because it is where the array begins. The name of the array that is the name you get to the array variable is also the address of the array.  To explain this let's look at how strings are used in C unlike many other languages. C does not have a dedicated string data type in C A string is just an array of characters for convenience C treats the null character Slash's zero as the string Terminator. When you declare a string variable like this C automatically ODs a null char at the end. Now let's see if we can find where this string is stored in memory. Now here's my program and here you can see that I've just created a string hello world whi...

Udemy - advanced c programming pointers - Addresses and Indirection

Udemy - Advanced c programming pointers - Addresses and Indirection

What is the relationship between a pointer and an array (or string)?

Transcription :
Arrays in C are actually just sequential data items stored at some location in memory the address of the array is the same as the address of the first item in the array because it is where the array begins. The name of the array that is the name you get to the array variable is also the address of the array.  To explain this let's look at how strings are used in C unlike many other languages. C does not have a dedicated string data type in C A string is just an array of characters for convenience C treats the null character Slash's zero as the string Terminator. When you declare a string variable like this C automatically ODs a null char at the end. Now let's see if we can find where this string is stored in memory. Now here's my program and here you can see that I've just created a string hello world which I've assigned to the string array variable. S.T. all one. So let's run this first. It displays the string that is the array of characters of the variable s.t. all one. Then the character at index 0 that is at the first index of the array which is h of hello world. Then I show the address of the array which is this number representing a memory location. Now I get the address the first character remember that I said the address of the array is the same as the address of the first item in the array. Well we can see that's true because the address of the character H which is shown when I use the ampersand address of operator is the same as the address of the string shown when I use the address of operator with the string variable s.t. one. But now look at this last value here instead of using the ampersand to get an address I just display the variable itself. Or one as an integer using percent D in my format string. And this shows the same number which is the address of the array. Now to understand how this works. Let me repeat what I said at the beginning of this lesson because it's really important that you understand this the address of an array is the same as the address of the first item in the array because it's where the array begins and the name of the array that is the name you give to the array variable is also the address of the array. In other words why we may tend to think of arrays as fixed length lists and in many other programming languages that may be all you need to know about arrays. In fact the way your computer and the C language creates and stores an array is a bit different. So remember that an array is really the same as an address in memory that defines the beginning of sequential data items. And when you deal with arrays including strings you're dealing with addresses. And usually when you're dealing with addresses you will be using pointers that's what I'll explain in the next lesson.

How to display pointer values?


Arrays addresses and pointers


Transcription :
Let's now look at how pointers and addresses work and why array's especial in this program I declare to string variables Esti all one under TR two. You can create string variables using either syntax but you need to understand that these two variables are by no means the same as one another. The first SDL one declared with a pair of square brackets is an array second SDR two declared using the store operator is a pointer as we know an array and an address or equivalent. So Esti one is the address at which the array of characters in the string hello is stored. But Esti are two is a pointer whose value is not the string goodbye but the address of that string. So here are two points to the address at which the characters goodbye are stored. This I hope should be clear when I run the program let's do that now. So here you can see the results. Now as you can see when displayed as an integer value the address of all one returned by the address of operator is the same as the value of the variable as TR 1 itself. That's because SDL one is an array and an array is in effect an address but the address of Vestiaire to return by the address of operator is different from the value of the Esti are two variable here the address gives us the location in memory of the pointer variable as too. But the value of that variable is the address of the array of chars to which it points. Let me repeat that because it's important an array variable such as Esti or one is an address. In fact it has its own address an array variable is the address of an array but a pointer variable is not an array it's a variable that stores the address of an array. The pointer variable itself is stored at one address. The array is stored at a completely different address. Think back to the analogy I gave in an earlier lesson where I need to go to a specific warehouse on a road containing many warehouses on my index card you remember I had the address written down. Warehouse 13 of the index card is like a point available. It is not the location which in our example might be the address of an array but it stores a value that is the address that lets me find that location not swat a pointer variable does. Now as for the warehouse itself that is the physical building we can think of that as being like our array variable. Its not just a reference to the location. It is the location go back to my code and be sure that you really understand that SDL one is the location of the start of this array of characters. Hello. In computer memory the address of SDL one is the location where that string of chaws begins. But the value of the pointer variable or two is a number that gives the location of the start of the array of characters. Good bye. In computer memory the address of Vestiaire 2 is the location where the SDR two pointer variable is stored. And if we just want to get the data in the array the address of the pointer variable itself is of no interest to us. The address of pointer variables will however be of interest later on. But for now I'm only interested in the address of the array to which this pointer points the value of SDR too is the address of the array. The address of the first character in the string. Goodbye. In other words the value of the pointer variable refers to all points to the address of the array. If you still finding this confusing try playing around with this code. For example let's try an experiment. I set Esti to a point available to the address of SDR one let me do that now. The simple assignment as TR to Eco's ampersand for address of all one. Run my program so the value of the pointer as TR to is now the address of the array. Hello. So as TR two can be thought of as pointing to the string. Hello let's close down. But instead of assigning the address the string array as TR 1 let's try assigning the array itself. So all I have to do in order to do that is get rid of the address of operator. I make this a simple assignment. Let's see what happens now now well we get exactly the same results as before. That's because as I've said before an array is an address.

Multiple indirection

Transcription :
Up to now I've explained how to create pointer variables that point data items such as integers and characters. In fact a pointer can also point to another pointer. So if for example you have a pointer variable called PIII that points to an integer. You can have another pointer variable called BPI that points to the pointer variable PIII when you use a pointer to access data stored at an address we call it dereferencing or in direction using a pointer to access data referenced by another pointer maybe called multiple indirection. That's because it requires more than one step more than one level of indirection to get out of the data such as an integer character or array that is being referenced. You may wonder why on earth you'd want to do that well multiple indirection can be used when working with lists and arrays. You might have lists of lists that are accessed using pointers to pointers. We see examples of this sort of thing later in this course. Don't worry about that panel though at the moment. All you need to know is how pointers to pointers work. Even if you don't use the use in your own programs you need to be able to understand them. If you see them in other people's program.

Multiple indirection with integrers

Transcription :
Let's start by looking at a fairly simple example of multiple indirection here I declare an array to store three integers where length equals three this loop. Put some values into the array 0 1 and 2 and this loop just prints those values for me to check that everything's correct. Now let's see how I can access those values using both simple indirection is using a pointer to an integer and multiple indirection using a pointer to a pointer to an integer. I warn you in advance that simple as this may seem you'll probably need to stare at this quite a while in order to understand what's going on. Here are my two pointer variables p i. Which is a pointer as the asterisk shows to an int and P PIII which as it's declared with two asterisks All Stars is a pointer to a pointer to an int data is an array of integers as we know. An array is an address. It's the place in memory where a list of data items begins. So I can simply assign not address that array variable data to my point to variable API. Now I assign the address of PIII using the ampersand address of operator to my variable p p. So p p is a pointer which points to the data array and PTI points to the pointer p i.e.. Now this loop iterates from 0 to 1 less than the length of the array. That is the loop runs only while I is less than length. In other words from zero to two and it prints out various bits of information which we look at shortly at each turn through the loop the pointer is advanced to the next element in the array by adding one to the point of variable P-I. This is a simple example of pointer arithmetic which will be explained later in the course. Now let's look at these printf statements before we do that. Let me run the program and see the results so you can see the first print statement prints the array address the percentage. The format specifier is used to print an address as a hexadecimal value in address never changes of course. So we see the same number at each turn through the loop. Next we dereference the int pointer PIII to display the integer at each index of the array. The first turn through the loop PIII points to the start of the array and the first element 0 is displayed in subsequent turns through the loop. The other integers which we added to the array 1 and 2 are shown and now we display the item pointed to by PBI you recall that PBI is a pointer that points to another pointer PIII we assigned the data array to PIII. So remember that an array is an address and at the first turn through the loop we dereference PBI to get the value stored at whatever it points to. It points to the point of variable PIII and that is the address of the data array. So you can see that PBI points to p i.e. which points to the array. The address of the array is shown here so that when we dereference PBI we get the address of the array stored in the pointer PIII in order to go further and get the value pointed to by the pointer. PIII. We need to use this double indirection operator stop stop BPI says. Get the value of what is pointed to by the pointer that p p p points to. So Peepy I points to the pointer PIII and PIII points to an int. So Stass stop PBI gets the value of the int pointed to by PIII at each turn through the loop API is incremented to point to the next element of the array. And when we use double indirection starstuff PBI that returns the value pointed to by API which is the next integer in the array. Now I know this can be hard to follow so let's look at this final printf statement. This displays the address of the integer pointer variable API and the value of the pointer variable PPA. So when you run it you can see that the numbers are the same and they stay the same. But it shows the value stored by the PBI variable is the address of the variable in this program. That address never changes. So the value of pi is the address of the thing it points to. It points to API API points to it. So one level of indirection stop API gets the value of the pointer PIII which happens to be the address of an integer two levels of indirection. Star Star PBI gets the value of PIII that is the data stored at the address pointed to by PIII. And in this program that's the integer 0 1 or 2 at that address. Finally add one more line to clarify this I hope even further. Just copy and paste this in full speed save it and run it again. Now this line prints the value of the pointer PIII which is an address and by indirection stop by. So there we get the integer that stored at that address the address of PIII is incremented at the end of the loop. So the number shown changes on each pass through the loop the value pointed to also changes to if you look back here in the print half where we used to start before the variable. That is two levels of indirection. The value returned is the same value which we got when using one level of indirection with the P variable here. That's because Peepy I points to p. I so one level of indirection goes to p. I on the second level of indirection. Goes to the integer to which P I points as I know I really know that this stuff can be really hard to get to grips with especially if you've never used pointers or on multiple in before and you may need to try out this code sample or write your own and maybe use a debugger to step through it one line at a time. It really is worth the effort though. Once you can understand this you'll have crossed one of the major barriers to understanding how pointers really work.

Multiple indirection with strings


Transcription :
Let's look at another example of multiple indirection this time with an array of strings. Yeah I have a char pointer PC and a pointer to a char pointer PPC. I've declared an array of words to hold a sequence of strings. Remember that in C A string is a sequence of characters terminated by now. So I can declare a string as a pointer to a char that is a pointer to the address of the start of the array of characters in a string. When I initialize a string variable or as a string element in an array C automatically appends a null terminator to that string. The code here assigns my PPC variabilis the pointer to a pointer to the array. That is to the address of the start of the array. In this for loop I iterate through the array of strings and then in this why loop I iterate through the characters in each string printing them out one by one the outer for loop moves the PPC pointer through the array by adding 1 to the array address here. PPC equals words plus one. When I say it moves the point what I mean is that the address that's the number stored by the Point available is updated to a different address. And we can think of this as moving the pointer because the value point available stores determines the address that can be accessed using the pointer at each turn through the follow up. PPC is moved to point to the start of the next string in the array. PCI-E the pointer to char is then also moved to point to the first character of the string pointed to by PPC. I do this by dereferencing the PPC pointer star PPC to access the pointer PC to which PPC points. Now this while loop executes and this runs as long as the char pointed to by P C is not known. Remember I get it. The char itself by dereferencing the pointer by placing an asterisk before it Star b c this printf statement prints the current char Plus a space then the PC char pointer is moved to point to the next char in the current string PC plus because one and I can run it and check that I get the results that I am expecting. So here you can see that is iterated through the array of 3 strings 0 1 2 and printed them out one character at a time separated by spaces which is what I've expected from the loops I've written. Once again if you're new to pointers this code may take some thinking about it to understand exactly how it works and you might find it useful to trace through your code with a debugger. You can use whatever ID you prefer Visual Studio Net beans and so on here I happened to be using code light debug a Windows doctor at the bottom so I could add watches and view the coal. All sorts of other debugging tools might be available in your preferred ID either. So let's have a look at a simple example of how I might trace through this. I could put a breakpoint for example here on this line PC plus equals one in code light. I just double click in the margin and it adds this little break point marker. And now I can view the addresses and values of the pointer variables at each turn through the loops I start the debugger and when it pauses the break point you can see that I can open up the various variable values here in this debugger window and it shows me what the current value is like higher up tracing through and the values change as I carry on debugging. So in order to understand pointers because they really are quite difficult to understand when you are learning how to use them I really advise you to take your time to write some code and use your debugger to see how the pointers work what they're pointing out and how their values change.

Indirection and commandline args


Transcription :
Here's another very common example of multiple indirection you'll often find that the main function of a C program declares the argument or the preceded by two stars as you know that means it's a pointer to a pointer to. In this case a char the OG C argument gives us the number or count of arguments while the ARG the argument is initialized with any arguments passed at the command line the first argument is the program name itself on subsequent arguments. Are any strings entered after the program name. If you want to access the arguments you can simply treat all the as an array and print out the strings in a simple loop and that's what I've done here. But you could equally well iterate through the elements by moving the ARG the pointer Oggy plus because one then using the dereference operator star on the at each turn through the loop to access the current string. Now let's try this out. I should say first of all that your ID may let you enter program arguments in some dialog box Homer for example. In code light I can click my project name and go to settings on here in this dialog. I can add program arguments and that can be useful if you want to set breakpoints and step through your code using a debugger. However command line arguments are probably best tested from the command line itself and to do that you need to open a command prompt system prompt or the terminal window and log into the directory where your programs being built. In this case I'm running Windows and if I see what's in this directory and here I can see that I've got the program executive or command line args not exit. Obviously that would be different on different operating systems. Now let's execute this by entering program name on its own to run the program. And if I execute it without supplying any arguments the executive name is received as the only argument at index 0. Back to the code so you can compare the output with the code shown. But now if I add some arguments in addition to that one separated by spaces 1 to three and executes. Now you can see the output here. So these arguments are received by the main procedure as an array that initializes the ARG the argument and then my code parses them out into individual strings.

Generic pointers


Transcription :
So far reviews are pointers to specific data types such as int and char but sometimes you may want to write code that can deal with pointers to any type of data. For example you may want to write some code that can sort data but you don't want to duplicate that code by writing one function to sort Chas another function to sort integers another for floating points and so on. In that case you can use generic pointers instead of pointers to predefined data types. A generic pointer is written as a pointer to void. And when you use a generic pointer to access some data you must first cast it to a specific data type. Here's a short example. As in previous examples I've created an array of ints this time I've declared the point to GP to be generic so you can see that your void star GP with no particular data type. Now if I scroll down to see my code so here you can see I point this to the data array. No cost is needed here as I'm not yet trying to access any actual data elements. So the data type doesn't matter at this point. Now here I want to print the first integer to do that. I must cast it to a pointer to int that's in style between parentheses. Now I use the dereference operator another asterisk to get the value. That's the Int at this address. And here I moved to the next array index. And again I need to cast the pointer to a pointer to int and I print the second integer. Here let me run this and you can see this is the output I get. So when I run it you can see now how it actually works. The first item in the array of ints zero is displayed. Then after moving the pointer to the second item that is also displayed. So that's the integer 1 there. Close this window. But as g.p is a generic pointer I should be able to use it with other data types not just with integers. So let's see how I can use it with an array of strings. Scroll up my code so you can see that I've I've actually created an array of strings here called words and I've initialized the array with the strings 0 1 and 2. I have already written some code to manipulate not just uncomment it down. Right. So now that you can see here that just as with the array of say once again set my pointer GP to point to an array This is now the array of strings. So you see that here G points GP points first to the array of ants up here and now it points the same pointer points to the array of strings. But remember that an array of strings is in effect an array of arrays of chars because each string is an array of chars. So when I worked with string arrays and previous examples I had to use a pointer to a pointer to char. So here my cost has to be a pointer to a pointer to a char that's char stack style between parentheses. Now I use the dereference operator the single star or asterisk to access the string itself. And then I iterate to the next index again casting to char star star and finally I print the second string and run it again. And you can see the output. There you see the output words array address. First item pointed to is the first string which has the string 0. I moved it to the next item in my code and then it was pointed to the second string which is the string one. So here you can see how using a generic pointer unable to access different types of data with the same pointer and in some programs for example the data type might vary and you don't want to write repetitive blocks of code to handle each data type. Well that ability could be quite useful.

Allocating memeory


Transcription :
When I created arrays and strings in the previous examples I either declared each array all string with a fixed length prior to initializing it like this or I assigned a string at the time of its declaration class. Now in either case the actual size is the amount of memory needed to hold the data is known before I even run my program. The C compiler is then able to set aside the right amount of memory. So I don't get any problems for example by accidentally writing bits of data into some memory that already contains some other data. But what if I need to create an array at runtime. Say for example the user enters a string at the command prompt or some data is read in promise Kyle eyechart NO prior to compiling my code. Exactly how much data are we dealing with. Maybe it'll be a string containing two or three characters or it could be text from a file containing tens of thousands of characters. When I create an array to hold those characters or other types of data I must have some way of calculating how much space in memory I need to hold them all. And then I need to allocate about memory that is I need to get a chunk of memory that can hold exactly the right amount of data only by doing that can I be sure that I won't overwrite some memory that's already been allocated for some other data. Memory corruption like that is a serious bag and it can cause a program to malfunction or to crash. Now let's see how we can handle memory allocation in C.. Or start with a function that receives a string as an argument and returns a string as a result. This function could in principle be sent many different string arguments at different points in the program. So it has no way of knowing in advance how long a string argument will actually be. Of course when I say receives and returns a string. What I mean is that it receives and returns a pointer to a char. So I declare the function return type and the string argument as char star. I've defined a constant mux as steel and to be 100 and within the function I've declared a variable s to be appointed to Achang. And as we know a pointer to a chart may also be a pointer to an array of chars or to put it another way to a chunk of memory that stores the characters of a string. But before I can stuff some characters into memory safely I need to allocate that memory and I do that using the malloc function here. I allocate 100 bytes which is enough for 100 normal alphanumeric characters this assignment begins by initializing a string with novel which creates an empty string. Then I use the SDR cut function to concatenate hello with the string argument and finally a new line character and right at the end I return a pointer to the string. And here you can see I've called this argument twice and I decided to print the return value from the argument in this code here. And I have used two strings of different lengths to test that the string function daz correctly with it. Let me run the code on. Here's the result. So you can see it works correctly it's allocated the correct amount of memory to deal with two strings of different lengths. Incidentally it's worth mentioning that malloc allocates memory on the heap. That's important but local variables declared inside a function are allocated memory in an area called with stack when you exit from a function. The variables on the stock are cleaned up to all intents and purposes they no longer exist when the function exits. But the heap is when global data is stored in memory. Data assigned to variables on the heap continues to exist even after you've exited the function in which they were allocated. So now I have 100 bytes set aside for my string. Everything works correctly as long as I don't try to create a string that has more than 100 characters. But what if I do need a longer string. And there's another problem too by allocating more memory than I need. Wasting memory in a very big program one that handles large amounts of data. Or conversely if I'm writing a program for some sort of hardware device that has very small amounts of memory wasting memory in this way could be a problem. I'll explain how to avoid that in the next lesson.

Malloc and sizeof


Transcription :
Let's now see how I can allocate just the right amount of memory to hold an array containing a specific amount of data. Once again my program will use a string with a char array as an example. All I want to do here is copy a string into an array. I do this using the SDR and p y. Function the array into which I want to copy characters is the first argument. S sorcerer. In other words the string I want to copy is the second argument here that's Hello. The third argument is the number of characters that I want to be copied on. Obviously I want that to be the size of the string. The question is how do I calculate the size. That's where size of comes in. At first sight this looks like a regular C function. In fact it's an operator and it calculates the size of the data available an array or structure placed between the parentheses. And of course right here is the string hello. The value returned is an integer that represents the number of bytes required to store the data object in this program. I've simply used size up to calculate the number of bytes in the string. Hello. I've then called malloc to allocate that number of bytes to the char point s. Notice the cost char star here. Which is required to cast the generic pointer returned by malloc to the specific pointer type pointer to char and for safety. I've added this little test down here to check that the operation succeeded. Undresses not now then. Or being ral. I use SDR in c.p y to copy the chaws from the string Hello into the memory location that that's referenced by the pointer and finally just to prove the test has been initialized with the chars and is now a valid array. I've just used the normal array indexing syntax down here. And here what I've done is I've changed the first character from H to C so hello becomes Chello. There's one final point I need to mention. You can see that I put some breakpoints here. I put a breakpoint here and another one here. Now that will let me run this in the debugger and examine the values of variables at these points here. I'm using Microsoft Visual Studio because I happen to like its debugger. But you should be able to see similar results in other debuggers. So let me start the debugging session stop at the first breakpoint. Now as you can see down here the value of string size is 6. That's the variable that was assigned the return value from size of how low the string Hello. So even though Hello only has five characters string size has the value of 6. And that's because it includes the string Terminator Nuddle in its current. But how can I show that. Let me run to the next break point. OK so since S is a pointer to char the debugger only shows me the char that it actually points to expand airstone here shows me just the value H. That's the first character the start of the string s. But I only need to find the sixth char that is the one that fav characters along in memory from the char at index 0 at the at the position the the pointer S points to Visual Studio. I can evaluate arbitrary expressions in the immediate window down here so I can enter s and put in index 5 to see what characters actually aren't index 5 in the in my string. And here you can see it is indeed. No it's the terminating now. Hence size of hello is 6 because it measures the size of the string of 5 characters that I can see a G W O. Plus the the null at the end.

Functions that cause errors or warnings


Transcription :
Now if I compile this code in Microsoft Visual Studio I have a problem. I'm told that by default see the error message. SDR and CPI is considered to be a deprecated function and I should use the safer SDR in C.P. why underscore Yes. Now it is quite possible that your C compiler will complain about some functions either this one or maybe some of those functions that I use in my code but which your compiler warns you are old that pre-created or unsafe. So why am I using them. Simple answer is to make sure that my code will run in pretty much any C compiler. Often I use the simplest most traditional functions for clarity and to ensure compatibility. But it is true that in many cases there may be better and safer alternative functions which you may prefer to use in your own programs. If for example your compiler or your ID tells you that the function is unsafe you may want to stop to look up the documentation of the recommended function and use that instead. Or you can define the constant suggested so you can see here it suggests to disable the application. Use this constant down here so I could copy that into my source code. I've already made a copy ready to go and put it up here. Saved my program and should tell the compiler to stop pestering me with error messages about the function in question so see if that works. Try rebuilding it goes a little think about it. And yes so this time it seems to be quite happy. Compile the program on there are no errors so although there on your end say for functions that C compilers and platforms may use. The danger is that they are going to be specific to those compilers. The SDR and CPI underscore as function for example is provided by Microsoft but it may not work with other compilers. So bear in mind that my code in this course sticks whenever possible to older traditional while widely supported functions purely for compatibility. Even though your C system may have newer and safer alternatives and you can look those up in the documentation and use them if they are recommended.

Calloc


Transcription :
As well as my lawk there's another function called convoke it's often used when allocating memory just like malloc lock clock function allocates memory but it also performs one additional step. It clears the memory. In other words it initializes the memory with nulls uninitialized memory contains unknown data junk which you could accidentally try to use in your program. If you allocate memory with Carlock a series of nodes will be written into memory until of course you specifically write some of the data there. If you are careful always to initialize allocated memory then by all means use malloc. The clock function performs exactly the same function as malloc. But in addition it ensures that the allocated memory is initialized and that allows you to test the allocated memory if required so that you know whether or not any specific data the data that you intended for hasn't yet been written into that memory. The only difference to bear in mind is the syntax malloc takes a single argument which is the size in bytes of the memory required to hold all the data you want to store clock takes two arguments. The number of elements in the array and the size of each element. You can calculate the size using the size of operator. Incidentally you can also use size of with malloc if you need. For example I could rewrite this line here which I've just got 6 as the single parameter to malloc. I could rewrite it by calculating the size of the type which is here. Char multiplied by size of. That's entirely valid. But since the simple chars just one byte in size this isn't necessary here but with other data type such as doubles it would be needed. So let me run my code to see how it works. There's the results so here I just allocate memory with malloc but the memory is uninitialized. So when my full loop iterates through it I just print out whatever random values happen to be the as you can see all sorts of unpredictable numbers are returned. But when I do the same thing with clock the memory that is the characters array array which my char pointer points that's been initialized with knows. And similarly the memory pointed to by my pointer p here. Kulak 6. Size of int. Well not to has been initialized with novels. I mean just close not. Bear in mind that both malloc and Carlock return a generic pointer a pointer to void or a null pointer. If the allocation of memory fails it's worth saying at this point. What a null pointer actually is. It's nothing more nor less than a pointer whose value is zero. In other words whereas other pointers store a number greater than zero which is treated as an actual address in memory. By convention a pointer with the value 0 is considered to be one that does not point to a valid address and we call a pointer with zero value. Unknown pointer pointer that points to nothing and we can test for another pointer in our own code. You can see an example here that I used in an earlier program where I test if X equals no.

Free


Transcription :
In a new program that's this one in which I used my luck to set aside some memory for a string. I allocated the memory and I left it allocated throughout my program once memory is allocated. It's no longer available to the rest of your program. So in principle if you continue to allocate chunks of memory you might eventually run out of memory when there is no more memory left to be allocated. Now on modern desktop computers this is rarely in fact the case because they simply have huge amounts of memory. I could go on allocating more and more memory for strings. I never run into any problems. Even so if you allocated very large amounts of memory without ever freeing any up when it's no longer needed you'd be using memory very inefficiently keeping memory allocated even when it's not needed. That is when it's no longer referenced by any variables or pointers in your program. Well that creates what are usually referred to as memory leaks. This could be a real problem if you happen to be writing C programs for devices that don't have huge amounts of memory. For example hardware controllers for machines or a Bartik devices and they might have very small amounts of memory at any rate. It's good practice to d allocate memory to make it available again for use in your program. When that memory is no longer needed and the usual way to do that in C is by calling the free function let's look at this other program so you can see this program. I've already done that. I've called free. This is the program where I showed in an earlier lesson how to use the clock function and I called free to free up memory that's no longer needed. For example I've allocated memory for an array of 6 characters and here for six integers and then later on when I no longer need that array I call free passing to it. The variable for which the memory was allocated here. That's the string s the char pointer s and here it's the pointer. The pointer p. You should make a habit of freeing memory whenever it's no longer needed. But be careful if you call free on a variable that was never allocated. Or if you try to use allocated memory after you've called free then your program will go horribly wrong.

Realloc


Transcription :
Sometimes you may want to change the size of a block of allocated memory. You can do that using Retallack here for example. I've allocated enough memory to hold the string hello. That's six bytes as calculated by size of five characters on the null terminator. But now I decide I want to display the string Hello world. So what do I do just increase the string length here. And then just go ahead and print it anyway. Or he thought works ran my program on and I just got some dumdum junk after that each time I get some different character displayed completely unpredictable and says hello five. Each time I run it you can see I'm getting something else some unpredictable junk that's looking around in memory and that's because I've only allocated enough memory for hello but I tried to copy a largest string into memory that has not been set aside to hold it and that just does not work. I must allocate memory first but maybe I think well I can just concatenate world onto my existing string and just comment this out first and try that out. So I've called the function SDR caught with my string which currently contains the characters follow. And I've tried to concatenate world onto it. Let's run this program again and see what happens. Even worse. So I really messed up my program big time here by trying to cut and paste a string onto the original string without allocating memory first. So let me just shut this down and put my code but to use previous form. Now since the string hello world contains 12 characters that's higher than hello one for the space Feiffer world and one for the null terminator. I need to allocate 12 bytes of memory and just fix this back to the correct version of the code first. Now look down here this is where I do that re-allocation I call real cloak with the pointer to the previously allocated block of memory which is a pointer to chawl as the first argument and the new size required here that's 12 bytes as the second argument. Now you can use the alc as an alternative to calling free in order to deallocate the previously allocated memory block followed by malloc to allocate it with a given size. See if this works. And this time it correctly displays. Hello world. So the first time through it space hello because I have calculated the size of hello and then allocated about size using malloc and the second time it displays. Hello world. Because I have relooked. I called the function the new size the correct size to hold the string Hello world. So all is well and good. So think of reality as a simple convenient way of allocating a new amount of memory referenced by an existing pointer.

Pointer arithmetic


Transcription :
Some of the short programs we've looked at in this course I reiterated over the items in an array just by adding one to the point of variable. For example here I add one to p i.e. That's a pointer to an integer in order to move to the next element in an array of integers. And here I iterate to the next character in a string by adding one to the PC variable which is a pointer to char. But wait a minute since the value of a pointer is a number that represents an address in memory. Why does adding one to a point to have the effect of moving it to the next element in an array. Maybe it's because it just increases the value by one byte so it moves the pointer one byte in memory and that's where the next element in the array is stored. But no that but simply doesn't make sense either. I know that my C-compiler in Windows needs 4 bytes for an integer. So I'd seen that when I add one to my pointer I actually move four bytes in memory to the next into my array. To understand what's really going on here we need to look at how pointer arithmetic is done in C.. Here in my address arithmetic one sample program I create an array of 4 integers since I've declared the arrays size at the time of its declaration memory will automatically be allocated for it. So I don't need to call the malloc function this for loop I initialize the array with four integers from zero to three. And I set the pointer to point to it that is by assigning the array A to the point of P I set the value of P to the address of a. Now let me run this code so you can see the results. First I showed the address of the array A and the value of the pointer p and they're the same as you'd expect then Id reference P which shows me the integer to which it points its zero. The first element of the array the address of the array never changes. So this number remains the same throughout my program. Now I add one to the pointer variable P by default pointer values are shown in hexadecimal and that's this number here. For clarity I've also shown it in decimal format though it's possible that a compiler may object to that. And look even though I added one to the pointer its value is increased by 4. So it points to an address in memory that's not one byte but four bytes further along from the start of the array. In other words adding one to the pointer has increased its value by the size in bytes of a single array element and now it points to to the second element of this array. And that's the integer 1. Why does adding one to the pointer to increase its value by 4 is because he knows that my array contains ints. That's how I've declared it. It knows it takes up 4 bytes and so it knows that when I add one to my pointer what I mean to do is to increase the value of that pointer is to increment the address that it stores by however many bytes are needed to move to the next element of the array. Now I add two to the pointer and I can see that it's value the address to which it points has been increased by 8. That is two times the size of an int previously pointed to the second element. Now it points to the fourth element and that's the integer 3. And finally I decide to see what happens if I increment the pointer once again. It already points to the final element in the array. So what will it point to now. Well the answer is your guess is as good as mine. It points to whatever happens to be in the memory for bytes after the end of the array. I shouldn't really be trying to access that memory at all. So in a real world program you would need to check very carefully that any pointer arithmetic operations only take you to some known memory location such as an index in an array which you have previously allocated and initialized.

Calculating an array index


Transcription :
In the last lesson we saw that adding 1 to a pointer cause the point to point to the next integer in the array. This doesn't only work with integers as long as she knows what the data type of an array is. It's able to calculate the appropriate number of bytes needed to move from one element to the next. Let's look at another example. In the address arithmetic to project I've declared pointers to a variety of data types. Int float double long long it short int and long and on each of these pointers points to an array of the matching data type I've assigned the arrays to the pointers and fill the arrays with some data and see them done here. And now down here I've done some simple point arithmetic by adding one to each point to variable and finally I print the results. Let me run this right. So this is what I see when I've added one to the point of variables that's had the effect of moving to the element at the next index of each array. If you look at the array address and the address of the first element that is the result of adding 1 to the point of. In each case the difference is the same as the size of the data type for fun an int 4. For a float 8 for a double 8 for long long it to for short int for the long int you can pause the video or run the source code yourself if you need longer to look at the decimal versions of these addresses to see how they're incremented. I haven't had to calculate the offset myself. Nowhere in my code do I get the size of the data type and increment the address by that number of bytes. C's pointer arithmetic. When I add a value to a point of variable calculates the appropriate offset for me. In fact on some platforms and with some C compilers the sizes of data types may be different from the ones shown here. I run this code just to test it out on my Mac for instance and when I did that I noticed that a long int has a size of 8 bytes. You can see that shown here. Whereas on my Windows PC same long int data type has 4 bytes. Even so I've been able to take the code that I wrote on my PC and recompile and run it on my Mac without making any changes at all and it works correctly because the Mac compiler automatically calculates an 8 byte offset for my array of long illness. So when I do my pointer arithmetic by adding one to the pointer variable it moves 8 bytes in memory rather than 4 bytes as on my PC and that's how it references the next element of the array.

Pointers to structs


Transcription :
In an earlier program I showed how you can allocate a specific amount of memory here that's 12 bytes to hold data of a specific size allocating a fixed number of bytes like this is all well and good in a simple demonstration program but in a real world program it's a very bad idea because of the size of data types can sometimes vary according to which compiler or operating system you are using. Well we've already seen an example of that with a longing which has a different size on my PC and on my Mac with more complex data types such as struts you should never assume that you know how much memory is actually required. Let's look at this program that uses struts here. I've declared a struct containing two. It's a double on the long long int. Well I've used these data types before and I know that each end takes up 4 bytes while the others take up 8 bytes each of them together. I get 24 bytes. Look I can show that this is the case by running this program and do that now and see it. I print out the size of my struct and it says 24. So when I want to allocate memory for an array of my struts I just need to allocate 24 bytes for each write wrong. But why is this wrong. It works after all. We we've just seen that the program runs fine on here I allocate 24 bytes for each struct. So what's the matter. Well it's not so much that it's absolutely wrong for the time being in the present case as the code stands at the moment but it is at any rate still a very very bad idea. Let me show you why. Let's say I decide to reorder the features of my struct. After all C should logically come off to be shouldn't it. So let me do that. I'll just move B into the right position. A B C tidy up this very k. Now let's assume that I've written this program. Tested it to see that it works as I've just done. And then at the end of the day I just tidy up the struct as I've just done and I think no more about it. I send my program out into the world and when I get back to my desk the next morning everyone's going nuts. Why Well that's run my program again. Here we go. Oh OK so we have a problem shut this down. Some know my program and maybe in real life this would be a really important program one that runs an international banking system or an airline control network who knows what my program now keeps crashing. But what did I do. I didn't change anything did I just tidy up the struct definition by reordering the features. Well it turns out that is a change and it's not a trivial change either because strange as it may seem my strat no longer takes up 24 bytes of memory. So when I allocate 24 bytes I not allocating the correct amount. This is why you should always use size of to calculate the actual size of a piece of data rather than assuming you know its size. So this is the problem line where I do the allocation that you replace that sort of allocating 24 bytes the size of my struct and run the code again. And this time it works. Now let's put the struct back the way it was before. So if I move integer back into here order the struct feels DCV and run it again and it still works. Because no matter what the size of the struct size of returns the correct value when memory needs to be allocated. But I see why this program crashed when I changed the order of the fields. This is now the struct as it was initially defined with two integer fields followed by a double and then a long long int. And when I print size this show this again you can see up here it comes to 24 bytes. And that worked when I specifically allocate it as I did in my original code 24 bytes per struct. Now if I change the order of the fields again OK. So now we've got to double an. And the long long int. Now let's see what happens when I run not. Scroll to the top and you can see the size of my structure is different. It's now thirty two bytes. And that's why the program crashed when I tried to add more bytes per struct than I allocated because I'd only allocated 24 bytes. But look the struct itself actually contains the same data now as it did before. To lots of 4 bytes the two ints I'm two lots of eight bytes the double and the long long int and that adds up to 24. But it says my struct takes up 32 bytes. When the fields are in this order. So where are these extra bytes actually come from to understand that you have to understand how the C-compiler lines the data in memory.

Data type alignment


Transcription :
Now let's find out what's going on. When I reorder the fields of a struct in the last lesson I showed that when I declare a struct with these two integer fields next to one another the size of the struct is 24 that's equal to the total number of bytes required by each of the four data types. When I declare them in a different order like this. So now the inputs are separated by the double. No the size of the struct is 32. So what's going on. The answer is that the data types are being aligned in memory. At least this is what happens on desktop computers such as. Such as the PC that I'm using here. But it may be quite different on other architectures such as microcontrollers to understand data alignment. Imagine that I'm storing my struct in the matrix of cells like in a spreadsheet. Now here's my point. A It takes up full bytes of 4 cells in my spreadsheet. I double B comes next. That takes 8 bytes another c another 4 bytes and then the long long int d. And that also takes 8 bytes these data fields arranged in memory. Much as I've arranged them here in the spreadsheet they form a nice neat regular matrix. Now it's not exactly the way that memory is arranged in your computer but it might be a useful way to imagine that the fields of a struct are aligned so that they all start at a predefined boundary and to visualize that in a spreadsheet I can start counting along the cells in my matrix of cells so each 8 byte data type needs to start at some multiple of 8 bytes in memory from the start of the matrix. So I count the cells all the bytes used by a 1 to 3 4 but my double B constant starts here in the fifth cell because that's on a 4 byte boundary it's where the full byte int A ends. So I carry on counting along the four empty cells or unused bytes. That's five six seven eight and now I've arrived at an 8 byte boundary. Now the empty cells here on the right aren't used in fact but they are important because they help to pad out the gap between the full byte int and 8 byte double and that's how I ensure that the double starts on this 8 byte boundary. So that's where it starts. Now since I've used the clock function when allocating memory these empty cells the ones shown on the right of the A and C it's what they've been initialized with Nos. They don't have to be initialized that way but it's a good idea to do so and it makes debugging easier because at least their values are predictable. Think of this struct as occupying a matrix of 4 by 8 fulfills 8 bytes wide to accommodate the largest data type. That's the double and the long long int plus some padding unused bytes after the smaller int fields. Hence my struct takes up four multiplied by 8. That's 32 bytes. But when I rearrange the field order by putting the two int fields one after the other so that's like this changes the structure of my that the layout of my structure rather to something like this. So the C-compiler cannot optimize the structure in memory. Instead of putting out the first field a with extra bytes it just puts the next data field which is now another INT with the full byte. And that's the C int. It puts it alongside a. And that also forms now a nice neat Matrix. But this time no extra bytes needed to align the 8 byte data fields at 8 byte boundaries. So the Matrix now takes eight fuel cells in my spreadsheet or eight fewer bytes in memory. My spreadsheet now has three rows and columns three times eight. A lot ECOs 24. And so now my struct takes up 24 bytes in memory. But let's go back to this version of my struct where the interviews are not adjacent to one another so that's shown here in the spreadsheet where I've got the in a divided from C by the double B. And then I've shown these nodes alongside. Let me go back into my code to put the code back into that state. So once again I've got the it's two ints separated by this double. So let's see what happens when I run this as the output of my program. I've written this code to display the fields of the struct at index 0. The first element and index 3 last element in my array this fall displays data stored at full byte offsets. That's four bytes because that's the size of an int from the start of the address containing the struct at index 3 the first four bytes contains the int variable a. And if I look at the output you can see that the value 3 the next 4 bytes is 0 that is it contains the nose that we use to initialize the memory. When I called Carlock to allocate the memory initially the memory contain Knowles is the painting. These are the unused bytes between the end of the end and the start of the double and they are there in order to line the sort of the the double tonight by boundary. Remember we saw that represented in this way in the spreadsheet so this structure contains a mix of data for the fields and unused bytes which here is just like that matrix in my spreadsheet. Then we come to field B which is a double. Stored over 8 bytes. Don't worry what these two numbers are. I'm displaying a decimal representation divided up into two four byte chunks of the floating point data which occupies 8 bytes. So it's not good to make much sense. The actual numbers are not important. What's important is to note that the 8 byte double fills up to adjacent four by chunks of memory so no additional bytes were needed to align it. Then there's another INT see its value is 60 days i.e. times 20 which I set in my code but that takes up only 4 bytes. So once again the full bytes have been added onto the end of it. This is the chunk of memory that contains the nose that were added by clock and finally there's the DeFeo that's another 8 bytes to represent a long long int. Again the actual numbers shown here are not useful or informative as I'm showing two four by chunks of an actual 8 byte number but that's not important for our purposes. What's important is to see that once again no extra bytes have been added because the full 8 bytes used and no padding is needed to line this data field.

Type alignment on boundaries


Transcription :
INRI This is how data alignment works. Data Types of a certain size are aligned on boundaries of size for byte into is aligned at as it starts in memory on a full byte boundary and 8 byte double starts at an 8 byte boundary. If a single four byte and immediately preceding and 8 byte double as it does in my struct for extra bytes I did after the end to ensure that the 8 by double starts on an 8 byte boundary that is at a multiple of 8 bytes from the start of the struct with boundaries at 8 16 24 bytes and so on. But when 2 4 byte insecure one after the other the and I could not Charile 8 byte boundary. So the double is aligned with that boundary and no extra padding is needed and really important lesson you need to learn from this is that the size of data types cannot be a feud with different compilers on different architectures. Even simple data types might take different amounts of memory. So if you allocate a specific number of bytes when you write your code on one computer the program may not work correctly when it's deployed on some other computer or some other device or microcontroller. And if you use complex data types such as struts the situation becomes even more error prone the way struts are stored in memory is not predictable across different machine architectures on its iPhone or even making an apparently trivial change to a struct by reordering its Philo's may change the amount of memory it needs.

Type alignment and pointer arithmetic


Transcription :
So as a general rule never assume that you know how many bytes are required to hold a piece of data. Don't allocate memory using a simple integer such as 24. As shown here when you were allocating a specific number of bytes instead make a habit of using size of Dickau collect the amount of memory needed like this but is much much safer. The good news is when you do pointer arithmetic you can let the compiler work out how many bytes it needs to move in order to go to the next element. Recall that in the earlier program that I wrote here I did some pointer arithmetic with ints so I've got an array of ints and when I added one to the pointer variable that caused the pointer to reference the element 4 bytes along from the previous element. And now with my struct I have a more complex data type which can take up either 24 or 32 bytes according to how I declare it fields. This only works by the way with arrays of specific data types you can't do pointer arithmetic with generic pointers pointers to void unless they're first cost to a known type pointer arithmetic with fairly complex types. Such a struct is just as simple as with simple types such as integers adding one to the pointer variable moves it to the next element. That is the second element in my array of struct. That's a great thing about pointer arithmetic. The compiler can figure out how many bytes each element in an array occupies. When I add one I'm not adding a specific number. Certainly not the integer value one to the value of the pointer. I'm telling the pointer to move one complete element along the array and that is how pointer arithmetic works.

Debugging C Programs


Transcription :
Have some questions I've been asked by students I know that some programs using pointers can be incredibly hard to understand. Now unfortunately there's no single program that causes the same problems for everybody. One program might be difficult for somebody to understand it's a different program might cause somebody else problems. So rather than give you a specific solution to a specific problem I want to show you a way of solving point of problems for yourself using a debugger. Now here I've picked a sample program from the code archive it's the one that goes through the command line arguments and this one uses multiple indirection that is pointers to pointers. Now the program itself is fairly short. You can see I've got it loaded here into Visual Studio but it is not double level of indirection. The **argv can be really challenging to get into your mind. So let's see how the debugger can help us. I'm usually using Visual Studio. I mean just start the debugger so that you can see something happening. Now most other good ideas with how similar tools for stepping through code and watching variables but they may not have all the same tools as Visual Studio and a window that I like for debugging is the one down here it's the immediate window and I'll be showing you how to use that shot. So some of ideas may not have that but they will allow you to set breakpoints and step through your code. Now before we start let me remind you what Argosy is actually supposed to be in principle it's an argument vector that's an array of strings. Now in fact to be more accurate it's a pointer to an array of pointers with those pointers each pointing to a string. So let's draw a diagram to show this. I've got Aag the OK. So this is a pointer to an array draw my array down here. And he is going to have three elements. So the array is some address in memory and this race contains some pointers. Two strings. So all the points to this array and the array contains pointers to the three strings and each of those strings is remember in fact an array of char an array of characters. Now back to the debugger. Whichever debugger you are using the first thing you need to do is to set one or more breakpoints. Now I'll do that here in Visual Studio so in Visual Studio I just click in the margin and you see that red breakpoint Mark appear a breakpoint tells the debugger to pause on a specific line to give you the chance to look at the value of variables at that point in the program. Now I want to understand how the ARG the argument in Maine actually works as I've already explained óg V is an array of character arrays. The first string is the name of the program that you are running. If you enter any command line arguments they will also be added to the ARG V array at least to the array to which ARG V points. Now as I'm not actually running this from the command line I need to tell visual studio to pass some arguments to the program. Do that by right clicking the project node hears selecting properties going into the configuration properties debugging on it's got this entry command arguments. By the way if you do this I'd recommend you select all platforms it can get very confusing if you select one platform and I compile it for another and you find that you have a different set of arguments or no arguments at all. So all platforms and then these will be these will take the place of the command line arguments that I would have passed to the program had I been running it from the command line. OK so I'm ready to go. So I'll start in debugging mode. Click up here. And when my breakpoint is hit the program pauses. Now down here in the locals window I can see the values of variables. First I can see that. Argh. See the value for óg c stores a count of the arguments where the first at index 0 is the name of the program itself and you can see that down here is the full path. To my program. OK so I have carry on debugging I press 5 to carry on. And now the breakpoint is hit again. And that's on another turn. Through this for loop. So this time I see the first argument the specific argument that I entered that was the string one and not shown alongside V here. So what are the two asterisks for. Now these are after all supposed to indicate that this is a pointer to a pointer. Well look this number here gives the value of the ARG the variable its value is an address it's the address of another pointer and it's not a pointer that points to the string. The array of characters of a single argument. Now I think this might be clearer if I switch to the immediate window. Now if you can't see the immediate window you may need to activate the Debug menu go to Windows and then down here you can see the option to display the immediate window. Well I've already got the immediate window shown so I can start entering some things to be evaluated in them. Now all will remember as a pointer to a pointer to char. Let's just enter argufy and see what we see. OK that's the results. So this is the same information as was shown in the locals window. But let's break this down a bit. First what is the address of the ARG of the variable. Let me enter the address of operator ampersand. ARG. And now this is what we see. The important bit of data here is this first number. That's the address of the ARG the variable itself. It's where that variable is stored in memory. Now this stuff here. All this between curly brackets. This is like a full expansion of where the OG V pointer ultimately points to Daag V is remember a pointer to a pointer to a character char star star OG V. So let's see if we can unpick this. Let's start with the idea that ARG V is a pointer to a pointer. That means its value is an address that contains another pointer. Or to put it another way the og the pointer points to another pointer. This first value inside the curly brackets here is the address of that other pointer. In other words the all v variable lives at this address but its value is this address an immediate window I can see the value of a variable by entering the variable name. So let me do that again into arguably one small plane all this time and sure enough the value stored by the org the variable is another number another address. So what is it the address of. Well all being well it should be the address of another pointer. In this case a pointer to an array of characters that is a string the string is one of the command line arguments. But how can we verify that. Why do we need to dereference all the to one level. I do that by entering asterisk all star óg the and this time I arrive at another point. Which is at the address shown here. And this pointer points to the string 1 the characters 0 and E form that string. And if I want to get at the string itself I need to use one more level of direction. I do that with Star Star OG v. Right. And this time I've arrived at the address of the string one. What's stored at that address the character o the first character of the array of characters that forms the string one the value on the left is not an address because this is not a pointer. Hundred and eleven is the ascii value of the character. Oh Incidentally you may be wondering how he ended up pointing to an array of strings in the first place. That how did each of the command line arguments get assigned the pointer. And how did those pointers get put into an array before the program even ran. Well it turns out that the C language runtime does that for you. There are in fact a few startup operations that go on before your program executes. So anyway I hope this helps you understand the basics of multiple interaction how to use the debugger. In this case the Visual Studio debug but in general how to use a debugger to solve pointer problems. We've looked at a fairly complicated example here of dereferencing several levels. Two levels of pointers and when you are debugging difficult pointer programs I strongly recommend that you go into your debugger and use the sort of tools that I've shown in this video to help you understand the relationship between pointers and the addresses to which they point.

Debugging Multiple Indirection


Transcription :
Now over the years when I've been teaching C programming one thing comes up time and time again it's something that's raised by my students. It's a struggle to understand exactly how pointers work and worst of all pointers to other pointers. So here's an example. Now just look at this. This here is a pointer to an int. The asterisk star before I.P shows us it's a pointer. So let's look at this. What's this then. This one has got two stars. Well that means it's a pointer to a pointer to an int. And if you starting to panic at this point. Well I've got bad news here. It's going to get a lot worse because look at this variable. It's got three stars and that means it's a pointer to a pointer to a pointer to an int. How the heck are you supposed to make sense of a lot. Well let's use the visual studio debugger. Now you can use other debuggers Of course I mean whatever ID you are using has probably got some sort of debugging to build 10 but I'm using Visual Studio because Visual Studio has a great set of debugging tools. And in this lesson I particularly want to show you how to use the memory window by the way you notice that I grouped the pointers here inside a struct. There's nothing special about that. The pointers would work in exactly the same way if they were ordinary variables. Well look I got another project down here and if I open this up you can see that here I've got the pointers freestanding as freestanding variables and not grouped in a struct. But for our purposes is going to be more convenient if they're placed in a struct because then they will occupy contiguous memory locations and that's going to make it much easier for me to show you some of the relationships between the point is when we get into the debugger and particularly in the memory window. Now one other thing if you want to try this for yourself I'd suggest that you compile for Win32 not correct 64. Again that's for convenience. Win32 works with smaller data types and that just makes debugging a bit easier. You can set it in Visual Studio you can set this target up you're in the Configuration Manager and you pick whichever project you're running on and alongside it use select when. And that's going to make sure that it can compile it as a 32 bit application. OK so let's briefly look at what the program does. I set I P P P to point to the address of IBP or that's actually the dot. Here is the pointers are in a struct. I said I Peepy to point IP and IP points to an integer. I do which I've assigned the hexadecimal number just to make it easy to see when we start debugging. Now I put a breakpoint here on return and start the debugger and immediately we hit a breakpoint on the program pauses. Now let's here we can trace our way through this set of pointers. One way would be to go into the watch window on just a struct P and you can see that it shows some information there which I can expand. But that's already starting to look a bit confusing. Just show me a bit too much information and it's quite hard for me to pick So instead of going to use the memory window. Now if you can't see the memory window go to debug select Windows and then you can scroll down to memory on pick memory one to display one of memory windows. Now at first sight here you can see the memory window. This might look even more confusing than the watch window did because it shows a massively detailed view of the memory that's being used. But I can simplify that. So first of all I right click on to get rid of all this stuff on the right which is the text display. So I just select no text and once I've done that I need to set it to 4 byte integer and 32 bit programs of 4 bytes is the size I need and I don't want all these columns. I just want I got here. I just want one column. OK so that's tidying up this memory window display a bit. Now I need to display the location that I am interested in. As this is a display of memory I have to specify an address in memory so I enter the address of my struct to my struct called P So I enter ampersand P for the address of the struct right. So let's see what we've got here. Let's start with this. Here's how I got this information here. That's the value that I entered for my Int. I over here. So that's helped me spot where I am in the memory. Now on the left this is its address but look that's the same address. This one here. So this must be a pointer the point to i.p. That points to Ivy and I can check that by addressing or by entering up here the address which is P or type B. And you can see this is the address of the IP pointer. The value of that pointer is shown here the value is this address and at that address is my integer here. So that's the IP pointer pointing to my integer. Let me go back to the it displayed my structure of the address of P. So here I'm just being struck again. Now let me work forward. This time the first item in the struct P is at the same address as the struct itself. And it is my pointer to a pointer to a pointer pointer variable contains as its value a number that number represents an address and the number here is the first one in the right to column and it points to this address in the left column and you can see now why I've put these pointers in the struct by grouping them in a struct like this I've be able to ensure that they are stored next to one another in memory and that makes it easier for me to debug in the memory window. OK so now this address is the pointer to another point of us IBP or is this value here. Trace down to its values is the address of that pointer. So the next pointer is shown here and that contains another pointer remember. And that points to the integer. OK so by tracing through the pointers values in the memory window we've gone from a pointer it stores an address to the address it stores to the address that stores so on. And eventually we've arrived at the value of the integer which is pointed to by the last pointer in the whole list of pointers. So I know it's quite complicated to work out multiple indirection like this but using the debugger and in this case using the visual studio memory window you can use the watch window as well as I showed earlier. It should help you to understand how to peek into memory to see exactly where pointers or even pointers to pointers to pointers are actually pointing.

C pointer study notes


Content retrieved from : Udemy
Previous lesson

Comments

Popular posts from this blog

Udemy - advanced c programming pointers - Pointer Basics

Udemy - advanced c programming pointers - Pointer Basics What is this course about ? Transcription : Welcome to this c course on pointer's before we get started let me say a bit about who this course is for what you get out of it. Now let me be clear I'm assuming you already have at least some experience of programming in C before you start this course. This is definitely not a course for beginners. You need to know at least the basics of C programming syntax how to write functions parse arguments how to edit and compile C programs. You may also have at least some experience of using pointers but that isn't essential if you are completely new to see where I already have another course on C programming for beginners. And that's why you should start this course is more advanced. It explains pointers in depth in the early stages I'll explain what pointers are and how to use them. I'd explain addresses and in direction allocating and freeing memory pointer...