Issue on a do-while form in Strings - c

Ok, i'm a student in his first experiences with programmaing so be kind ;) this is the correct code to print "n" times a string on screen...
#include <stdio.h>
#include <string.h>
#define MAX 80+1+1 /* 80+\n+\0 */
int main(void)
{
char message[MAX];
int i, n;
/* input phase */
printf("Input message: ");
i = 0;
do {
scanf("%c", &message[i]);
} while (message[i++] != '\n');
message[i] = '\0';
printf("Number of repetitions: ");
scanf("%d", &n);
/* output phase */
for (i=0; i<n; i++) {
printf("%s", message);
}
return 0;
}
why in the do-while form he needs to check if message[i++] != '\n' and not just message[i] != '\n'??

The proper way to write that input loop is, in my opinion, something along the lines of:
fgets(message, sizeof message, stdin);
in other words, don't use a character-by-character loop, just use the standard library's function that reads a string terminated by newline and be done.

The do { ... } while(...) loop in your code reads characters one at a time and stores them in message. The index of the next character is one more that the index of the previous character, that's why we should increase index variable i after the current character is stored. The algorithm is:
Read the next character and store it in message[i].
If this character is '\n', exit.
Increase i and goto 1.
The expression message[i++] increments i after it was used as an index into message, so that next time we will look at the next character in the string. So, while (message[i++] != '\n') combines steps 2 and 3.
The same in for-loop:
int i;
for (i = 0; scanf("%c", &message[i]) && message[i] != '\n'; ++i);
But as #unwind pointed, it's better not to use char-by-char input.

Related

Why doesn't this get characters?

Why does this for only runs 5 times? As in it gets 5 character and then stops. And if I change the i<10 to i<5 it only runs 3 times.
#include <stdio.h>
char a[1000];
int main()
{
char a[100];
for(int i=0;i<10;i++)
{
scanf("%c",&a[i]);
}
}
I think the problem is most likely that you don't think the Enter key will give you a character, but it will result in a newline '\n' character.
If you want to skip the newlines (or really any white-space) then use a leading space in the scanf format string:
scanf(" %c",&a[i]);
// ^
// Note space here
If you want to read other space characters (like "normal" space or tab) then you need to use one of the character-reading functions like fgetc or getchar. For example as
for (size_t i = 0; i < 10; ++i)
{
int c = getchar();
if (c == '\n')
continue; // Skip newline
if (c == EOF)
break; // Error or "end of file"
// Use the character...
}

String Input with multiple lines

