Accepting string characters with space using C I/O only.

As you can see, I am working on file handling right now. The only problem is with gets() function. Well, the codes were in cin and cout at first but then my professor wants us to use printf() and scanf(). But, look at my line 19. I know that we should NEVER use gets(). Again, It's because of my professor's requirment not to use any cin or cout. More of a restriction, right? Don't know the reason why but I have to meet up with what she want. Any suggestion to my problem with the accepting string characters with space?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <iostream>

using namespace std;

int main()
{
  char prodnum[8],title[50], write[50],ans,ans2,c;
  float price;
  FILE *fp;   
  
      do{
      system("cls");
      printf("Product No. : ");
      scanf("%s",&prodnum);
      printf("Enter a title : ");
      gets(title);
      printf("Price: ");
      scanf("%f",&price); 
      
      printf("\n%s\n%s\n%.2f\n",prodnum,title,price);
      
          do{
          printf("Save this product?[Y/N]: ");
          scanf("%s",&ans);
          }while((ans=='Y' || ans=='y') && (ans=='N' || ans=='n'));
          
          if(ans=='Y' || ans=='y')
          
            fp=fopen("DVD.DBF","a");
          if(!fp)
              {
               printf("Could not open file!");
               exit(101);
              }
           else
             { strcpy(write,title);
               fprintf(fp,"\n%d %s %.2f ",prodnum,title,price);
               printf("Record Saved!!!\n");
              
             }
           if (fclose(fp)==EOF)
             {
               printf("Could not close file!!!");
               exit(201);
             }  
             
             printf("Add New Product?[Y/N]: ");
             scanf("%s",&ans2);
             
    }while(ans2=='Y' || ans2=='y' && ans2=='N' || ans2=='n');
  
 getch();
 return 0;    
}


Thanks alot guys. :)
Well it looks like the instream still has a '\n' and when gets() finds that, it immediately exits storing nothing.

Maybe try adding a scanf("%*c", title) before your gets()? That should remove the '\n' character from the stream and ignore it so you can input your title via gets().
Wow! Thanks wolfgang! It worked. But, how? Can you explain it to me. Thanks again! :D
When you call scanf("%s", &prodnum) it reads everything up to the first whitespace character it finds. So if we enter something like "5063(Return)" it puts in the instream "5063\n". Note the \n? Well that actually is put into the stream. scanf() then inputs every character up to but not including the '\n'. So now in the stream is '\n' and inside your prodnum is "5063". Now gets() comes to get its data from the stream. It checks the stream expecting nothing but finds a '\n' character. It reads that in which also happens to be its delimiter or expected end to a string. So it inputs into your character array "\0" which is basically nothing. Since gets() hits its delimiter character it doesn't prompt for input to the stream and ends. That is why it skips.

When you add the scanf("%*c", title) it looks for a character in the stream, like '\n' in this case, and reads it into the title object. But I specified %*c which instead ignores putting the first character it finds into the object.

There is probably a better way to ignore the '\n' or any other character by flushing the stream before you run gets() but I do not know of it.
Wouldn't a simple call to getchar() suffice after gets() ?

Edit: I raise the point because it takes more time for a program to handle the call to scanf() than it does to simply extract '\n' from stdin via getchar().
Last edited on
Not necessarily. Under the gnu toolchain scanf, etc is handled specially.
Still having problem with the gets() function. Aside from removing '\n'? How can I remove whitespaces created by '\b'? I have a problem displaying my input from the stream but in my file the program writes properly what I have entered. It's just how I display it. Here is what I have so far. Maybe you guys can take a look at it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <windows.h>

using namespace std;

void gotoxy( int column, int line )// Positioniong of cursor.
  {
  COORD coord;
  coord.X = column;
  coord.Y = line;
  SetConsoleCursorPosition(
    GetStdHandle( STD_OUTPUT_HANDLE ),
    coord
    );
  }

