Algorithmic Thinking: A Problem-Based Introduction Homepage for the book Algorithmic Thinking: A Problem-Based Introduction

Eliminating the gets Function

Hi everyone,

gets is an unsafe C function that reads from standard input. It’s unsafe because once you call gets, you have no control over how much stuff gets reads. If someone provides too much input, gets keeps reading and reading, clobbering whatever happens to get in its way.

In the Algorithmic Thinking book, I used the C gets function a few times.

I Did What??

Take a look at Listing 2-19 in the book, and you’ll see that I used gets to read a string. In this context, it’s safe, because we know the maximum number of characters that could be provided in a test case. It was also an easy way for me to read a string and not distract from our main task.

But gets is removed from C as of C11, so maybe your compiler will give a warning or outright reject programs that use gets. Or maybe you just don’t want to use it, and want to know what to use instead.

Replacing gets

We can replace calls of gets with fgets. We have to be a little careful, as you’ll see now. Here’s listing 2-19 again, replacing gets by fgets:

#define SIZE 255
#define TEST_CASES 5

int main(void) {
  int i;
  char line[SIZE + 2];
  node *tree;
  for (i = 0; i < TEST_CASES; i++) {
    fgets(line, SIZE + 2, stdin);
    line[strlen(line) - 1] = '\0';
    tree = read_tree(line);
    tree_solve(tree);
  }
  return 0;
}

To call fgets instead of gets, we need three arguments instead of one: the string to read into, the size of that string, and the file to read from (9).

One annoyance for us here is that fgets includes the newline in the string that it produces. (gets doesn’t do that; it throws the newline away without storing it.) To get rid of that newline, I find the length of what fgets produced and replace the final character (the newline) with a null character (10).

The second argument to fgets, the SIZE + 2 here, is what tells fgets the size of the array that it’s reading into. Here, we’re saying that fgets is reading into an array that has room for SIZE + 2 characters. fgets reads at most one character less than this, so that it’s guaranteed to have room for the null character. So, here, fgets will read at most SIZE + 1 characters. We’re safe: the SIZE covers the string from the test case, and the + 1 covers the newline that it will read.

What if the input ends without a newline? What if fgets fails to read anything at all? These are concerns for code in the wild, of course, but as in the rest of the book I’ve gone light on error-checking so as to not distract from the data structure/algorithm content.

Since You’re Here…

There are a few different ways to get rid of the newline that fgets leaves at the end of the string that it produces. You can check out some of that fgets newline discussion on Stack Overflow.

One of the coolest solutions provided there goes like this:

line[strcspn(line, "\n")] = '\0';

It’s clear that this code somehow finds the newline and replaces it by the null character. But how? The secret is the strcspn C function, which I hadn’t known about prior to reading about it here. It takes two arguments: the first is a string to search, and the second is a string of characters to search for. It returns the number of characters that it finds in the first string before it finds one of the characters from the second string. Here, we’re using it to tell us how many characters are found in line before the newline. That gives us the index of the newline character, which we replace by the null character. (For example, imagine that line consists of hello\n. Then, when searching for the \n, strcspn would return 5. Index 5 is where the newline is, which is exactly what we need to replace by the null character.)

And what if there is no newline at all in line? No problem for strcspn: in this case, strcspn returns the length of the string, so we end up just replacing the null character with another null character.

Happy Holidays!

Thank you all for your engagement and support of my work. There are a zillion ways that you could be spending your time online, a zillion things you could be reading. I appreciate you making time for what I have to say, and in return I hope it has been well worth it in terms of your learning.