int main() {
char userInput[100]; //Store user input
//Take user input
//scanf(" %s",&userInput);
//scanf("%[^\n]s",&userInput);
//scanf("%[^\n]", &userInput);
//gets(userInput);
scanf("%[]s", &userInput); //This takes input but doesnt leave input loop
printf(" %s",userInput);
//i = index to start for looping through the string, starting at the beginning
//count = Stores occurrences of '$'
//inputLength = length of the input, used for limit of loop
int i =0,count =0;
int inputLength = strlen(userInput);
//Loop through the user input, if the character is '$', the integer count will be incremented
for (i; i < inputLength; i++){
if (userInput[i] == '$'){
count++;
}
}
printf("%d", count);
return 0;
}
Hi i'm having some issues with my code, i need to take an input of 3 lines and count the number of'$' in the input. The input method not commented "scanf("%[]s", &userInput);" is the one only i have discovered to take all 3 lines of input, BUT i can't break the input loop and continue with my program.
Any help would be greatly appreciateed
To read 3 lines with the cumbersome scanf(), code needs to look for '$', '\n', and EOF. The rest of input is discardable.
int count = 0;
int line = 0;
while (line < 3) {
scanf("%*[^$\n]"); // Scan for any amount of characters that are not $ nor \n,
// "*" implies - do not save.
char ch;
if (scanf("%c", &ch) != 1) { // Read next character.
break;
}
if (ch == '$') count++;
else line++;
}
printf("$ count %d\n", count);
As #chux suggested, reading with fgets provides a convenient way to protect from buffer overrun and without having to hard code field-width modifiers in scanf conversion specifiers.
Here, if all you need to do is count the number of '$' characters found in your input (regardless of how many lines), you can simply read ALL the input in fixed sized chunks of data. fgets does just that. It doesn't matter if you have one line, or one million lines of input. It also doesn't matter if your input lines are one-character or one million characters long. You can simply read each line and count the number of '$' found within each chunks of data read, keeping a count of the total found.
You can do this for any character. If you wanted to also count the number of line, you can simply check for '\n' characters and keep a total there as well. The only corner-case in counting lines with fgets is to insure you protect against a non-POSIX end-of-file (meaning a file with no '\n' as the final character). There are a couple of ways to handle this. Checking that the last character read was a '\n' is as good as any.
Putting the pieces together, and protecting against a non-POSIX eof, you could do something similar to the following, which simply reads all data available on stdin and outputs a final '$' and line count:
#include <stdio.h>
#define MAXC 100
int main (void) {
char buf[MAXC] = ""; /* buffer to hold input in up to MAXC size chunks */
size_t lines = 0, dollars = 0; /* counters for lines and dollar chars */
int i = 0;
while (fgets (buf, MAXC, stdin)) /* read all data */
for (i = 0; buf[i]; i++) /* check each char in buf */
if (buf[i] == '$') /* if '$' found */
dollars++; /* increment dollars count */
else if (buf[i] == '\n') /* if '\n' found */
lines++; /* increment line count */
if (i && buf[i-1] != '\n') /* protect against non-POSIX eof */
lines++;
/* output results */
printf ("input contained %zu lines and %zu '$' characters.\n",
lines, dollars);
return 0;
}
Look things over and let me know if you have further questions.
scanf("%[]s", &userInput);" is the one only i have discovered to take all 3 lines of input, BUT i can't break the input loop and continue with my program.
"%[]" is an invalid scanf() specifier. Anything may happen, it is undefined behavior, including taking all lines in and not returning.
The 's' in the format serves no purpose here - drop it.
Yes fgets() is best but let us abuse scanf() to read 3 lines and look for '$'.
char line[3][100] = {0};
// v--------- Consume all leading whitespace
// | vv ----- limit input to 99 characters as scan() appends a \0
// | || v-v-- Look for "not \n"
#define FMT_1LINE " %99[^\n]"
// Let the compiler concatenate the 3 formats into 1 string for scanf
int scan_count = scanf(FMT_1LINE FMT_1LINE FMT_1LINE, line[0], line[1], line[2]);
// Check return value
if (scan_count == 3) {
// Successfully read 3 lines
int count = 0;
for (int line_index = 0; line_index < 3; line_index++) {
char *s = line[line_index];
while (*s) { // no need for strlen(), just loop until the null character
count += *s == '$';
s++;
}
}
printf("$ count %d\n", count);
}
You write:
scanf("%[]s", &userInput); //This takes input but doesnt leave input loop
but the comment is at best misleading. Your format string is malformed, so the behavior of the scanf call is undefined. An empty scan set (between the [] in the format) does not make sense, because the resulting field could never match anything. Therefore, a ] appearing immediately after the opening ] of the scan set is interpreted as a literal character not the ending delimiter. Your scan set is therefore unterminated.
Note, too, that %[ is its own field type, separate from %s. An 's' following the closing ] of the scan set is not part of such a field descriptor, but rather an ordinary character to match.
A trivial way to do this with scanf would be to read characters one at a time in a loop via a %c field. This is probably not what the exercise is looking for, and it's a hack to use scanf() instead of getchar() for this purpose, but perhaps it would serve:
int nl_count = 0;
int dollar_count = 0;
do {
char c;
int result = scanf("%c", &c);
if (result != 1) {
break;
}
switch (c) {
case '\n':
nl_count++;
break;
case '$':
dollar_count++;
break;
}
} while (nl_count < 3);
I'm afraid it would be much more complicated to do it safely reading multiple characters at a time with a %[ field, and there is no safe way to read all three lines in one scanf call, unless you can rely on the input lines not to exceed a line length limit known to you.
int readMatrix() {
char userInput[100][3]; //Store user input
int j = 0, m = 0;
for(m = 0; m < 3; m++){
scanf("%s", &userInput[j][m]); //This takes input (Ex: 22 *(enter)* 33$ *(enter)* 66$ *(enter)*
j++; //increase the column
}
int i =0,count =0;
m = 0;
//Loop through the user input, if the character is '$', the integer count will be incremented
for (i = 0; i < 100; i++){
for(m = 0; m < 3; m++){
if (userInput[i][m] == '$'){
count++;
}
}
}
printf("%d", count);
return 0;
}

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");
}
}
}

How to limit input length with scanf

