The Crashing Name-Sorter in C
Ananya writes a C program for the school office. It reads 10 student names with fgets(names[i], 20, stdin) into char names[10][20], sorts them with strcmp and strcpy, and writes the sorted list to names.txt. On testing, the last name is missing, one long name such as “Chinmayee Mohapatra” is cut off, and the program sometimes crashes during swapping because she wrote char *temp; strcpy(temp, names[i]);. The file also begins with a blank line. Her teacher says the array size and newline handling are both suspect. Ananya wants to keep using fgets because names may contain spaces, but she needs a correct, safe program. You are asked to diagnose the faults and propose fixes without rewriting the whole program.
1. Identify the causes of the missing last name, the truncation, the crash, and the blank line. Tie each symptom to a specific C behaviour.
Read the worked answer
Four separate faults. (1) The crash: char *temp; is an uninitialised pointer; strcpy(temp, names[i]) writes to an arbitrary address. It must point to a real buffer, e.g. char temp[20];. (2) The blank line: fgets stores the newline if it fits, so a name may contain a trailing '\n'; after sorting, that can produce an empty-looking line in the file. Strip the newline after each read. (3) Truncation: fgets(names[i], 20, ...) stores at most 19 characters plus '\0'. “Chinmayee Mohapatra” is 19 characters, so the newline cannot fit; if a name is longer, it is cut. Use a larger row, e.g. 40 or 64 bytes. (4) Missing last name: a leftover newline from the previous line can make the next fgets read only '\n', shifting all later names and leaving the tenth read empty. Consume or strip newlines consistently after every read.
2. Give a corrected swap for the sort and a safe way to remove the newline after `fgets`. Explain why the destination buffer matters.
Read the worked answer
Safe swap:
char temp[20];
strcpy(temp, names[i]);
strcpy(names[i], names[j]);
strcpy(names[j], temp);
temp is an array with its own storage, so strcpy has a valid destination. If rows are enlarged to 40, use char temp[40]. Strip the newline immediately after each fgets:
size_t len = strlen(names[i]);
if (len > 0 && names[i][len-1] == '\n')
names[i][len-1] = '\0';
Also check the return value of fgets; if it returns NULL, stop reading. Never use gets. The destination in strcpy must have enough space for the source plus the terminating null byte; an uninitialised pointer has no such space.
3. Explain why `fgets` is preferable to `scanf('%s')` here, and what still goes wrong if an input line is longer than the buffer.
Read the worked answer
fgets reads a whole line including spaces and limits the number of characters, so a name like “R. K. Padhi” stays intact. scanf('%s', ...) stops at the first whitespace, so it stores only “R.” and leaves “K.” for the next read; it also has no buffer-size limit, so a long input can overflow the array. fgets(names[i], 20, stdin) is safer, but if the line is longer than 19 characters, it stores only the first 19 and leaves the rest in the input buffer. The next fgets then reads the remainder as if it were a new name. That is exactly the truncation and shifting symptom. With a 40-byte buffer and newline stripping, ordinary names are handled; for arbitrary input, detect the missing newline and discard the rest of the line.