睿宏 陳
PRO
last month
睿宏country asked

Sorry I'll ask the question again. I've corrected all of the previous problems and come up with the following code: int main(){ scanf("%d", &employee1.age); getchar(); fgets(employee1.name, sizeof(employee1.name), stdin); printf("%s", employee1.name); printf("%d" employee1.age); return 0; } But if I want to combine the following two lines of code? printf("%s", employee1.name); printf("%d", employee1.age); Why is it: printf("%s%d", employee1.name, employee1.age); rather than printf("%s\n%d", employee1.name, employee1.age); I'm still so confused.

Udayan Shakya
Expert
last month
Udayan Shakya answered

Hi there!

Your confusion is completely natural because there are a lot of advanced and deeper aspects of C programming that we haven't taught yet (because they're beyond the scope of our course).

Basically, you're asking why we don't need to print \n right after printing employee1.name, right? That's because of how fgets works.

Basically, fgets not only stores the name that you entered inside employee1.name, but it also stores the newline character \n.

How does this happen?

To give the name input, we type the name and then press the Enter key. Hitting the enter key inputs the newline character \n into the input stream, which fgets ends up storing inside employee1.name.

So if you've entered Brad Pitt as input, fgets will store it like this:

employee1.name = "Brad Pitt\n\0"

Note: Please remember that \0 is the null terminator that's present at the end of all strings in C.

So when you print employee1.name, the \n is already included in that variable. That's why you use

printf("%s %d", employee1.name, employee1.age);

instead of

printf("%s\n%d", employee1.name, employee1.age);

But scanf("%s", string_var) behaves differently

On the other hand, if you use something like this:

scanf("%s", employee1.name) 

then the newline character does not get stored inside employee1.name because scanf throws out everything that comes after a whitespace (including the whitespace itself).

The drawback here is that you can only store a single word.

What's the solution?

The solution I gave you before is good enough, but it's still not perfect because employee1.name stores \n at the end.

This can cause a lot of problems in more complex programs because a name string (or any other string) should only contain the required data (i.e., the name) without unnecessary whitespaces.

So the solution is to trim the string after using fgets.

You can remove/trim the string by following the steps below:

  1. Import the string.h header file by using #include .

  2. Use strcspn() to get the index of the \n character in the string.

  3. Then, replace the character at that index with the null terminating character \0 so that \n gets completely removed.

Here's how to do this:

Using strcspn() to get index of \n

// Get the index of \n
int newline_index = strcspn(employee1.name, "\n");

Here, strcspn(employee1.name, "\n") compares two strings: employee1.name and "\n", and gives the index of the first occurrence of the second string i.e., "\n".

Since employee1.name has only one instance of \n in it, strcspn() effectively gives us the position of the extra line at the end of this string.

Then, we remove this newline character by replacing it with \0:

// Replace the \n with \0
employee1.name[newline_index] = '\0';

You can also simply combine the two steps like this:

employee1.name[strcspn(employee1.name, "\n")] = '\0';

Here's the FULL SOLUTION:

#include 
#include 

// create Person struct
struct Employee {
  int age;
  char name[50];
};

int main() {

  // create struct variable
  struct Employee employee1;

  // get age input for employee1's age
  scanf("%d", &employee1.age);
  getchar();

  // get name input for employee1's name
  fgets(employee1.name, sizeof(employee1.name), stdin);

  // Get the index of \n
  int newline_index = strcspn(employee1.name, "\n");

  // Replace the \n with \0
  employee1.name[newline_index] = '\0';
  
  // print name and age
  printf("%s\n", employee1.name);
  printf("%d", employee1.age);

  return 0;
}

Note: It's better to use employee1.name[strcspn(employee1.name, "\n")] = '\0'; instead of storing the \n index in a separate variable. The whole point of C programming is to be memory-efficient.

Why is this not included in the course (or in my previous answers)?

I wanted to inform you about this issue yesterday but thought the answer might get too long and confusing.

So I'm thankful that you asked this followup question.

Currently, our course cannot go into such deep detail because it's aimed at absolute beginners.

For now, I can only tell learners how to properly deal with it when they ask questions, as you've done here.

I hope you found this helpful! Please don't hesitate to ask further questions if you're still confused.

C
This question was asked as part of the Learn C Programming course.