String length Error - c

I am reading the string from the stdin using fgets function and then trying to print the length of the string, But I am always getting the length of the string as 1 always for the first time
Here is my code
#incldue<stdio.h>
#include<string.h>
int main(void)
{
printf("\n Enter the no of test cases");
scanf("%d",&t);
int i,j;
for(i=0;i<t;++i)
{
char song[500],val[28];
int k=0,x=0;
fgets(song,500,stdin);
int len=strlen(song);
printf("\nlen=%d",len);
}
return 0;
}
I am always getting 1 as the length for the first test case :/
Please suggest where i am going wrong

You are not clearing the input buffer. After giving the input value to first scanf newline will be there. So fgets will not get the input from the user.
Newline will be placed in that buffer in a first(song[0]) position. So this is the reason strlen returns as value 1.
Make this line before the fgets.
int c;
if ( i == 0 )
while((c=getchar()) != '\n' && c != EOF );
fgets(song,500,stdin);
Or else place this line after getting the input from the scanf.
scanf("%d",&t);
while((c=getchar()) != '\n' && c != EOF );

Include \n in scanf input string (and in C declare variables at the beginning of the block { }).
Also notice the len will include the \n char.
#include<stdio.h>
#include<string.h>
int main(void)
{
int t, i;
printf("Enter the no of test cases: ");
scanf("%d\n",&t);
for(i=0;i<t;++i) {
char song[500];
int len;
fgets(song,500,stdin);
len=strlen(song);
printf("len=%d\n",len);
}
return 0;
}
update
If you need to handle weird input just use fgets (\n removed from len).
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(void)
{
char song[500];
int t, i, len;
printf("Enter the no of test cases: ");
fgets(song,500,stdin);
t = atoi(song);
for(i=0;i<t;++i) {
fgets(song,500,stdin);
if ((len=strlen(song)) > 0) {
song[--len] = '\0';
printf("len=%d\n",len);
}
}
return 0;
}

When using scanf (or its relatives), it is important to check the return of the function. scanf returns the number of input values correctly matched and assigned. If there are inappropriate characters or insufficient characters, scanf will experience a matching or input failure. A quick if statement will suffice:
if (!scanf ("%d", &t)) {
fprintf (stderr, "error: invalid type or number for test cases.\n");
return 1;
}
As also noted, fgets will read and include in song the trailing newline character. Generally, you will want to remove the trailing newline to prevent having stray newlines scattered through various strings within your code. (not to mention looking at a length=5 for data is a bit strange) A simple method for removing the newline after your call to fgets is:
len = strlen (song);
while (len && song[len-1] == '\n') /* strip newline */
song[--len] = 0;
Putting together the test of scanf return, emptying the input buffer, and stripping the newline after fgets, your code would look similar to:
#include <stdio.h>
#include <string.h>
int main (void)
{
int c = 0;
int i = 0;
int t = 0;
printf ("\n Enter the no of test cases: ");
if (!scanf ("%d", &t)) {
fprintf (stderr, "error: invalid type or number for test cases.\n");
return 1;
}
while ((c = getchar()) != '\n' && c != EOF);
for (i = 0; i < t; ++i) {
char song[500] = { 0 };
size_t len = 0;
if (printf ("\n case [%d] : ", i) && fgets (song, 500, stdin))
{
len = strlen (song);
while (len && song[len-1] == '\n') /* strip newline */
song[--len] = 0;
}
printf (" len : %zu\n", len);
}
printf ("\n");
return 0;
}
Output
$ ./bin/scanf_rd_int
Enter the no of test cases: 2
case [0] : this is case one - 28 chars.
len : 28
case [1] : this is case two -- 29 chars.
len : 29

Related

How to prevent non-numeric input in C & ask user input again

