1.     #define MAX_NAME_SIZE 20
        typedef struct {
          char part_name[MAX_NAME_SIZE];
          int part_id;
          int quantity_on_hand;
          double cost;
        } Part;
      

    1. Declare a Part variable named "my_part" and initialize it with the values "water filter", 368, 45, 49.99.
       
        Part my_part;
        strcpy(my_part.part_name, "water filter");
        my_part.part_id = 368;
        my_part.quantity_on_hand = 45;
        my_part.cost = 49.99;
      

    2. What is the rationale for declaring 20 as a constant, rather than hard-coding it in the declaration of the array?

      The rationale for declaring 20 as a constant is that if I later change the size of the maximum name, I only have to change it in one place in the code, rather than in all the places where I used the constant. Another reason for declaring 20 as a constant is to distinguish it from other constants that also have a value of 20. Suppose that I hard-coded my constants and suppose that I have several constant values that are 20, such as the maximum word size and the maximum number of days that we wait before we send a dunning note to a customer. Then when the maximum word size changes, not only will I have to find all hard coded values of 20, but I will have to determine whether or not they refer to the maximum word size, in which case they should be changed, or the maximum billing date, in which case they should not be changed.

    3. Write a scanf statement that reads a floating point number from stdin into the cost field of my_part.
        // don't forget the & operator, because cost is a float
        scanf("%lf", &my_part.cost);    
      

    4. Write a scanf statement that reads a string into the part_name field of my_part.
        // I don't need the & operator because part_name is a string
        scanf("%s", my_part.part_name);
      

  2. Design an anonymous struct and use a typedef to name it SupplierAddress. It should have fields named street_address, city, state, and zip_code. The street address and the city should be C-strings with a maximum length of 30 characters, the state should be a two character C-string, and the zip code will be an integer.

    #define MAX_STREET_ADDRESS 30
    #define MAX_CITY_SIZE 30
    #define MAX_STATE_SIZE 2
    
    typedef struct {
      char street_address[MAX_STREET_ADDRESS];
      char city[MAX_CITY_SIZE];
      char state[MAX_STATE_SIZE];
      int zip_code;
    } SupplierAddress;
    
    1. 0xff4e7a98 + 0x4 = 0xff4e7a9c
    2. 0xfe93ab86 + 0x95 = 0xfe93ac1b

  3. Put a check mark next to any of the following statements that is illegal. Put an 'X' next to any of the following statements that might eventually cause a segmentation violation or bus error. Consider each statement in isolation and assume that all variables have already been initialized to valid values. If there is more than one statement on a line consider the statements as a group (e.g., if the combined effect of the statements might be to eventually cause a segmentation violation, then put an 'X' next to the statements).
           char name[20];
           char first_name[10];
           char last_name[20];
           char *str_ptr;
           
           _/ = checkmark
    
           _/  name = str_ptr;   (cannot assign a pointer to a statically allocated array)
    
               str_ptr = name;   (legal)
    
           _/  if (name == "brad") { ... } (must use strcmp instead)
    
           _/  name = "sue"; (must use strcpy instead)
    
           _/  first_name = strdup("tom"); (cannot assign a pointer to a statically alocated array)
    
           X   strcpy(name, first_name); strcat(name, last_name); (The second strcat may write
                                  past the end of name's memory)
    
               name[10] = 'c';  (legal)
    
           X   str_ptr[10] = 'c'; (could be a write past str_ptr's memory, depending on the
                                    size of the string currently pointed to by str_ptr)
           
    1. What is the output of printf statement (1)? puppy 5
    2. What is the output of printf statement (2)? 0xffbef98c 0xffbef978
    3. What is the output of printf statement (3)? 0xffbef980
    4. What is the value of *double_int_ptr? 0xffbef98c
    5. What is the value of **double_int_ptr? 5
    6. 	                                --------------------
      	  0xffbef974 double_int_ptr     | 0xffbef978       |
      
      	  0xffbef978 int_ptr            | 0xffbef98c       |
      
      	  0xffbef97c string_ptr         | 0xffbef980       |
      
      	  0xffbef980 word               | 'p' 'u' 'p' 'p'  |
      
      	  0xffbef984 word (continued)   | 'y' '\0' ?   ?   |
      
      	  0xffbef988                    | ?????            |
      
      	  0xffbef98c count              | 5                |
      	                                --------------------
                

    1. test1.c:
      	s = 0xefffe4f8
              i=0 x=0xefffe4f8 x=Plank *x=P x-s=0
              i=1 x=0xefffe4f9 x=lank *x=l x-s=1
              i=2 x=0xefffe4fa x=ank *x=a x-s=2
              i=3 x=0xefffe4fb x=nk *x=n x-s=3
              i=4 x=0xefffe4fc x=k *x=k x-s=4
      	
    2. test2.c:
      	s = 0xefffe4f0
      	i = 0 x=0xefffe4f0 *x=50 x-s=0
      	i = 1 x=0xefffe4f4 *x=51 x-s=1
      	i = 2 x=0xefffe4f8 *x=50 x-s=2
      	i = 3 x=0xefffe4fc *x=51 x-s=3
      	i = 4 x=0xefffe500 *x=50 x-s=4
      	
    3. test3.c:
      	Enter two words:
      	Jim Plank
      	Smaller is Jim
      	Enter two words:
      	Tee Martin
      	Smaller is Martin
      	Enter two words:
      	Sammy Sosa
      	Smaller is Sammy
      	Enter two words:
      	vols VOLS
      	Smaller is VOLS
      	Enter two words:
      	VOLS VOLS
      	Segmentation fault
      	
      The program seg faults on the last pair of words because smaller returns a null pointer. Hence when printf tries to de-reference the pointer to print the string it seg faults because it is de-referencing a null pointer.

    1. debug1.c: scanf seg faults because no memory has been allocated for x or y, which are the arguments for string1 and string2. An appropriate fix is to malloc memory for x and y before the call to read_strings:
      	 x = (char *)malloc(sizeof(char)*30);
      	 y = (char *)malloc(sizeof(char)*30);
      	 
    2. debug2.c: The second strcat command in concatenate seg faults because string1 (which is x) has only 10 bytes of memory allocated to it and you are trying to create a concatenated string that can have as many as 30 characters in it (9 from x, 19 from y, 1 for a null character, and 1 for the " ").

      A good solution is to have concatenate allocate a larger block of memory for string1 that can hold the entire concatenated string and return a pointer to this memory to the calling function:

      char *concatenate(char *string1, char *string2) {
          char *new_str = (char *)malloc(sizeof(char)*(strlen(string1)
                                                      +strlen(string2)+2));
          strcpy(new_str, string1);
          strcat(new_str, " ");
          strcat(new_str, string2);
          return new_str;
      }
      ...
      main() {
      ...
          /* it is always a good idea to free old memory so that you do not lose 
             it. */
          char *new_str = concatenate(x, y);
          free(x);
          x = new_str;
      }
      
      You may wonder why I simply did not assign the newly malloc'ed memory to string1. It's a bit complicated, but basically string1 is a copy of x and so changing the block of memory to which string1 points does not change the block of memory to which x points. As you become more experienced with pointers you will be better able to understand this point.

    3. debug3.c: debug3 is supposed to determine the maximum length string in the input and print the string and its length. As written, debug3 correctly computes and prints the maximum length, but it prints the last word in the input, rather than the maximum-length word in the input. The problem lies with the statement:
      save_largest_str = input_string;
                 
      The intent of this statement is to copy the contents of input_string to save_largest_str. However, remember that you cannot use the '=' operator to assign strings in C. If you try it, you get a pointer assignment instead of a string assignment. In this case save_largest_str ends up with the memory address of input_string, and hence points to whatever input_string points to, which is the last read string.

      To assign strings you must use either strcpy or strdup. In this situation I suggest using strdup because you are not sure about the size of the string being copied. Here is a clean fix with the changed statements bold-faced:

      /* initialize save_largest_str to 0 so that the first time you try to free
         its memory, you do not free a random piece of memory. free checks to
         see if a pointer is initialized and simply returns if the pointer is 
         set to NULL. */
         char *save_largest_str = 0;
         int max_length = 0;
         char input_string[20];
      
         while (scanf("%s", input_string) != EOF) {
           if (max_length < strlen(input_string)) {
             max_length = strlen(input_string);
             /* it is always a good idea to free memory whenever you no longer
                need it so that you prevent memory leaks */
             free(save_largest_str); 
             save_largest_str = strdup(input_string);
           }
         }