3

I'm trying to run the following code in the basic ubuntu gcc compiler for a basic C class.

#include<stdio.h>

struct emp
{

  int emp_num, basic;
  char name[20], department[20];

};

struct emp read()
{
  struct emp dat;

  printf("\n Enter Name : \n");
  scanf("%s", dat.name);

  printf("Enter Employee no.");
  scanf("%d", &dat.emp_num);

  //printf("Enter department:");
  //fgets(dat->department,20,stdin);

  printf("Enter basic :");
  scanf("%d", &dat.basic);

  return dat;
}

void print(struct emp dat)
{
  printf("\n Name : %s", dat.name);

  printf("\nEmployee no. : %d", dat.emp_num);

  //printf("Department: %s", dat.department);

  printf("\nBasic : %d\n", dat.basic);
}

int main()
{
  struct emp list[10];

  for (int i = 0; i < 3; i++)
  {
    printf("Enter Employee data\n %d :\n", i + 1);
    list[i] = read();
  }

  printf("\n The data entered is as:\n");

  for (int i = 0; i < 3; i++)
  {
    print(list[i]);
  }

  return 0;
}

I want the name to accept spaces.

The problem comes when I'm entering the values to the structures. I am able to enter the name the first time but the subsequent iterations don't even prompt me for an input.

I've tried using fgets, scanf("%[^\n]",dat.name) and even gets() (I was desperate) but am the facing the same problem every time.

The output for the 1st struct is fine but for the rest is either garbage, the person's last name or just blank.

Any ideas?

3
  • 1
    If you really need to "scan" "strings" from the user use %Ns with N being replaced by an integer describing the size of the buffer to read into. In the OP's example this would be %19s leaving room for the necessary 0-termination of the "string". Doing so avoids potential buffer overflows.
    – alk
    Commented Sep 1, 2013 at 10:27
  • But scanf doesn't read spaces and I want people to be able to enter their full name
    – Suman Roy
    Commented Sep 1, 2013 at 14:54
  • So you might switch to fgets() or even read() and do the parsing of what had been entered on your own.
    – alk
    Commented Sep 1, 2013 at 17:39

3 Answers 3

3

When reading a string using scanf("%s"), you're reading up to the first white space character. This way, your strings cannot include spaces. You can use fgetsinstead, which reads up to the first newline character.

Also, for flushing the input buffer, you may want to use e.g. scanf("%d\n") instead of just scanf("%d"). Otherwise, a subsequent fgets will take the newline character and not ask you for input.

I suggest that you experiment with a tiny program that reads first one integer number and then a string. You'll see what I mean and it will be much easier to debug. If you have trouble with that, I suggest that you post a new question.

5
  • could you be a little more specific because I think my problem has something to do with the buffer. and like I said I have already tried fgets() but with the same result
    – Suman Roy
    Commented Sep 1, 2013 at 10:44
  • You need to flush the buffer in between reading an integer number and a string, if you expect the two to be given in two different lines. Do this by scanf("%d\n", &n);. As I think you don't understand well enough how the input buffer works, try experimenting with a small program first.
    – nickie
    Commented Sep 1, 2013 at 10:49
  • But if I do that I'll have to enter an extra value between the actual values I need. And if do put another scanf() before printf("Enter Employee no."); I get get promted for data at all the wrong points.
    – Suman Roy
    Commented Sep 1, 2013 at 14:52
  • 1
    Look, I hate doing other people's exercises. This is not necessarily your case, but I feel it is. I think that the point in all this is to be guided to the right direction, not to be given the solution to a very simple problem in your hand.
    – nickie
    Commented Sep 1, 2013 at 15:03
  • @user2737039 Also try another call to fgets() and then strtol() for getting an integer instead of messing around with scanf(). The scanf() function is so counterintuitive and certainly not trivial to use that all beginners better stay far away from it.
    – user529758
    Commented Sep 1, 2013 at 20:18
3

The problem is that scanf("%[^\n",.. and fgets don't skip over any whitespace that may be left over from the previous line read. In particular, they won't skip the newline at the end of the last line, so if that newline is still in the input buffer (which it will be when the last line was read with scanf("%d",..), the scanf will fail without reading anything (leaving random garbage in the name array), while the fgets will just read the newline.

The easiest fix is to add an explicit space in the scanf to skip whitespace:

printf("\n Enter Name : \n");
scanf(" %19[^\n]", dat.name);

This will also skip over any whitespace at the beginning of the line (and blank lines), so may be a problem if you want to have a name that begins with a space.

Note I also added a length limit of 19 to avoid overflowing the name array -- if the user enters a longer name, the rest of it will be left on the input and be read as the employeee number. You might want to skip over the rest of the line:

scanf("%*[^\n]");

This will read any non-newline characters left on the input and throw them away. You can combine this with the prior scanf, giving you code that looks like:

printf("\n Enter Name : ");
scanf(" %19[^\n]%*[^\n]", dat.name);
printf("Enter Employee no. : ");
scanf("%d%*[^\n]", &dat.emp_num);
printf("Enter department : ");
scanf(" %19[^\n]%*[^\n]", dat.department);
printf("Enter basic : ");
scanf("%d%*[^\n]", &dat.basic);

This will ignore any spurious extra stuff that someone enters on a line, but will still have problems with someone entering letters where numbers are expected, or end-of-file conditions. To deal with those, you need to be checking the return value of scanf.

5
  • sorry, I tried it and still having the same problem; I still dont get the prompt for the next name.
    – Suman Roy
    Commented Sep 2, 2013 at 11:33
  • @user2737039: take the code you posted, change the "%s" in the scanf to " %19[^\n]", and it works fine, as long as you don't enter a too-long name. Don't forget the space -- it is very important.
    – Chris Dodd
    Commented Sep 2, 2013 at 17:24
  • Not sure why you have %*[^\n] in some of the scanfs. They fail because the %[^\n] format specifier will fail if the first character to be read is a \n.
    – Spikatrix
    Commented Feb 21, 2017 at 12:10
  • @CoolGuy: Those are to consume and discard everything up to the next newline. If there is nothing, they will do nothing, but if there is random garbage left on the line (if the string entered was too long, or there was cruft after the number), it will be discarded.
    – Chris Dodd
    Commented Feb 23, 2017 at 5:55
  • Ah, yes. You're right. Forgot about the case when input is too long. My bad.
    – Spikatrix
    Commented Feb 23, 2017 at 6:30
0

What you have tried was:-

scanf("%[^\n]",dat.name)

In this you forgot to specify the specifier.

You can try to use this:-

scanf ("%[^\n]%*c", dat.name);

or fgets() if you want to read with spaces.

Note:- "%s" will read the input until whitespace is reached.

6
  • actually i tried it both way with the same result
    – Suman Roy
    Commented Sep 1, 2013 at 10:40
  • Did you try to use this:- scanf("%[^\n]s",dat.name); ?? as it keeps taking in values until it encounters a '\n' Commented Sep 1, 2013 at 10:44
  • I did that too. It'll read the spaces. but i dont get a promt to enter the next string
    – Suman Roy
    Commented Sep 1, 2013 at 14:42
  • -1: the [ is the specifier; there's no need for another specifier after it (unless you want to read something else as well.)
    – Chris Dodd
    Commented Sep 1, 2013 at 20:18
  • @ChrisDodd:- So what you mean is scanf ("%[^\n]%*c", dat.name); is equivalent to scanf("%[^\n]",dat.name); ??? Please correct me if I am missing something!! Commented Sep 1, 2013 at 20:20

Not the answer you're looking for? Browse other questions tagged or ask your own question.