Actually, I can easily found a similar question in Google, but it still can not solve my question.
How to prevent non-numeric input in C?
The upper-link is like a similar case.
Here is my code
#include <stdio.h>
int main()
{
int n;
printf("Enter 1 or 2?\n");
scanf("%d", &n);
while(n != 1 && n != 2)
{
printf("Please do not enter other characters\n");
printf("Enter 1 or 2?\n");
scanf("%d", &n);
}
}
I hope if users enter other numbers(e.g. 1, 45, 656), characters (e.g. a, f, u, e), or string(e.g. apple), the upper program can print out an error message and ask for user input again.
Yes! if users enter other numbers, the program can do what I want.
But! if users enter other characters, string, the program will keep looping.
What should I need to add to this program?
How to prevent non-numeric input in C & ask user input again
Do not use scanf()**. Use fgets().
scanf("%d", ...) does not consume non-numeric input. Instead that offending input remains in stdio for the next scanf().
Code cannot prevent non-numeric input unless it locks the keys from being pressed. Instead, read all input, identify the non-numeric text, toss it and present the user with feedback for new input.
Make a helper function to control impact on rest of code.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
// return -1 on EOF
int read_int_in_range(const char *prompt, const char *reprompt, int lo, int hi) {
if (prompt) {
fputs(prompt, stdout);
fflush(stdout);
}
char buf[100];
while (fgets(buf, sizeof buf, stdin)) {
char *endptr;
errno = 0;
long val = strtol(buf, &endptr, 10);
// no overflow, conversion occurred, in range
if (errno == 0 && endptr > buf && val >= lo && val <= hi) {
// Tolerate trailing white-space.
while (isspace((unsigned char ) *endptr)) {
endptr++;
}
// No junk after the numeric text
if (*endptr == '\0') {
return (int) val;
}
}
if (reprompt) {
fputs(reprompt, stdout);
fflush(stdout);
}
}
return EOF; // or `INT_MIN` or TBD code to distinguish `int` from an error.
}
Usage
const char *prompt = "Enter 1 or 2?\n";
const char *reprompt = "Please do not enter other characters\n" "Enter 1 or 2?\n";
int n = read_int_in_range(prompt, reprompt, 1, 2);
**I recommend to not use scanf() anywhere to read user input until ones understands its weaknesses and limitations.
scanf is meant for formatted input, ie: you know what input will be received, in this case the user may enter something other than an int and your program breaks down. So to deal with that unknown treat the input as a string then analyze the string. In this case you could capture the input in buf and use the function atoi to convert it to an int, like this:
#include <stdio.h>
#include <stdlib.h> /* for atoi */
int main()
{
int n;
char buf[10]; /* this is new */
printf("Enter 1 or 2\n");
/*scanf("%d", &n);*/
fgets(buf, 10, stdin);
n = atoi(buf);
while(n != 1 && n != 2)
{
printf("Please do not enter other characters\n");
printf("Enter 1 or 2?\n");
/*scanf("%d", &n);*/
fgets(buf, 10, stdin);
n = atoi(buf);
}
}
fgets is the way to do this, but wanted to post something like this to actually avoid fgets as asked. It may be of some interest. The appending part should've been delegated to some function and buffer size may've not been 10. Anyways:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define endl "\n"
int main (void)
{
int my_char = 0;
short bad = 0;
char text[10];
memset (text, 0, 10);
printf ("enter number: ");
while ( (my_char = getchar()) )
{
if ( my_char < '0' || my_char > '9' )
{
if ( my_char != '\n' ) bad = 1;
}
else
{
size_t len = strlen (text);
char *strtemp = malloc (len + 2);
strcpy (strtemp, text);
strtemp [len] = my_char;
strtemp [len + 1] = '\0';
strncpy (text, strtemp, 9);
free (strtemp);
}
if ( my_char == '\n' )
{
if ( bad )
{
printf ("enter again (just numbers): ");
fflush (stdout);
bad = 0;
memset (text, 0, 9);
}
else break;
}
}
printf ("entered: %s"endl, text);
}

How do I read the number of characters from a input in C?

I am trying to read the number of characters including, the spaces.
I use the scanf function to check for chars using %c. Also on a side note, how would I go about storing the input into an array?
#include <stdio.h>
int main(void) {
char n, count= 0;
while (scanf("%c", &n) != EOF) {
count = count+1;
}
printf("%d characters in your input \n", count);
return 0;
}
When I test input (with spaces) such as
abcdefg
it doesn't print anything.
Defining a MAX_CHAR and checking that in loop would protect you against invalid memory write.
Remember that last byte of an array should be left for '\0', if you want to print or use the char array.
#include <stdio.h>
#define MAX_CHAR 100
int main(void) {
char n[MAX_CHAR]={0}, count= 0;
while((count!=MAX_CHAR-1)&&(scanf("%c",&n[count])==1))
{
if((n[count]=='\n')){
n[count]=0;
break;
}
count++;
}
printf("%d characters in your input [%s]\n", count, n);
return 0;
}
scanf does return EOF when it reaches the end of the file. But in order for you to see that happening, you should give your program a file input when you call it like this:
./a.out < input.txt
Inside input.txt you could put any text you want. But if you want to work in the command line, you should read until you find a \n
#include <stdio.h>
int main(void) {
char n, count = 0;
scanf("%c", &n);
while (n != '\n') {
count = count+1;
scanf("%c", &n);
}
printf("%d characters in your input \n", count);
return 0;
}
If you want to store the input in an array, you must know the size of the input (or at least the maximum size possible)
#include <stdio.h>
int main(void) {
char n, count = 0;
char input[100]; //the max input size, in this case, is 100
scanf("%c", &n);
while (n != '\n') {
scanf("%c", &n);
input[count] = n; //using count as the index before incrementing
count = count+1;
}
printf("%d characters in your input \n", count);
return 0;
}
Furthermore, if don't know the size or max size of the input, you'd have to dynamically change the size of the input array. But I think that would be a little advanced for you right now.
Your printf doesn't print anything because runtime doesn't reach to it. Your code looping for ever in while loop
while (scanf("%c", &n) != EOF) {
count = count+1;
}
because scanf won't return EOF in this case