int wherex()
  {
  CONSOLE_SCREEN_BUFFER_INFO csbi;
  COORD                      result;
  if (!GetConsoleScreenBufferInfo(
         GetStdHandle( STD_OUTPUT_HANDLE ),
         &csbi
         ))
    return -1;
  return result.X;
  }

int wherey()
  {
  CONSOLE_SCREEN_BUFFER_INFO csbi;
  COORD                      result;
  if (!GetConsoleScreenBufferInfo(
         GetStdHandle( STD_OUTPUT_HANDLE ),
         &csbi
         ))
    return -1;
  return result.Y;
  }

void ClearScreen()// Clearing the screen.
  {
  HANDLE                     hStdOut;
  CONSOLE_SCREEN_BUFFER_INFO csbi;
  DWORD                      count;
  DWORD                      cellCount;
  COORD                      homeCoords = { 0, 0 };

  hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
  if (hStdOut == INVALID_HANDLE_VALUE) return;

  /* Get the number of cells in the current buffer */
  if (!GetConsoleScreenBufferInfo( hStdOut, &csbi )) return;
  cellCount = csbi.dwSize.X *csbi.dwSize.Y;

  /* Fill the entire buffer with spaces */
  if (!FillConsoleOutputCharacter(
    hStdOut,
    (TCHAR) ' ',
    cellCount,
    homeCoords,
    &count
    )) return;

  /* Fill the entire buffer with the current colors and attributes */
  if (!FillConsoleOutputAttribute(
    hStdOut,
    csbi.wAttributes,
    cellCount,
    homeCoords,
    &count
    )) return;

  /* Move the cursor home */
  SetConsoleCursorPosition( hStdOut, homeCoords );
  }
  

struct dvd{
  
  int looping;
  char num[8];
  char name[30];
  char title[50];
  float price, cash;  
  
  };

dvd dvd[30],cust;

FILE *fp;

void mainUI()
{
     gotoxy(36,3);
     printf("Video City");
     gotoxy(34,4);
     printf("Rental System");
     gotoxy(18,7);
     printf("[1]Rent DVDs                  [2]Add new DVDs");
     gotoxy(18,9);
     printf("[3]View Available DVDs        [4]Transactions Made");
     gotoxy(36,12);
     printf("[5]Exit");
     gotoxy(18,16);
     printf("Option: ");
     
     
}

void addProdsInput()
{
     int x=0;
     char c;
      printf("Product No. : ");
      scanf("% *c",dvd[x].num);
      scanf("%s",&dvd[x].num);
      printf("Enter a title : ");
      scanf("% *c",dvd[x].title);
      gets(dvd[x].title);
      printf("Price: ");
      scanf("% *c",dvd[x].price);
      scanf("%f",&dvd[x].price); 
      getchar();
      printf("\nDVD: %s    %s     PHP %.2f",dvd[x].num,dvd[x].title,dvd[x].price);    
      
}
void addProds()
{   
  char ans,ans1;
  int x=0;
     
do{
      ClearScreen();
      addProdsInput();
      
      gotoxy(0,5); printf("Save this product?[Y/N]: ");
                   ans=getchar();
          
     if(ans=='Y' || ans=='y')
          
          {
             fp=fopen("DVD.TXT","a");
            
             if(!fp)
              {
               printf("Could not open file!");
               exit(101);
              }
             else
             { 
               fprintf(fp,"\n%s %s %.2f ",dvd[x].num,dvd[x].title,dvd[x].price);
               gotoxy(0,6); printf("Record Saved!!!\n");  
             }
             
            if (fclose(fp)==EOF)
             {
               printf("Could not close file!!!");
               exit(201);
             }  
          }    
     
     else if(ans=='N' || ans=='n')
          printf("Data Not SAVED!");           
     else
         printf("\nInvalid INPUT! GOODBYE!");
             gotoxy(0,8); printf("Add New Product?[Y/N]: ");
                           scanf("%s",&ans1);
                         getchar();    
                         getchar();             
    }while(ans1=='Y' || ans1=='y');
       if(ans1=='N' || ans1=='n')
          printf("Thank you! :D");
       else
          {
           printf("\nInvalid Input");
           getchar();
           exit(1);
          }
}



