#define MAX_NAME_SIZE 20 typedef struct { char part_name[MAX_NAME_SIZE]; int part_id; int quantity_on_hand; double cost; } Part;
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;
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.
// don't forget the & operator, because cost is a float scanf("%lf", &my_part.cost);
// I don't need the & operator because part_name is a string scanf("%s", my_part.part_name);
#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;
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)
-------------------- 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 | --------------------
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
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
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 faultThe 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.
x = (char *)malloc(sizeof(char)*30); y = (char *)malloc(sizeof(char)*30);
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.
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); } }