Why we need getchar() although using scanf()?

this code should read a positive number and if user enter a non-numeric value, it asking him again to enter a number and wait the input to check again till entering a number
do
{
printf("Enter a positive number: ");
}
while ( (scanf("%d%c", &n,&c) != 2 || c!='\n' || n<0) ) ;
but actually when entering non-numeric it keeps doing the body of the while loop without reading the waiting to check the condition of the while loop while(scanf("%d%c", &n,&c) != 2 || c!='\n' || n<0)
when edit the condition to
int clean_stdin()
{
while (getchar()!='\n');
return 1;
}
do
{
printf("Enter a positive number: ");
}
while ( (scanf("%d%c", &n,&c) != 2 || c!='\n' || n<0) && clean_stdin() ) ;
It executes in the right way, but I don't understand why we need to add getchar() although we already use scanf() in the condition
When scanf("%d%c", ... encounters non-numeric input, the "%d" causes the scanning to stop and the offending character to remain in stdin for the next input function. The "%c" does not get a chance to read that non-numeric character.
If code re-reads stdin with the same scanf("%d%c", ..., the same result. Some other way is needed to remove the non-numeric input. getchar(), getch(), etc. will read any 1 character.
Example code GetPositiveNumber()
Consider using fgets to collect input. Any invalid input is already removed from the input stream making it simpler to try again.
Parse the input with sscanf or others as needed.
char input[40] = "";
int valid = 0;
int n = 0;
do {
printf ( "Enter a positive integer\n");
if ( fgets ( input, sizeof ( input), stdin)) {
int last = 0;
if ( 1 == ( valid = sscanf ( input, "%d%n", &n, &last))) {
if ( n < 0 || input[last] != '\n') {
valid = 0;//reset if negative or last is not newline
}
}
}
else {
fprintf ( stderr, "problem getting input from fgets\n");
return 0;
}
} while ( valid != 1);
Because scanf() with most specifiers ignores white spaces, and you need to collect them before calling scanf() again if a '\n' is left in the buffer. If you don't collect them (and discard them immediately), then scanf() will return immediately on the next call.
See this code
#include <stdio.h>
int
main(int argc, char* argv[]) {
char c = 0;
scanf("%c", &c);
printf("%c\n", c);
scanf("%c", &c);
printf("%c\n", c);
return 0;
}
If you type over two or three characters, second call of scanf doesn't work as interructive. And getch() is not standard. Also you shouldn't call getchar() since it may block. You can use fseek.
Hack using fseek works only on Windows. :-(
BAD SOLUTION
#include <stdio.h>
int
main(int argc, char* argv[]) {
char c = 0;
scanf("%c", &c);
printf("%c\n", c);
fseek(stdin, 0, SEEK_END);
scanf("%c", &c);
printf("%c\n", c);
return 0;
}
GOOD SOLUTION
#include <stdio.h>
int
main(int argc, char* argv[]) {
char buf[BUFSIZ];
char c = 0;
scanf("%c", &c);
printf("%c\n", c);
while (!feof(stdin) && getchar() != '\n');
scanf("%c", &c);
printf("%c\n", c);
return 0;
}
This works good on Windows & Linux

The difference between fgets() and scanf()

This is my code. I didnt want to use scanf() to read the name and I tried using fgets() but after I put the first name and age, the second and third time my program runs the for loop it doesnt take age .
#include <stdio.h>
#include <string.h>
struct student
{
char name[15];
int age;
};
int main()
{
int i;
struct student s[A];
for (i = 0 ; i < A ; i++)
{
printf("enter the names and age\n");
fgets(s[i].name, 10, stdin);
scanf("%d", &s[i].age);
}
printf("\n\n");
for (i = 0 ; i < A ; i++)
{
printf("%s\t%d\n", s[i].name, s[i].age);
}
return 0;
}
It doesnt work, why?
But when I replace fgets with
scanf("%s%d",s[i].name,&s[i].age);
It works fine
The difference between fgets() and scanf()
fgets(...) typically reads until receiving a '\n'
scanf("%d", ...) typically:
1. Reads and discards leading white-space.
2. Reads numeric input (sign,digits) until scanning a non-digit.
3. Non-digit is put back into stdin for the next input function.
Example:
JohnEnter
"John\n" is read by fgets() into s[0].name.
21Enter
21 is read by scanf("%d",...) into s[0].age. '\n' put back into stdin
"\n" is read by fgets() into s[1].name.
M
"M" is read by scanf("%d",...), nothing is put in s[1].age. 'M' put back into stdin.
aryEnter
"Mary\n" is read by fgets() into s[2].name.
19Enter
19 is read by scanf("%d",...) into s[2].age. '\n' put back into stdin
"\n" is read by fgets() into s[3].name.
Alternative: To read 2 lines, call fgets() twice, then parse:
int Scan_student(struct student *dest) {
char buffer[2][80];
dest->name[0] = '\0';
dest->age[0] = -1;
printf("enter the names and age\n");
for (int i=0; i<2; i++) {
if (fgets(buffer[i], sizeof buffer[i], stdin) == NULL) {
return EOF; // stdin was closed, no more input (or input error)
}
buffer[i][strcspn(buffer[i], "\r\n")] = '\0'; // lop off potential trailing \n
}
// parse the 2 buffers: MANY options here - something simple for now.
if (sscanf(buffer[0], " %14[-'A-Za-z ]", dest->name) != 1) {
return 0;
}
if (sscanf(buffer[1], "%d", &dest->age) != 1) {
return 0;
}
return 1;
}
int i;
struct student st[3];
for (i = 0 ; i < sizeof(st) / sizeof(st[0]) ; i++) {
if (Scan_student(&st[i]) != 1) break;
}
If you input both the name and the age in a single line, then that's the normal behavior because fgets() will read the whole line until 9 bytes (in your case) are read or a '\n' is found.
You need one of the two, for instance you could only use fgets() like this
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
char name[100];
int age;
};
int main()
{
int i;
struct student s[1];
for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
{
char number[100];
char *unconverted;
printf("Name > ");
fgets(s[i].name, sizeof(s[i].name), stdin);
if ((unconverted = strchr(s[i].name, '\n')) != NULL)
*unconverted = '\0'; // Remove the trailing '\n'
printf("Age > ");
fgets(number, sizeof(number), stdin);
s[i].age = strtol(number, &unconverted, 10);
if ((*unconverted != '\0') && (*unconverted != '\n'))
s[i].age = -1; // Invalid value indicating input error
}
for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
printf("Name: %s\nAge : %d\n", s[i].name, s[i].age);
return 0;
}
Or scanf() only
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
char name[100];
int age;
};
int main()
{
int i;
struct student s[1];
for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
{
printf("Name Age > ");
if (scanf("%99s%d", s[i].name, &s[i].age) != 2)
{
fprintf(stderr, "input error\n");
s[i].name[0] = '\0';
s[i].age = -1;
}
}
for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
printf("Name: %s\nAge : %d\n", s[i].name, s[i].age);
return 0;
}
and you can then input both name and age in a single line.
The fgets() method is better because you don't need to deal with the '\n' that scanf() doesn't pick up from stdin. A combination would work if you are careful to force the user to input the values in separate lines.
To be honest fgets() isn't required here as you've specified to read from stdin you should simply use gets() this reads from stdin by default. If your moving between a scanf() statement and a gets() statement you should use fflush(stdin) to clear out the input stream, example below:
scanf("%99s", s[i].name);
fflush(stdin);
gets(s[i].age);
In general your better sticking with either scanf() or gets() and not combining them.

Print each word in a separate line from an input string

I'm having trouble printing each word in a separate line from an input string in C. The question from the assignment I'm doing states:
Take a sentence as input and print its words in separate lines.
My Code:
#include<stdio.h>
int main()
{
int i;
char s[100];
scanf("%s", s);
for(i=0; s[i]!='\0'; i++)
{
printf("%c", s[i]);
if(s[i]==' ')
{
printf("\n");
}
}
}
Any help would be appreciated.
In your code,
printf("%s", s[i]);
is wrong. Change it to
printf("%c", s[i]);
as, you're trying to print a char value. The conversion specifier for a char is %c.
Note: Always remember, using wrong conversion specifier will lead to undefined behaviour.
Also, while scan()-ing with %s, you cannot read the whole space-delimited input as a single string. From the man page,
%s
Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null byte ('\0'), which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.
You need to use fgets() to do the job.
That said,
Indent your code properly, make it human-readable.
Chnage scanf("%s", s); to scanf("99%s", s); to avoid possible buffer overflow by putting longer input string than 99 chars.
the proper signature for main() is int main(void).
Rookie, using line-oriented input like fgets or getline is, in general, the proper way to read a line of text. However, when doing simple splitting on a single character, reading a character at a time can be advantageous.
In your case if your task is to read a sentence up to 100 characters and print the words of the sentence out on separate lines, then there is no reason to read the sentence into an array and store the words. You can simply read/print each character until a space is read, then print a newline instead of the space. The reading/printing continues until you reach 100 chars, encounter a newline or EOF:
#include <stdio.h>
#define MAXC 100
int main(void) {
int c = 0;
size_t n = 0;
printf ("\n Enter a sentence.\n\n input: ");
/* read up to 100 characters from stdin, print each word on a line */
while (n < MAXC && (c = getchar ()) != EOF && c != '\n')
{
if (c == ' ')
printf ("\n");
else
printf ("%c", c);
n++;
}
printf ("\n");
if (n == MAXC) /* read and discard remaining chars in stdin */
while ((c = getchar ()) != '\n' && c != EOF);
return 0;
}
Use/Output
$ ./bin/getchar_print_nl_space
Enter a sentence.
input: This is a sentence to split into words.
This
is
a
sentence
to
split
into
words.
Note: if you were going to store all characters, up to 100 (meaning 99 chars and 1 null-terminator), you would need to adjust the length check to n < MAXC - 1 and then null-terminate the array:
char s[MAXC] = {0};
/* read up to 99 characters from stdin into s */
while (n < MAXC - 1 && (c = getchar ()) != EOF && c != '\n')
s[n++] = c;
s[n] = '\0'; /* null-terminate after last character */
if (n == MAXC - 1) /* read and discard remaining chars in stdin */
while ((c = getchar ()) != '\n' && c != EOF);
You would then repeat the logic checking for a space and printing a newline in a for loop:
for (c = 0; c < n; c++)
if (s[c] == ' ')
printf ("\n");
else
printf ("%c", s[c]);
Understanding both manner of input, character-oriented input and line-oriented input will save you time allowing you to match the correct tool to the situation. Here, there is no "more correct" or "less correct" approach, just different ways of doing it.
I think one more way to do this work in a better way is as following.
#include <stdio.h>
#include <string.h>
#define MAX_CHAR 100
int main() {
char s[100],*c;
int i = 0;
scanf("%[^\n]", s);
//Write your logic to print the tokens of the sentence here.
for ( c = s; *c != (int)NULL; c++){
if ( *c == ' '){
*c = '\n';
}
}
printf("%s",s);
return 0;
}
Below code is the answer.
Program also calculates number of space/char and new line.
http://cprograming-char-operation.blogspot.com/2018/07/for-given-statement-print-word-in-each.html
/* Program 1_12 */
/* Count number of line, space and char */
/* Replace a char with specific newline */
/* Add blank space in first input */
#include<stdio.h>
int main()
{
int c,nl,nc,ns,nt;
nl=nc=ns=nt=0;
int d,r, prevd, prevr;
printf("Enter which char to replace :: ");
/* prev is stored before of \n */
while((d = getchar()) != '\n' && (prevd = d));
d = prevd;
printf("Enter word below \n");
while((c=getchar()) != EOF)
{
++nc;
if(c==' ')
++ns;
if(c=='\n')
++nl;
if(c=='\t')
++nt;
/* Replace a char with A */
if(c==d)
putchar('\n');
else
putchar(c);
}
printf("total char=%2d, newline=%2d, space=%2d tabs=%2d\n",nc,nl,ns,nt);
return 0;
}
/* Written by: Prakash Katudia <prakash.katudia#gmail.com> */
gcc ./my_code.c
./a.out
Enter which char to replace :: #space#
Enter word below
hello how are you
hello
how
are
you
#include<stdio.h>
#include<string.h>
int main()
{
char a[1000];
int i,len;
scanf("%[^\n]s",a);
len=strlen(a);
for(i=0;i<len;i++)
{
if(a[i] !=' ')
{
printf("%c", a[i]);
printf("\n");
}
}
}

Resources