While Loop will not Execute in C - c

When I run this program, everything is executed except for the block of while loops at the end. I am asked for the "number of symbols to print per line" and then the program ends. Any help would be greatly appreciated.
#include <stdio.h>
int main(void) {
int num_lines;
printf("Enter a number of lines, greater than or equal to 7, to print : ");
scanf("%d", &num_lines);
if (num_lines < 7) {
while ( num_lines < 7 ) {
printf("Enter the number of lines to print\nMust be greater than or equal to 7 : ");
scanf("%d", &num_lines);
}
}
char symbol;
printf("Choose a symbol/character to be displayed */&/+/0/x : ");
scanf("%s", &symbol);
int num_symbols;
printf("Enter the number of symbols to print per line : ");
scanf("%d", &num_symbols);
if (num_symbols < 7 || num_symbols > 27) {
num_symbols = 19;
}
while (num_lines > 0) {
while (num_symbols > 0) {
printf("%s", symbol);
--num_symbols;
}
printf("\n");
--num_lines;
}
return;
}

In this code snippet
char symbol;
printf("Choose a symbol/character to be displayed */&/+/0/x : ");
scanf("%s", &symbol);
there is used invalid format specifier %s. Instead use format specifier " %c"
char symbol;
printf("Choose a symbol/character to be displayed */&/+/0/x : ");
scanf(" %c", &symbol);
Also in this call of printf
printf("%s", symbol);
you have to use the format specifier %c
printf("%c", symbol);
To provide that these loops would work correctly
while (num_lines > 0) {
while (num_symbols > 0) {
printf("%s", symbol);
--num_symbols;
}
printf("\n");
--num_lines;
}
you need to use an intermediate variable to store the value of num_symbols between iterations of the outer loop. For example
while (num_lines > 0) {
int n = num_symbols;
while (n > 0) {
printf("%c", symbol);
--n;
}
printf("\n");
--num_lines;
}

Your code has a very severe bug,
char symbol;
scanf("%s", &symbol);
is undefined behavior, because "%s" expects a pointer to a char array of at least size 2. In your case, you are passing a pointer to a single char, the effects of such code is undefined.
Instead, it could be (at least)
char symbol[2];
scanf("%1s", symbol);
Or, see #BLUEPIXY's suggestion.
After invoking undefined behavior, the program's memory could become corrupted so the rest of the program could fail for multiple reasons.
You also, never check that scanf("%d", ...) was succesful potentially another cause for undefined behavior.
ALWAYS check that scanf() returns the right value.