In this program I have taken a dimensional character array of size[3][4],
as long as I enter a 3 characters for each row it will work well.
For example: if I enter abc abd abd I get the same output but if i enter more letters in the first or second or 3rd row I get an error.
How should I check for null character in 2 dimensional?
# include <stdio.h>
#include <conio.h>
# include <ctype.h>
void main()
{
int i=0;
char name[3][4];
printf("\n enter the names \n");
for(i=0;i<3;i++)
{
scanf( "%s",name[i]);
}
printf( "you entered these names\n");
for(i=0;i<3;i++)
{
printf( "%s\n",name[i]);
}
getch();
}
As pointed out by #SouravGhosh, you can limit your scanf with "%3s", but the problem is still there if you don't flush stdin on each iteration.
You can do this:
printf("\n enter the names \n");
for(i = 0; i < 3; i++) {
int c;
scanf("%3s", name[i]);
while ((c = fgetc(stdin)) != '\n' && c != EOF); /* Flush stdin */
}
How should I chk for null character in 2 dimensional ... [something has eaten the rest part, I guess]
You don't need to, at least not in current context.
The problem is in your approach of allocating memory and putting input into it. Your code has
char name[3][4];
if you enter more that three chars, you'll be overwriting the boundary of allocated memory [considering the space of \0]. You've to limit your scanf() using
scanf("%3s",name[i]);
Note:
change void main() to int main(). add a return 0 at the end.
always check the return value of scanf() to ensure proper input.
EDIT:
As for the logical part, you need to eat up the remainings of the input words to start scanning from the beginning of the next word.
Check the below code [Under Linux, so removed conio.h and getch()]
# include <stdio.h>
# include <ctype.h>
int main()
{
int i=0; char name[3][4];
int c = 0;
printf("\n enter the names \n");
for(i=0;i < 3;i++)
{
scanf( "%3s",name[i]);
while(1) // loop to eat up the rest of unwanted input
{ // upto a ' ' or `\n` or `EOF`, whichever is earlier
c = getchar();
if (c == ' ' || c == '\n' || c == EOF) break;
}
}
printf( "you entered these names\n");
for(i=0;i<3;i++)
{
printf( "%s\n",name[i]);
}
return 0;
}
(Cringing after reading the answers to date.)
First, state the problem clearly. You want to read a line from stdin, and extract three short whitespace separated strings. The stored strings are NUL terminated and at most three characters (excluding the NUL).
#include <stdio.h>
void main(int, char**) {
char name[3][4];
printf("\n enter the names \n");
{
// Read tbe line of input text.
char line[80];
if (0 == fgets(line, sizeof(line), stdin)) {
printf("Nothing read!\n");
return 1;
}
int n_line = strlen(line);
if ('\n' != line[n_line - 1]) {
printf("Input too long!\n");
return 2;
}
// Parse out the three values.
int v = sscanf(line, "%3s %3s %3s", name[0], name[1], name[2]);
if (3 != v) {
printf("Too few values!\n");
return 3;
}
}
// We now have the three values, with errors checked.
printf("you entered these names\n%s\n%s\n%s\n",
name[0], name[1], name[2]
);
return 0;
}
you might consider something on the order of scanf( "%3s%*s",name[i]);
which should, if I recall correctly, take the first three characters (up to a whitespace) into name, and then ignore anything else up to the next white space. This will cover your long entries and it does not care what the white space is.
This is not a perfect answer as it will probably eat the middle entry of A B C if single or double character entries are mode. strtok, will separate a line into useful bits and you can then take substrings of the bits into your name[] fields.
Perhaps figuring out the entire requirement before writing code would be the first step in the process.

C: scanf chars into array

just starting C and want to know how to enter an unknown numbers of char into array,
when the finishing symbol will be '~'
#include <stdio.h>
#define N (499)
int main()
{
int count;
int i;
char input;
char text[N];
printf("Text:\n");
scanf("%c", &input);
while (input != '~')
{
for(i = 0; i < N; i++)
{
text[i] = input;
scanf("%c", &input);
count++;
}
}
return 0;
}
But i keep getting an infinite loop
thanks!
Remove the while loop and replace the for loop with:
for(i = 0; i < N && input != '~'; i++)
Also it is a good idea to finish your string with a terminating null character so the program knows where the string ends.
So after the for loop add:
text[i] = '\0';
Alternatively you can use some scanf regex to avoid loops alltogether.
For example:
scanf("%498[^~]", text);
will read 498 characters in the array text until the ~sign is met. It will also put the terminating character to the string.
(you should not usually use scanf, but it is good enough for a beginner)
Edit: thanks to some random guy, "amis" or smth(please tell your name) a mistake replaced.
You have 2 loops. If the first one is not elapsed (because you get less chars than N), you never return to the first one, when you test input.
More than that, the last char you read will usually be a \n, so you won't get a ~in the first loop level
If you are using count for counting initialize it to zero first.
int count = 0;
You are using for loop inside a while loop, for every character input the for loop will run N times. so check input != '~' in for loop itself, Remove while loop.
Instead of your looping method, Try this-
for(i = 0; i < N && input != '~'; i++)
{
text[i] = input;
scanf(" %c", &input); // Note the space before ' %c'
count++;
}
text[i]='\0'; // To make the last byte as null.
You need give a space before %c if you use it in loops, else you can read only N/2 input from the user!
It is due to \n after the input character. After your input when you hit enter \n is read as a next input, to avoid this give a space before %c!
Output( No space before %c )-
root#sathish1:~/My Docs/Programs# ./a.out
Text:
q
w
e
r
t
y
~
Count = 12
Output( With a space before %c )-
root#sathish1:~/My Docs/Programs# ./a.out
Text:
q
w
e
r
t
y
~
Count = 6
Note the count difference!

Resources