Why for loop never ends? - c

int ln;
printf("how many letters are your name?\n");
scanf("%d", &ln);
printf("Ok...enter your name by characters: \n");
char name[ln];
for (int i = 0; i<=ln; i++){
scanf("%s", &name[i]);
}
This code should transform a name in the array but the for-loop never ends. Someone who can help me?

%s is scanning string so technically your whole name is considered as one element. So have to enter many strings . just replace %s by %c and code should be ready to use

"Why for loop never ends?"
First things first, I do not think that the loop is infinite. For me it seems that you are just confusing %s with %c and interpret the waiting for more input as loop that "never ends".
You didn´t provided sufficient ressources to rebuild your issue, though.
But let´s get started:
The %s conversion specifier of scanf() is for reading a string, not a single character. If you want to read a single character per iteration, use scanf("%c", &name[i]); or name[i] = getchar(); instead of scanf("%s", &name[i]); in the for loop.
Your loop condition i <= ln is faulty, as you attempt to write one character more than expected with it, because index counting starts at 0, not 1. Use i < ln instead.
A string needs to have a terminating null character at the end. name needs to have one element more than to just hold the letters of the input name. Also place name[ln] = '\0'; after the loop to insert a null character in the last element of VLA name.
Note:
If you want to read a variable amount of characters from stdin which is determined at run-time, you don´t need to read each character separate and stop until the counter reaches ln - 1.
Reading a string with a variable amount of characters is one point, where fgets() is more appropriate than scanf().
Use fgets (name, sizeof(name), stdin); which ensures that the read string plus the string-terminating null character will fit exactly into name and catch the name once.
int ln;
printf("How many letters are in your name?\n");
scanf("%d", &ln);
getchar(); // catching left newline from scanf.
char name[ln + 1]; // +1 for null character.
printf("Ok...enter your name: \n");
fgets(name, sizeof(name), stdin); // Will read the name and append the null character.
getchar(); // catching left newline from fgets.

in the for condition, try to remove that equality and see, because you are allocating ln bytes in name variable, so the variable i will start from 0 and go to ln-1
for (int i = 0; i<ln; i++){
scanf("%c", &name[i]);
}
also note im using %c here to scan character, %s scans string.

Because your for loop must run one more time to end . simply change
i<=ln
to
i<ln

Why for loop never ends?
Inside the loop, scanf("%s", &name[i]); attempts to read a name ln + 1 times, eventually attempting to save data outside name[] bounds.
Saving data outside name[] bounds is undefined behavior (UB). Anything may happen.
Loop not needed to read one line of input as a name and name[] too small.
//char name[ln];
//for (int i = 0; i<=ln; i++){
// scanf("%s", &name[i]);
//}
char name[ln+1]; // One more for a \0
if (scanf("%s", &name[i]) ==1) {
Success();
}
Recommend to not use scanf() and use fgets().
char name[ln+1+1]; / One more for a \n and 1 for a \0
if (fgets(name, sizeof name, stdin)) {
name[strcspn(name, "\n")] = '\0'; // lop off potential \n
Success();
}

Related