Let's boil the problem down to it's core: you're overwriting num_lines on the call stack because you're asking to read a string when you really want a character. When scanf creates the string, it will be null terminated ... and so add a null character after the single char on the stack. One of the joys of working with pointers in C.
(This isn't a stack overflow but rather just a stack overwrite.)
Here is a minimal example of failure. Just change the %s to %c and everything will work:
#include <stdio.h>
int main(void) {
int num_lines;
sscanf("7", "%d", &num_lines);
printf("at first, num_lines is %d\n", num_lines);
char symbol;
sscanf("x", "%s", &symbol);
printf("but now, num_lines has become %d\n", num_lines);
printf("value changed because the second sscanf overwrote\n");
printf(" num_lines on the call stack!!!\n");
return;
}
You'll notice that I'm lazy; use sscanf during testing to have less annoying typing to perform.
Run it and you get:
$ gcc scan.c ; ./a.out
at first, num_lines is 7
but now, num_lines has become 0
value changed because the second sscanf overwrote
num_lines on the call stack!!!

Your problem is with char variable symbol. You are declaring symbol as character variable and reading it as string. There is one more issue. While you are using scanf to read string or character and number at the same time always read the string or char value before reading a numeric value. The reason is scanf also read one more character \n for which it always creates problem.
now change your code like below:-
#include <stdio.h>
int main(void) {
int num_lines;
char symbol;
printf("Choose a symbol/character to be displayed */&/+/0/x : ");
scanf("%c", &symbol);
printf("Enter a number of lines, greater than or equal to 7, to print : ");
scanf("%d", &num_lines);
if (num_lines < 7) {
while ( num_lines < 7 ) {
printf("Enter the number of lines to print\nMust be greater than or equal to 7 : ");
scanf("%d", &num_lines);
}
}
int num_symbols;
printf("Enter the number of symbols to print per line : ");
scanf("%d", &num_symbols);
if (num_symbols < 7 || num_symbols > 27) {
num_symbols = 19;
}
while (num_lines > 0) {
while (num_symbols > 0) {
printf("%s", symbol);
--num_symbols;
}
printf("\n");
--num_lines;
}
return 0;//you have to return a value
}
if still giving you any problem just hard coded symbol = '*'; and try.

Related

Code to print data of a name, price and its pages by using arrays

#include<stdio.h>
int main(){
char name[3];
float price[3];
int i,page[3];
printf("enter the name price and book\n");
for(i=0;i<3;i++){
scanf("%s",name[i]);
printf("enter character:\n");
}
for(i=0;i<3;i++) {
scanf("%f",&price[i]);
printf("enter floating point number:\n");
}
for(i=0;i<3;i++) {
scanf("%d",&page[i]);
printf("enter digit:\n");
}
printf("\n");
for(i=0;i<3;i++) {
printf("%s\n",name[i]);
}
for(i=0;i<3;i++) {
printf("%f\n",&price[3]);
}
for(i=0;i<3;i++){
printf("%d\n",&page[i]);
}
return 0;
}
When I was trying this code, I thought this was quite simple to do but I realized, there is something which I am missing in the code. The main problem with this code is it is not scanning the values of price and pages. I don't understand where I am mistaken.
So, please correct my code so that it will print the values of name price and pages.
There are a number of issues in your code. First and foremost, the %s specifier (for both the scanf and printf functions) expects a string argument (that is, a nul-terminated array of char for printf or an array sufficiently large to hold the input characters plus that terminator, for scanf); however, you are attempting to read (and print) a single char value in each of the relevant for loops.
To fix this, use the %c format specifier, instead of %s. However, when you use this, the newline character that is generated when you press the Enter key will be left in the input buffer, and that will be read as the actual char input on the next iteration of the first for loop. To clear any such newline (or, indeed other whitespace) from the input before the real input, add a space in the format string before the %c. Also, when using this, you will need to pass the address of each name element: scanf(" %c", &name[i]);.
Further, the printf function takes the actual values of the variables to be output, rather than their addresses – so remove the & from the arguments in your printf calls. (Also, and I assume it's a typo, the price[3] expression should be price[i] – the former attempts to access an out-of-bounds element of the price array.)
Another issue is that, in each of your input loops, you call the scanf function before you display the relevant prompt. In the code below, I have reversed your printf and scanf lines in each of those input loops.
Here's a possible fixed version:
#include<stdio.h>
int main()
{
char name[3];
float price[3];
int i, page[3];
printf("enter the name price and book\n");
for (i = 0; i < 3; i++) {
printf("enter character:\n");
scanf(" %c", &name[i]);
}
for (i = 0; i < 3; i++) {
printf("enter floating point number:\n");
scanf("%f", &price[i]);
}
for (i = 0; i < 3; i++) {
printf("enter digit:\n");
scanf("%d", &page[i]);
}
printf("\n");
for (i = 0; i < 3; i++) {
printf("%c\n", name[i]);
}
for (i = 0; i < 3; i++) {
printf("%f\n", price[i]);
}
for (i = 0; i < 3; i++) {
printf("%d\n", page[i]);
}
return 0;
}

Variable Use Fgets with a char array in C

I'm trying to read in a grade (1-10) into an array called moduleGrades.
The fgets(moduleGrades[i]-1, sizeof(moduleGrades), stdin); causes an error, yet what i've typed is exactly what I need. I want to store 3 grades (if the number of modules entered was 3)
many thanks.
#include<stdio.h>
#include <string.h>
char name[30];
int moduleNumber;
char moduleGrades[2];
int main(int argc, char **argv)
{ //read name & module amount
printf ("Please enter your name: ");
fgets(name, sizeof(name), stdin);
printf ("How many Modules: ");
scanf("%d", &moduleNumber);
int i;
for (i = 1; i <= moduleNumber; i++)
{
printf ("Please enter module %d grade ", i);
fgets(moduleGrades[i]-1, sizeof(moduleGrades), stdin);
}
printf("%d", moduleGrades[0]);
printf("%d", moduleGrades[1]);
printf("%d", moduleGrades[2]);
return 0;
}
If you want to print three chars, as indicated by your output, then your array must also be able to hold three chars:
char moduleGrades[2];
Also this loop here:
int i;
for (i = 1; i <= moduleNumber; i++)
This isn't wrong in itself because you subtract the 1 you're off inside the loop, but I would do this and just put this instead:
for (int i = 0; i < moduleNumber; i++)
The fgets call inside the loop is wrong. You're giving it a char instead of a pointer to char. Instead of using fgets, I would just use scanf again:
scanf(" %c", &moduleGrades[i]);
When you print those char that you read in, you need to use the %c format specifier, too:
printf("%c", moduleGrades[0]);
This way it'll print the char that you read in earlier. For instance, if you pressed A, it will print A. With %d it will probably print 65, but it's undefined behavior, so anything else than that might happen instead and there's no guarantee on what exactly will happen.

Why doesn't my strcmp actually detect the smallest between 2 words?

I'm trying to write a program that finds the "greatest" and "smallest" between a set of words inputted by the user. The program should stop listening for words assign as the user inputs a 4 letters long word and I can suppose that there aren't any words longer than 20 letters.
Here's how it should work:
Enter word: dog
Enter word: zebra
Enter word: rabbit
Enter word: catfish
Enter word: walrus
Enter word: cat
Enter word: fish
Smallest word: cat
Largest word: zebra
I tried debugging the code and I noticed that my function only runs the first "if" twice (until zebra is inputted) and then stops working. I don't really get why, every word there is smaller than zebra so it should always run. Also I don't get why the second "if" doesn't run.
Here's my code:
#include <stdio.h>
#include <string.h>
#define N 20
int read_line(char smallest[], char largest[]);
int main(){
char smallest[N], largest[N];
int check = 0;
while(check != 4){
check = read_line(smallest, largest);
}
printf("Smallest word: %s\n", smallest);
printf("Largest word: %s\n", largest);
return 0;
}
int read_line(char smallest[], char largest[]){
char input[N];
printf("Enter word: ");
scanf("%s", input);
if(strcmp(smallest, input) < 0){
printf("Smallest is: %s was: %s\n", input, smallest);
strcpy(smallest, input);
}
if(strcmp(largest, input) > 0){
printf("Largest is: %s was: %s\n", input, largest);
strcpy(largest, input);
}
return strlen(input);
}
As others have pointed out there might be a problem initialization. Since the array is not initialized you don't know what's there that's why a comment was saying it is generating an undefined behaviour. In my case I run your original code inputting twice and even after zebra it continued. Anyway is always better to initialize.
Just put a scanf outside the loop and initialize both values to the first input:
EDIT
I did not pay attention to strcmp usage because the main problem seemed to be the initalization.
From your code and comment it is clear that you are also messing with strcmp. You should have read the documentation:
int strcmp(const char *s1, const char *s2);
Upon completion, strcmp() shall return an integer greater than, equal
to, or less than 0, if the string pointed to by s1 is greater than,
equal to, or less than the string pointed to by s2, respectively.
So strcmp(smallest, input) ) returns a value < 0 if smallest is less (before in the dictionary pages to be clear) than input. You should change to if(strcmp(smallest, input) > 0) meaning smallest is greater than input or to if(strcmp(input, smallest) < 0)
strcmp(largest, input) returns > 0 if largest is bigger than input. Your condition strcmp(largest, input) > 0 is wrong. You want the opposite: you can invert the comparison: strcmp(largest, input) < 0 or invert the inputs: strcmp(input, largest) > 0.
#include <stdio.h>
#include <string.h>
#define N 21
int read_line(char smallest[], char largest[]);
int main(){
char smallest[N];
char largest[N];
int check = 0;
char firstInput[N];
printf("Enter word: ");
scanf("%s", firstInput);
printf("Smallest and largest initialized to: %s\n", firstInput);
strcpy(smallest, firstInput);
strcpy(largest, firstInput);
while(check != 4){
check = read_line(smallest, largest);
}
printf("Smallest word: %s\n", smallest);
printf("Largest word: %s\n", largest);
return 0;
}
int read_line(char smallest[], char largest[]){
char input[N];
printf("Enter word: ");
scanf("%s", input);
if(strcmp(smallest, input) < 0){
printf("Smallest is: %s was: %s\n", input, smallest);
strcpy(smallest, input);
}
if(strcmp(largest, input) > 0){
printf("Largest is: %s was: %s\n", input, largest);
strcpy(largest, input);
}
return strlen(input);
}
In my opinion this is the clearer initialization (and more correct) since it uses user's input and does not rely on any condition. However the code is less compact than other possible initializations since you are repeating some part of the code.
EDIT alternative initializations
There are other initialization methods. One is to initialize for example to the lowest letter:
char smallest[N];
for (int i=0; i<N-1; i++)
{
smallest[i] = 'z' ;
}
smallest[N-1] = '\0';
char biggest[N];
for (int i=0; i<N-1; i++)
{
biggest[i] = 'a' ;
}
biggest[N-1] = '\0';
In your original code this will print something like zzzzz.... and aaaa....
Another alternative is to initialize them to the numerical min and max values of the range of char types (typically -128 and 127):
#include<math.h>
...
char smallest[N] ;
char biggest[N] ;
for (int i=0; i<N-1; i++)
{
smallest[i] = (char) (pow(2,sizeof(char)*8)/2 - 1);
}
smallest[N-1] = '\0';
for (int i=0; i<N-1; i++)
{
biggest[i] = (char) -1*(pow(2,sizeof(char)*8)/2);
}
biggest[N-1] = '\0';
However in case in your first print will print thrash (better not to print at all ).
EDIT FOR scanf alternatives
When a user is inputting anything, especially a string, it is a good behaviour to test if that input conforms to what you are expecting. In C this becomes even more important since inputting a string longer than the length (actually length-1) of the array in which the string will be stored will cause Segmentation fault error and the program crashes.
There is a simple way to avoid this: instead of scanf("%s", firstInput); do, in your specific case, scanf("%20s", firstInput); i.e. the length of your input array minus 1 (N-1). The problem with this approach is that you cannot use a dynamic value: for example:
#define M 20
scanf("%Ms", firstInput);
does not work.
According to this post you could:
#define MAX_STRING_LENGTH 20
#define STRINGIFY(x) STRINGIFY2(x)
#define STRINGIFY2(x) #x
{
...
char word[MAX_STRING_LENGTH+1];
scanf(file, "%" STRINGIFY(MAX_STRING_LENGTH) "s", word);
...
}
or follow the approach of this post:
int scanner(const char *data, char *buffer, size_t buflen)
{
char format[32];
if (buflen == 0)
return 0;
snprintf(format, sizeof(format), "%%%ds", (int)(buflen-1));
return sscanf(data, format, buffer);
}
NOTE
If you mix words with and without capital letters, the ordering might not work anymore: Zookeeper (fantastic animal) comes before antilope.
Ok, there are multiple flaws in your program:
First of all, as other answers pointed out, you should #define N as 21, not 20, so as to leave room for the null character.
Secondly, you should initialize your strings.
And, most importantly, you have messed the order of your strcmp arguments. You should either pass first input and then the string you want to compare to, or change the inequality signs.
Finally, you should initialize largest as "" so that the first character equals zero and so the string is smaller than all possible strings. And you should initialize smallest to the largest possible string (e.g. "\xFF", although that will not work if the input string starts with the non-ASCII character '\xFF'). Then, when you enter the first string, it will be copied over both buffers. However, you'd better set a variable to check for the first input string given, and add a condition to copy it to both largest and smallest. This is slightly more complex, but works with all strings.
Here is your updated code:
#include <stdio.h>
#include <string.h>
#define N 21
int read_line(char smallest[], char largest[]);
int not_first = 0;
int main(){
char smallest[N], largest[N];
int check = 0;
while(check != 4){
check = read_line(smallest, largest);
}
printf("Smallest word: %s\n", smallest);
printf("Largest word: %s\n", largest);
return 0;
}
int read_line(char smallest[], char largest[]){
char input[N];
printf("Enter word: ");
scanf("%s", input);
if(strcmp(input, smallest) < 0 || !not_first){
printf("Smallest is: %s was: %s\n", input, (not_first)? smallest : "(none)");
strcpy(smallest, input);
}
if(strcmp(input, largest) > 0 || !not_first){
printf("Largest is: %s was: %s\n", input, (not_first)? largest : "(none)");
strcpy(largest, input);
}
not_first = 1;
return strlen(input);
}

Getting undesired result by using while loop to find the sum of n natural numbers

I am attaching the code for the same.Its working fine.But once i enter a number less than the previous one it stops giving desired output.Any help/suggestion shall be greatly appreciated.
int i=1;
int j=0;
int n;
char ch;
while(ch!='n')
{
printf("Enter the number upto which you want the sum of \n \n");
scanf("%d",&n);
while(i<=n)
{
j=j+i;
i++;
}
printf("%d \n",j);
printf("Do it with another number? Y/N \n \n");
scanf("%s",&ch);
}
return 0;
In your outer while loop, you're never resetting the value of the variable i back to 1, or j back to 0. That is why subsequent loops will produce an incorrect sum.
There are a smattering of bugs in this code, including:
Comparison to uninitialized value of of ch in the initial while expression.
Failing to reset i and j for each outer-loop iteration
Failing to test for data-read success in either scanf call to ensure proper input.
The continuation scanf("%s", &ch) is simply wrong for a single character with skipped whitespace (which you must do to avoid reading the newline after your list integer input). Unless EOF or an error state is reached, what you have now is guaranteed to invoke undefined behavior, as a string-read of at least one character requires at least two for storage (the character, and a subsequent terminator).
Addressing all of those:
#include <stdio.h>
int main()
{
char ch;
do
{
int n;
printf("Enter the number upto which you want the sum of \n \n");
if (scanf("%d", &n) != 1) // See (3)
break;
int j = 0; // See (2)
for (int i = 1; i <= n; ++i) // See (2)
j += i;
printf("%d \n", j);
printf("Do it with another number? Y/N \n \n");
if (scanf(" %c", &ch) != 1) // See (3) and (4)
break;
} while (ch != 'n' && ch != 'N'); // See (1)
return 0;
}
Everything here is self-explanatory when referred to the previous bug punch list, save for maybe the format string for reading the single character. You mentioned in comments that you tried %c but it skipped to another loop iteration. That's because you didn't have the leading whitespace " %c" that tells scanf to skip white space before extracting the next argument. With that, it should work as desired.
You need to reset i and j for every n.
i = 1;j=0;
while(i<=n)
{
Also your format specifer is wrong. For char, it should be %c and not %s
scanf("%c",&ch);
The simplest solution is to set i to 0 at the outer while:
int i=1;
int j=0;
int n;
char ch;
while(ch!='n')
{
i = 0;
printf("Enter the number upto which you want the sum of \n \n");
scanf("%d",&n);
while(i<n)
{
j=j+i;
i++;
}
printf("%d \n",j);
printf("Do it with another number? Y/N \n \n");
scanf("%s",&ch);
}
return 0;
Note that I have changed <= to < for your inner while, since you do not want to increment the value if the same n is inputted one after the other.
#include<stdio.h>
int main(){
int n;
char ch;
while(ch!='n')
{
printf("Enter the number upto which you want the sum of \n \n");
scanf("%d",&n);
int i=1;//it should be 1 in every loop of the number
int j=0;//the sum should also be initialized to zero to erase the previous value
while(i<=n)
{
j=j+i;
i++;
}
printf("%d \n",j);
printf("Do it with another number? Y/N \n \n");
scanf("%c",&ch);//this is a char not a string
}
return 0;
}
Due to the i is not initializing to 1 when the loop is coming for the second time there it is not going inside the loop and printing the previous value .

Getting an Array from user? C programming

My console keeps on crashing after entering a few numbers. I am trying to get an array of 10 numbers from the user thru the console and then taking count of positives, negatives, evens, and odds. What am I doing wrong?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int pos, neg, even, odd;
int nums[10];
printf("Give me 10 numbers: ");
pos = neg = even = odd = 0;
for(int i = 0; i < 10; i++){
scanf(" %d", nums[i]);
if(nums[i] > 0){
pos++;
if(nums[i] % 2 == 0){
even++;
}
else{
odd++;
}
}
else{
neg++;
}
}
printf("Positives: %d, Negatives: %d, Evens: %d, Odds: %d\n", pos, neg, even, odd);
return 0;
}
In your code,
scanf(" %d", nums[i]);
should be
scanf(" %d", &(nums[i]));
or,
scanf(" %d", nums+i);
as you need to pass the pointer to variable as the format specifier's argument in scanf() .
To elaborate, %d expects a pointer to int and what you're supplying is an int variable. it invokes undefined behavior.
That said,
Always check the return value of scanf() to ensure proper scanning.
int main() should be int main(void) to conform to the standard.
Modify scanf like scanf(" %d", &nums[i]);
scanf(" %d", nums[i]);
Scanf expects a pointer to a location to write to, and you're not giving it one.
Change your scanf to:
scanf(" %d", &(nums[i]));
to make your program work.
With this change I tested your program with stdin of
20 10 9 1 39 1 2 2 31 1
And recieved output:
Give me 10 numbers: Positives: 10, Negatives: 0, Evens: 4, Odds: 6
ideone of the thing for your testing purposes.
Change scanf(" %d", nums[i]); to scanf(" %d", &nums[i]);, because scanf() needs addresses. The parentheses around nums[i] isn't necessary, and may effect readability.
Also note that 0 is even, but not negative.
When scanf is usedto convert numbers, it expects a pointer to the corresponding type as argument, in your case int *:
scanf(" %d", &nums[i]);
This should get rid of your crash. scanf has a return value, namely the number of conversions made or the special value EOF to indicate the end of input. Please check it, otherwise you can't be sure that you have read a valid number.
When you look at your code, you'll notice that you don't need an array. Afterreading the number, you don't do aything with the array. You just keep a tally of odd, even and so on numbers. That means you just need a single integer to store the current number. That also extends your program nicely to inputs of any length.
Here's a variant that reads numbers until the end of input is reached (by pressing Ctrl-D or Ctrl-Z) or until a non-number is entered, e.g. "stop":
#include <stdlib.h>
#include <stdio.h>
int main()
{
int count = 0;
int pos = 0;
int neg = 0;
int even = 0;
int odd = 0;
int num;
while (scanf("%d", &num) == 1) {
count++;
if (num > 0) pos++;
if (num < 0) neg++;
if (num % 2 == 0) even++;
if (num % 2 != 0) odd++;
}
printf("%d numbers, of which:\n", count);
printf(" %d positive\n", pos);
printf(" %d negative\n", neg);
printf(" %d even\n", even);
printf(" %d odd\n", odd);
return 0;
}
Change scanf statement after for loop to
scanf(" %d", &nums[i]);

Resources