void viewProds()
{
     
     char ans,ans1,ans_;
     int x=0;
     
     ClearScreen();
     gotoxy(35,1);
     printf("View DVDs");
     gotoxy(8,4);
     printf("DVD No.");
     gotoxy(30,4);
     printf("Title");
     gotoxy(48,4);
     printf("Price");
     gotoxy(65,4);
     printf("Available");

	{
            
	  fp=fopen("DVD.TXT","r");


	    if(!fp)
		{
		  printf("Could not open File!!!");
		  exit(101);
		}
		else
			{
              while(fscanf(fp,"%s %s  %f", &dvd[x].num, &dvd[x].title, &dvd[x].price)!=EOF) //%.2f
			    {                 
 			      gotoxy(8,6+x);
			      printf("%s",dvd[x].num);
			      gotoxy(30,6+x);
			      printf("%s",dvd[x].title);
			      gotoxy(49,6+x);
			      printf("%.2f",dvd[x].price);
     	 		  x++;
                }
			}

		if(fclose(fp)==EOF)
		   {
		     printf("Could not close file!!!");
		     exit(201);
		   }
	     printf("\n\n\n");printf("-----------------------------------!End of List!--------------------------------");
         getch();       
       }
       
     
  }
  



main()
{
   int opt;
   
   do{
      ClearScreen();    
      mainUI();
      scanf("%d",&opt);
      getchar();
     // if(opt==1)
         
      if(opt==2)
        addProds();
      else if(opt==3)
        viewProds();
      else if(opt==5)
           {
            ClearScreen();
            gotoxy(26,12); printf("Thank You Very Much! GOODBYE!");       
            getchar();
            
            exit(0);   
           }
      else
      {
         ClearScreen(); 
         gotoxy(33,12); printf("Invalid input");
      }
      }while(opt>=1 && opt<=5);
      
      
      getch();
      return 0;
      
}


NOTE: The program is not yet finished. Just ignore option 1 and 4. Haven't made their functions yet.

Thanks to all who replied. :)
Wait... are you programming in C (and not C++)? Even so, you need to show your professor the manpage for gets():

http://linux.die.net/man/3/gets wrote:
Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.

Just as dangerous is scanf("%s", ....

Tell your professor you are aware of the proven security dangers of these functions and that she should not be teaching their use. (But do as she says while in her class, I suppose. I'm just dismayed at how common teachers teach these kinds of bad, dangerous habits.)

Either use fgets(), which is safe, or use a width specifier with scanf():

1
2
3
4
  fgets( dvd[x].title, 50, stdin );
  char*p = strstr( dvd[x].title, '\n' );
  if (p) *p = '\0';
  else /* remove trailing whitespace here */
1
2
  scanf( " %49[^\n]", dvd[x].title );
  /* remove trailing whitespace here*/

To remove trailing whitespace, you can use scanf() or getc():

 
  scanf( "%*[^\n]%*1[\n]" );
 
  while (getchar() != '\n');

Reading input is not simple, and C doesn't help much. You really need to pay attention. Alas.


If you are using C, you need to get rid of line 6 (using namespace std;) and line 91 must explicitly use the struct keyword. Also, make sure you are compiling as C and not with a C++ compiler.

1
2
struct dvd dvd[30];
struct dvd cust;

Personally, I don't like mixing type and variable names -- they should be sufficiently distinct to tell them apart. C solves this by requiring the struct keyword, but even so, I would have named it something like "struct dvd_t". That's just me, though.


For your file I/O, I suggest you put each field of your struct on a separate line. Then the file would be just a sequence of some number of lines.
1
How the West Was Won
12.99
2
The Good the Bad and the Ugly
14.99
3
The Little Princess
10.99
Here, each three lines is a movie: number, title, and price. You can make it the way you like. Then getting input from the user and from the file would be very similar.

Hope this helps.
Topic archived. No new replies allowed.