Program seems to be ignoring one instance of 'gets()' and show an error message when the user hasn't interacted with the program [duplicate]

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
int n=1,i,cont;
char string[50];
scanf("%d",&n);
while(n!=0){
gets(string);
cont=0;
for(i=0;i<strlen(string);i++){
if(string[i]=='.'){
cont++;
}
}
if(cont%2==0){
printf("S\n");
}else{
printf("N\n");
}
scanf("%d",&n);
}
return 0;
}
My problem is quite simple but troublesome, I want to read an integer value n, and then read a string, after that read n again, but whenever I run the program, it only reads the string value... but if I digit 0 the program ends... it's like my scanf is within the gets function.
Mixing scanf with gets or fgets is troublesome because they each handle newlines differently.
Get rid of the gets call (which is unsafe anyway) and replace it with the following scanf call:
scanf("%49s", string);
This will read at most 49 characters into string (i.e. one less that its size).
From OP's comments, it sounds like the goal is to be able to read strings containing spaces. While there are ways to accomplish this using scanf(), it would be better to use fgets(), which is at the least less error-prone.
The fgets() function can be used to read input for the number into a buffer, and this buffer can then be processed by sscanf() to extract the number. Since fgets() keeps the newline character, it is not left behind to interfere with the next I/O operation.
But, when fgets() is used to get the string, since the newline is retained, it may be desirable to remove it. This can be accomplished in a number of ways, but here strcspn() is used to provide the index of the first \r or \n character encountered; a \0 character is then written to this location, removing the terminating newline from the string.
The code below illustrates these suggestions. Note that both buffer[] and string[] are generously allocated to accommodate reasonably large inputs. If a user enters a large number of characters (more than 999 in this case), the extra characters are left behind in the input stream for the next I/O function call. Also note that the main loop has been streamlined a bit; now there is a for(;;) loop that never terminates, broken out of when the user enters 0 for the number. And, there is a nested loop within the main loop that prompts the user to enter a number until a valid number is entered. Since the #include <stdlib.h> was unnecessary, it was removed. Better code would check the values returned from the calls to fgets() for possible errors.
#include<stdio.h>
#include<string.h>
int main(void)
{
int n = 1, cont;
char buffer[1000];
char string[1000];
for (;;) {
/* Loop until user enters a number */
do {
printf("Please enter a number: ");
fgets(buffer, sizeof buffer, stdin);
} while (sscanf(buffer, "%d", &n) != 1);
/* Break on 0 */
if (n == 0) break;
/* Get a string, and remove trailing newline */
printf("Please enter a string\n");
fgets(string, sizeof string, stdin);
string[strcspn(string, "\r\n")] = '\0';
cont = 0;
for (size_t i = 0; i < strlen(string); i++) {
if (string[i] == '.') {
cont++;
}
}
if (cont % 2 == 0){
printf("S\n");
} else {
printf("N\n");
}
}
return 0;
}
When you enter 5 for an example, you hit a new line character afterwards.
So you are entering 2 characters: 5 and a new line character.
That new line character is causing your headache.
The new line character is also considered an input.
In order to ignore this new line char, simply add a new line that acts as a garbage collection:
char garbage[50];
scanf( "%d", &n);
fgets(garbage, sizeof(garbage), stdin);

The first char of my array doesnt get printed out

