300 likes | 447 Views
CS 108 Computing Fundamentals April 29, 2014. Exam #3. High score: 170 Low score: 24 Average score: 120.5 Median score: 127. Thursday's Class. Review Exam #3 Open and Closed Book Review Exam #2 Open book Discuss Exam #4 Discuss GHP #14 Discuss Preparing for CS 240 Data Structures
E N D
CS 108 Computing Fundamentals April 29, 2014
Exam #3 • High score: 170 • Low score: 24 • Average score: 120.5 • Median score: 127
Thursday's Class • Review Exam #3 Open and Closed Book • Review Exam #2 Open book • Discuss Exam #4 • Discuss GHP #14 • Discuss Preparing for CS 240 Data Structures • Complete Student Course Critique
Defining Variables • As we’ve discussed many times, defining a variable does all of the following • Gives us a name to use as a "handle" to get to a memory location • Assigns a memory location • Assigns a data type • Ensures exactly the right amount of space at that memory location to accommodate the data type • Defines an encoding and decoding standard for data representation • Determines the operations that can be performed • What's wrong with the next slide's program?
Defining Variables #include <stdio.h> // 1.c #include <string.h> int main(void) { char *message_ptr; strcpy(message_ptr,"Beam me up Scotty."); printf("%s", message_ptr); return(0); }
Defining Variables • What's wrong with the last slide's program? • No memory space was ever reserved/saved/marked for the message • A pointer ( message_ptr ) was declared, but a pointer holds only an address… the address of some other variable (usually) • It doesn't hold more than an address • It doesn't have the space to accommodate something like a string (in this case) • It doesn't have a memory location (address) to store something like a string (in this case) • Remember, a pointer has its own address (which is unchanging) and it can hold the address of another variable or memory location, but that has to be assigned somehow • How can we fix this?
Defining Variables #include <stdio.h> // 2.c #include <string.h> int main(void) { char message [50] ; char *message_ptr; message_ptr = message ; strcpy(message_ptr,"\n\nBeam me up Scotty.\n\n\n"); printf("%s", message_ptr); return(0); }
Defining Variables • What if we don't want to delare an array of characters like char message [50] ; ? • Is there a way to assign a memory location and the exact amount of space without declaring a variable?
Defining Variables • malloc( ) to the rescue • It's used to take a piece of available memory and then assign the location of that memory while your program is running • Here's the general format guidelines pointer = ( type_cast * ) malloc ( size ) ; • For example, using 2.c as an example char *message_ptr ; message_ptr = ( char * ) malloc ( 50 ) ;
Defining Variables #include <stdio.h> // 3.c #include <string.h> #include <stdlib.h> int main(void) { char *message_ptr; message_ptr = ( char * ) malloc ( 50 ) ; strcpy(message_ptr,"\n\nBeam me up Scotty.\n\n\n"); printf("%s", message_ptr); return(0); }
Defining Variables • malloc( ) • How cool is this? • malloc( ) allows you to do what the compiler and operating system have been doing for you: • Reserve a memory location • Allocate space at that memory location • Make that space represent the data stored there in a specific manner (char in 3.c) • And you can do this "on the fly" • Of course, it's possible that malloc( ) can fail when we call it (perhaps there are no memory resources available), so we need to write our code to take that event into account
Defining Variables #include <stdio.h> // 4.c #include <string.h> #include <stdlib.h> int main(void) { char *message_ptr; message_ptr = ( char * ) malloc ( 50 ) ; if (message_ptr == NULL) { puts("\n\nNot enough memory available… sorry.\n\n"); } strcpy(message_ptr,"\n\nBeam me up Scotty.\n\n\n"); printf("%s", message_ptr); return(0); }
Defining Variables • malloc( ) • Unfortunately, some responsibility comes with the ability to use malloc( ) : you must "free" memory when you are finished using it (the compiler and OS usually do that for you, but you're bypassing them when you use malloc( ) ) • For example, using 4.c as an example free ( message_ptr ) ;
Defining Variables #include <stdio.h> // 5.c #include <string.h> #include <stdlib.h> int main(void) { char *message_ptr; message_ptr = ( char * ) malloc ( 50 ) ; if (message_ptr == NULL) { puts("Not enough memory available… sorry."); } strcpy(message_ptr,"\n\nBeam me up Scotty.\n\n\n"); printf("%s", message_ptr); free ( message_ptr ) ; return(0); }
An Alternative to Static Arrays • Arrays are static… we cannot resize them • malloc( ) gives us the opportunity to dump arrays when we need a "dynamic" data structure like a linked list • Let's look at the next example program
#include <stdio.h> // 6.c #include <string.h> #include <stdlib.h> typedef struct vehicle { char make[15] ; char model[15] ; char color[8] ; } vhcl ; int main (void) { vhcl * truck_ptr ; truck_ptr = ( vhcl * ) malloc ( sizeof ( vhcl ) ) ; if (truck_ptr == NULL) { puts("\n\nNot enough memory available… sorry.\n\n"); } strcpy(truck_ptr->make, "Chevy") ; strcpy(truck_ptr->model, "Suburban") ; strcpy(truck_ptr->color, "Brown") ; // continued on next slide
printf("%s %s %s \n\n" , truck_ptr->make , truck_ptr->model , truck_ptr->color) ; return ( 0 ) ; }
An Alternative to Static Arrays • At this point we're just one step away from creating a dynamic data structure called a linked list • All we need to do is figure out a way around creating named pointers to allow us to use malloc ( ) • Actually, at this point, looking at program 6.c, it appears that there's no real benefit using malloc ( ) because we need to create a named pointer for keep track of every memory location staked-out by malloc ( ) for us • Hmmm…. • Is there something we can do here to improve our lot in life?
An Alternative to Static Arrays • Brainstorm: instead of creating a pointer to stake-out a location of a structure, why don't we embed a pointer in the structure when we define the structure? • Then we can use a structure's embedded pointer point to another instance of the structure in memory • And then we can have THAT structure's embedded pointer point to yet another instance of the structure in memory • Chalk talk
An Alternative to Static Arrays • Key points to remember for linked lists • The pointer inside each structure acts as the link • A group of structures that are linked together form a linked list • A list is linked by all the pointers… the pointers are the glue that bind the structures together • Let's see how this works with some examples
#include <stdio.h> // 7.c #include <string.h> #include <stdlib.h> typedef struct vehicle { char make[15] ; char model[15] ; char color[8] ; struct vehicle * next_vehicle ; } vhcl ; int main (void) { vhcl * truck_ptr ; truck_ptr = ( vhcl * ) malloc ( sizeof ( vhcl ) ) ; if (truck_ptr == NULL) { puts("\n\nNot enough memory available… sorry.\n\n"); } strcpy(truck_ptr->make, "Chevy") ; strcpy(truck_ptr->model, "Suburban") ; strcpy(truck_ptr->color, "Brown") ; truck_ptr->next_vehicle = NULL ; // continued on next slide
printf("\n\nThe first structure instance was created and here are its contents: \n") ; printf("Make: %s \nModel: %s \nColor: %s \nNext Structure Instance Address: %p \n" , truck_ptr->make , truck_ptr->model , truck_ptr->color, truck_ptr->next_vehicle ) ; return ( 0 ) ; }
Link List Concepts to Understand • You must start with a structure • The structure must contain a pointer of the same type as the structure itself • You cannot use the structure tag to create this pointer… you must use struct structure_name * structure_element_name • To build the first structure instance, you need to use malloc( ) and you need to use a pointer to hold and retain this first structure instance's address • Let's add another structure instance and link it to the first structure instance • To make things a little easier, will introduce the concept of "reusable pointers"
#include <stdio.h> // 8.c #include <string.h> #include <stdlib.h> typedef struct vehicle { char make[15] ; char model[15] ; char color[8] ; struct vehicle * next_vehicle ; } vhcl ; int main (void) { vhcl * first_truck ; vhcl * current_truck ; // Reusable pointers vhcl * new_truck ; // Let's create the first structure instance first_truck = ( vhcl * ) malloc ( sizeof ( vhcl ) ) ; if (first_truck == NULL) { puts("\n\nNot enough memory available… sorry.\n\n"); } // continued on next slide
// Let's populate the first structure instance strcpy(first_truck->make, "Chevy") ; strcpy(first_truck->model, "Suburban") ; // first_truck pointer for first instance strcpy(first_truck->color, "Brown") ; new_truck = ( vhcl * ) malloc ( sizeof ( vhcl ) ) ; first_truck->next_vehicle = new_truck ; // Let's populate the second structure instance current_truck = new_truck ; strcpy(current_truck->make, "Mazda") ; strcpy(current_truck->model, "Miata M1") ; // current_truck pointer for second instance strcpy(current_truck->color, "Blue") ; new_truck = ( vhcl * ) malloc ( sizeof ( vhcl ) ) ; // reused new_truck current_truck->next_vehicle = new_truck ; // reused current_truck // Let's populate the the structure instance current_truck = new_truck ; strcpy(current_truck->make, "Hummer") ; // current_truck pointer for third instance strcpy(current_truck->model, "H1") ; strcpy(current_truck->color, "Black") ; current_truck->next_vehicle = NULL ;
// Let's display what we have in our linked list printf("\n\nThe first structure instance was created and here are its contents: \n") ; printf("Make: %s \nModel: %s \nColor: %s \nNext Structure Instance Address: %p \n" , first_truck->make , first_truck->model , first_truck->color, first_truck->next_vehicle ) ; current_truck = first_truck-> next_vehicle ; printf("\n\nThe second structure instance was created and here are its contents: \n") ; printf("Make: %s \nModel: %s \nColor: %s \nNext Structure Instance Address: %p \n" , current_truck->make , current_truck->model , current_truck->color, current_truck->next_vehicle ) ; // reused current_truck current_truck = current_truck-> next_vehicle ; printf("\n\nThe third structure instance was created and here are its contents: \n") ; printf("Make: %s \nModel: %s \nColor: %s \nNext Structure Instance Address: %p \n" , current_truck->make , current_truck->model , current_truck->color, current_truck->next_vehicle ) ; // reused current_truck return ( 0 ) ; }
Dynamic Memory Allocation • malloc( ) and calloc( ) often used interchangeably • calloc( ) advantage is that it initializes all newly allocated numeric memory to 0 and character memory to NULL • malloc( ) is the more general purpose • malloc(5*sizeof(int)) or calloc(5,sizeof(int)) requests enough memory to store 5 integers • The space allocated by malloc( ) comes from the computer’s heap
Dynamic Memory Allocation • Let's use malloc ( ) to create an array
Traditional Array Creation #include <stdio.h> //My file 9.c #define size 5 int main (void) { int i ; float test_scores [size] , total = 0.0 , average = 0.0 ; for ( i = 0 ; i <= 4 ; i = i + 1) { printf("\n Enter a test score: "); scanf("%f", &test_scores [i] ); } for ( i = 0 ; i <= 4 ; i = i + 1) total = total + test_scores[i] ; average = (float) total / size; printf ("\n\n The average of your test scores is: %.2f \n\n\n", average); return (0) ; } • Array Creation Using Dynamic Memory Allocation
#include <stdio.h> //My file 10.c (9.c with somewhat dynamic memory allocation) int main (void) { int i , num_test_scores ; float *test_scores, total = 0.0 , average = 0.0 ; printf("\n\nEnter the number of test scores to be entered: "); scanf("%d" , &num_test_scores) ; test_scores = (float *) malloc (num_test_scores * ( sizeof ( float ) ) ) ; if (test_scores == NULL) { printf("\n\nArray creation failed.\n\n"); return (1) ; } for ( i = 0 ; i < num_test_scores ; i = i + 1) { printf("\n Enter a test score: "); scanf("%f", &test_scores [i] ); } for ( i = 0 ; i < num_test_scores ; i = i + 1) total = total + test_scores[i] ; average = (float) total / num_test_scores; printf ("\n\n The average of your test scores is: %.2f \n\n\n", average); free (test_scores) ; return (0) ; }