I want to program a Hangman game, but before comparing strings etc. I just wanted to scroll through the array automatically to see if that works - it doesn't, well, not as I imagined.
Everything besides the very first character gets printed out, but why?
int gameWon = 0;
char secretWord[7][1] = {{"H"},{"A"},{"N"},{"G"},{"M"},{"A"},{"N"}};
char guessedChar;
while(gameWon != 1)
{
printf("Guess a single letter: ");
scanf("%s", &guessedChar);
for(int i = 0; i < 7; i++)
{
printf("%c\n", secretWord[i][0]);
}
}
You're using the wrong format specifier to scanf:
scanf("%s", &guessedChar);
The %s format specifier expects a char * which points to the first element of a char array and places a null terminated string at that location. What you passed in was the address of a single char. This caused scanf to write past the memory location of guessedChar, invoking undefined behavior. In this case, it manifested as a nearby variable getting overwritted, specifically the first element of the array secretWord.
Change this to use %c instead, which is for reading single characters. Also, be sure to put a space before it in the format string to absorb any whitespace characters left in the input buffer:
scanf(" %c", &guessedChar);
The type that you specify in scanf is wrong, you pass in an address to a character but the format specifier %s expects a string which will cause undefined behavior. My guess is that it affects the rest of your code.
Also the type of secretword seems a bit odd, why not just an array or string?
char secretWord[] = "HANGMAN";
scanf is not a good choice of reading from the keyboard, instead use fgets() and strip off the ending \n or like in your case, just read the first char. Then you don't need to deal with the fact that scanf leaves characters in the keyboard buffer.
while (... )
{
printf("Guess a single letter: ");
char buffer[128];
if (fgets(buffer,sizeof(buffer),stdin) != NULL)
{
for (int i = 0; i < strlen(secretWord); ++i)
{
if (buffer[0] == secretWord[i])
{
...
}
}

Counting the Whole String Including The Spaces in C

I'm trying to set up a code that counts the whole string and doesn't stop after the first space that it finds. How do I do that?
I tried this kind of code but it just counts the first word then goes to display the number of letters in that first word.
So far this is what I have tried.
int main(){
char get[100];
int i, space=0, len=0, tot;
scanf("%s", get);
for (i=0; get[i]!='\0'; i++)
{
if (get[i] == ' ')
space++;
else
len++;
}
tot = space + len;
printf("%i", tot);
}
And
int main(){
char get[100];
int len;
scanf("%s", &get);
len = strlen(get);
printf("%i", len);
}
But would still get the same answer as the first one.
I expected that if the
input: The fox is gorgeous.
output: 19
But all I get is
input: The fox is gorgeous.
output: 3
strlen already includes spaces, since it counts the length of the string up to the terminating NUL character (zero, '\0').
Your problem is that that the %s conversion of scanf stops reading when it encounters whitespace, so your string never included it in the first place (you can verify this easily by printing out the string). (You could fix it by using different scanf conversions, but in general it's easier to get things right by reading with fgets – it also forces you to specify the buffer size, fixing the potential buffer overflow in your current code.)
The Answer by Arkku is correct in its diagnose.
However, if you wish to use scanf, you could do this:
scanf("%99[^\n]", get);
The 99 tells scanf not to read more than 99 characters, so your get buffer won't overflow. The [^\n] tells scanf to read any character until it encounters the newline character (when you hit enter).
As Chux pointed out, the code still has 2 issues.
When using scanf, it is always a good idea to check its return value, which is the number of items it could read. Also, indeed the \n remains in the input buffer when using the above syntax. So, you could do this:
if(scanf("%99[^\n]", get) == 0){
get[0] = 0; //Put in a NUL terminator if scanf read nothing
}
getchar(); //Remove the newline character from the input buffer
I will take one example to explain the concept.
main()
{
char s[20], i;
scanf("%[^\n]", &s);
while(s[i] != '\0') {
i++;
}
printf("%d", i);
return 0;
}
i have used c language and u can loop through the ending the part of the string and you will get the length. here i have used "EDIT SET CONVESRION METHOD" to read string, you can also gets to read.

scanf not reading properly because of gets function

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
int n=1,i,cont;
char string[50];
scanf("%d",&n);
while(n!=0){
gets(string);
cont=0;
for(i=0;i<strlen(string);i++){
if(string[i]=='.'){
cont++;
}
}
if(cont%2==0){
printf("S\n");
}else{
printf("N\n");
}
scanf("%d",&n);
}
return 0;
}
My problem is quite simple but troublesome, I want to read an integer value n, and then read a string, after that read n again, but whenever I run the program, it only reads the string value... but if I digit 0 the program ends... it's like my scanf is within the gets function.
Mixing scanf with gets or fgets is troublesome because they each handle newlines differently.
Get rid of the gets call (which is unsafe anyway) and replace it with the following scanf call:
scanf("%49s", string);
This will read at most 49 characters into string (i.e. one less that its size).
From OP's comments, it sounds like the goal is to be able to read strings containing spaces. While there are ways to accomplish this using scanf(), it would be better to use fgets(), which is at the least less error-prone.
The fgets() function can be used to read input for the number into a buffer, and this buffer can then be processed by sscanf() to extract the number. Since fgets() keeps the newline character, it is not left behind to interfere with the next I/O operation.
But, when fgets() is used to get the string, since the newline is retained, it may be desirable to remove it. This can be accomplished in a number of ways, but here strcspn() is used to provide the index of the first \r or \n character encountered; a \0 character is then written to this location, removing the terminating newline from the string.
The code below illustrates these suggestions. Note that both buffer[] and string[] are generously allocated to accommodate reasonably large inputs. If a user enters a large number of characters (more than 999 in this case), the extra characters are left behind in the input stream for the next I/O function call. Also note that the main loop has been streamlined a bit; now there is a for(;;) loop that never terminates, broken out of when the user enters 0 for the number. And, there is a nested loop within the main loop that prompts the user to enter a number until a valid number is entered. Since the #include <stdlib.h> was unnecessary, it was removed. Better code would check the values returned from the calls to fgets() for possible errors.
#include<stdio.h>
#include<string.h>
int main(void)
{
int n = 1, cont;
char buffer[1000];
char string[1000];
for (;;) {
/* Loop until user enters a number */
do {
printf("Please enter a number: ");
fgets(buffer, sizeof buffer, stdin);
} while (sscanf(buffer, "%d", &n) != 1);
/* Break on 0 */
if (n == 0) break;
/* Get a string, and remove trailing newline */
printf("Please enter a string\n");
fgets(string, sizeof string, stdin);
string[strcspn(string, "\r\n")] = '\0';
cont = 0;
for (size_t i = 0; i < strlen(string); i++) {
if (string[i] == '.') {
cont++;
}
}
if (cont % 2 == 0){
printf("S\n");
} else {
printf("N\n");
}
}
return 0;
}
When you enter 5 for an example, you hit a new line character afterwards.
So you are entering 2 characters: 5 and a new line character.
That new line character is causing your headache.
The new line character is also considered an input.
In order to ignore this new line char, simply add a new line that acts as a garbage collection:
char garbage[50];
scanf( "%d", &n);
fgets(garbage, sizeof(garbage), stdin);

storing and printing out elements of structs in C

I have created a simple struct:
struct album {
char title[20];
char artist[20];
};
and later in the program I created an instance a (struct album a;). I only need to ask the user to enter the title and the artist so that I save them in the appropriate place and then print the values:
printf("Please enter your album: \n");
printf("album name: ");
scanf("%.20s", a.title);
fflush(stdin);
printf("artist: ");
scanf("%.20s", a.artist);
printf("======\n");
printf("The album's name is %s and the artist is %s\n", a.title, a.artist);
however when I run this, I get this result:
Part of the input text is lost. What exactly goes wrong here?
scanf reads characters up to white space. So if you are entering Michel Jackson the space in between Michel and Jackson terminates your string so you only get the string Michel.
Try using something like fgets:
fgets(a.artist, 20, stdin);
fgets gets terminates the string on new line rather than white space.
**if you do use fgets make sure to remove the new line character from the end of the string of you do not want a new line character at the end.
With the %s specifier in scanf, the length specifier is the number of characters to write. This differs from most functions which expect the size of the entire buffer.
Since your buffer needs to contain the null terminator, you need to be using "%.19s" here. Another option is to not hardcode the value:
scanf("%.*s", (int)sizeof a.title - 1, a.title);
Note that this only works if a.title is an array (not a pointer), and the cast is necessary because int may be a smaller type than size_t but the * expects int.
As noted by others, %s is for reading up until the next whitespace. You can read up until the next line with %[ , for example:
scanf("%.19[^\n]", a.title);
The ^ means to keep reading until any of the following characters are hit, and \n actually means the newline specifically, not general whitespace.
You will want to flush the buffer after doing this, because the newline will still be in the buffer. However fflush(stdin); is not portable. The portable way to discard the rest of the current line is:
int ch; while( (ch = getchar()) != EOF && ch != '\n' ) { }

Resources