C - Can't stop program using while and logical operator - c

I'm just starting learning C but I really don't know what am I doing wrong. I wrote this code, and it was supposed to stop reading numbers when it receives a negative number. I have wasted a lot of time trying to figure out what it is wrong, and I still don't know what it is.
#include<stdio.h>
int main(){
const int qtd = 3;
float ent[qtd];
int i = qtd;
printf("Digite os numeros\n");
do{
scanf("%f", &ent[i]);
i--;
}while (ent[i] >= 0 && i >= 1);
printf("\n\n\n\nPressione 'Enter' para sair");
fflush(stdin);
getchar();
return 0;
}

The problem is with the index of ent that you check for being negative. It's ent[i], but it is after i has been decremented, so you are reading the location that has not been written yet by scanf.
To fix the problem, change the code to use the prior location, i.e.
do {
...
} while (ent[i+1] >= 0 && ...);
There are several other problems with your code, all coming from the assumption that array indexes start at 1. In C, however, the initial index is zero, not one, so the correct check should be
do {
...
} while (ent[i+1] >= 0 && i >= 0);
In addition, i should be initialized to int i = qtd-1; to avoid writing past the end of allocated array.

Related

New input isn't asked, Inside a while loop in C

I have been trying to solve the problem set 1 in CS50, language C. I've come to this point, but I got stuck in here. I want my code to ask for a new input while(n>=9 || n<=0) but it ends there, instead of asking for a new input. I have already tried return n; but it didn't work at all. You can see the console and the results.
When I asked my code to return 0; I thought it would be asking for a new input. But as it can be seen, it ended up. What I want is it to ask for a new input, instead of stop working.
This is my first time and post in here, so I hope I have described my problem good enough.
#include <stdio.h>
#include <cs50.h>
int main(void)
{
int n = get_int("Number: ");
while(n>=9 || n<=0)
{
return 0;
}
int i;
for(i=0;i<n;i++)
{
int a;
for(a=n-1;a>i;a--)
{
printf(" ");
}
int y;
for(y=0;y<=i;y++)
{
printf("#");
}
printf("\n");
}
}
As others suggested, return 0 is an action that terminates the current function you are in, and returns said value. I don't know what is your level of knowledge of C, I'll try to put less informations possible here. Just know that if you write return inside your main(){} block, the program will ignore all the following code and end the program if that return is executed.
Now as to how to get your desired result
I want my code to ask for a new input while(n>=9 || n<=0)
it seems you just need to put your statement inside the while loop:
int n=0;
while (n>=9 || n<=0)
{
n = get_int("Number: ");
}
in this case you need to declare int n outside the loop since you will use it later. (I initialized it as 0 to let the program enter the loop).
If you have studied and are able to use "do while" loops, it may be your best choice here. If your program needs to ask for input, and keep asking until input is no longer in the range (n >= 9 || n <= 0) you might want to try
int n=0;
do
{
n = get_int("Number: ");
} while (n>=9 || n<=0)
This will execute the block of code once for sure, then checks if the while condition is met and loops again. The outcome is you get the statement executed once and then until the condition is no longer met.
Put your code inside while loop to ask it whenever (n >= 9 || n <= 0) because right now whenever n is greater or equal 9 or less or equal 0 your your program will end because return 0 ends actual function and in your case it is main() function

Programming while loop in C

First, I am a total beginner, so the question is probably very obvious for all of you, but i don't get what's wrong with the while loop in this program. Te aim of the program is to calculate the average between numbers where the user inputs 0 when he wants to continue putting numbers in and inputs 1 when he wants to stop, so the loop is supposed to stop when the user puts 1 and to compute a sum of the values when he enters 0 at the end. So this is what i wrote, i used stdio.h and stdlib.h as libraries :
int decision;
int value;
int sum = 0;
float av;
int order = 1;
printf ("for continue press: 0\n ");
printf ("for stopping press: 1\n ");
while (decision == 0) {
printf("input value:");
scanf("%d", &value);
sum = sum + value;
printf ("continue?");
scanf("%d", &decision);
order = order + 1;
}
av = (float) sum / (float) order;
printf("the average is: %.2f", av);
return EXIT_SUCCESS;
what the terminal displays is just "the average is:0.00", it skips the whole operation above.
You should initialize decision to 0
int decision = 0;
so that the while loop is true
while (decision == 0) {
on the first iteration.
In C, simply declaring a variable does not assign it a value of 0. You have to do that. In fact, actually using a variable that has not been initialized is undefined behavior. Most likely, the variable contains whatever contents was in the memory location assigned to it.
The solution is to actually define decision.
int decision = 0;
In C, declaring a variable does not initialize it. So the initial value of decision is more or less random. If it's not zero (and it likely is not), the cycle is never entered.
Perversely, when in "debug mode" or using some instrumentation such as valgrind, memory might be either zeroed or initialized consistently, leading to "unreproducible" bugs that may be difficult to track. That is why you really want to always initialize your variables
Try with:
int decision = 0;
Also, turn on all compiler warning flags. You want to be warned when such things happen, and the compiler can do so if you tell it to.
Another way
You do not need decision anywhere else, so it's good to have one less variable in the outer scope:
for (;;) {
int decision; /* The variable only lives inside this loop */
printf("input value:");
scanf("%d", &value);
sum = sum + value;
printf ("continue?");
scanf("%d", &decision);
if (0 == decision) {
break;
}
order = order + 1;
}
Notice
If you start order from 1, and enter only one value, order will be increased to 2, and this will get your calculation off. Either start from 0 or increase the value after decision confirmation.
You have not initialized the decision variable and that is why the error.
int decision = 0;

C loop won't exit

Good-morning one and all!
This is going to end up being one of those blindingly-easy questions in hindsight, but for the life of me I'm stumped. I'm going through some of the exercises in The C Programming Language, and I've managed to write some code to initialize a loop. After some Googling, I found better ways of initializing a loop to 0, but I don't understand why the loop that I wrote to do it doesn't finish. I've used the debugger to find out that it's because the 'c' variable never reaches 50, it gets to 49 and then rolls over to 0, but I can't figure out why it's rolling over. The code is attached below, does anyone know what's going on here?
#include <stdio.h>
#define IN 1
#define OUT 0
/* Write a program to print a histogram of the lengths of words in
itsinput. */
main()
{
int c=0;
int histogram[50]={0}
int current_length=0;
int state=OUT;
//Here we borrow C so we don't have to use i
printf("Initializing...\n");
while(c<51){
histogram[c] =0;
c=c+1;
}
c=0;
printf("Done\n");
while( (c=getchar()) != EOF){
if( (c==32 || c==10) && state==IN ){
//End of word
state=OUT;
histogram[current_length++];
}else if( (c>=33 && c<=126) && state==OUT ){
//Start of word
state=IN;
current_length=0;
}else if( (c>=33 && c<=126) && state==IN ){
//In a word
current_length++;
} else {
//Not in a word
//Example, " " or " \n "
;
}
}
//Print the histogram
//Recycle current_length to hold the length of the longest word
//Find longest word
for( c=0; c<50; c++){
if( c>histogram[c] )
current_length=histogram[c];
}
for( c=current_length; c>=0; c--){
for( state=0; state<=50; state++){
if( histogram[c]>=current_length )
printf("_");
else
printf(" ");
}
}
}
It's because histogram[c] = 0 writes past the histogram memory when c = 50. So essentially histogram[50] overwrites c and makes it 0.
This happens because arrays start from 0 in C. So the last valid index in a 50-element array is 49.
Technically, while interesting and exploitable you can't rely on this. It's a manifestation of undefined behavior. The memory could easily have another layout causing things to "just work" or do something funnier.
histogram has 50 elements: from index 0 to index 49.
You attempt to write to index 50. ALL BETS ARE OFF
do
while (c < 50)
or, to avoid magic constants
while (c < sizeof histogram / sizeof *histogram)
You are accessing elements 0 to 50 in histogram, which only contains elements 0 to 49 (C/C++ use zero-indexing, so the maximum element of an array will always be size-1).
To avoid errors like this, you could define the histogram size as a constant, and use that for all operations relating to the histogram array:
#define HISTOGRAM_SIZE 50
Or (only works for C99 or C++, see below comment):
const int HISTOGRAM_SIZE = 50;
Then:
int histogram[HISTOGRAM_SIZE];
And:
while(c<HISTOGRAM_SIZE)
'#define' is a C-preprocessor statement, and will be processed before compilation. To the compiler, it will just look as if you've written 50 everywhere where HISTOGRAM_SIZE is used, so you wont get any extra overhead.
'const int' gives you a similar solution, which in many cases will give the same result as with the define (I'm not 100% certain under which circumstances though, others are free to elaborate), but will also give you the added bonus of type-checking.

Caesar Cipher Program - Absurd Number in Array Output

I'm actually writing about the same program as before, but I feel like I've made significant progress since the last time. I have a new question however; I have a function designed to store the frequencies of letters contained within the message inside an array so I can do some comparison checks later. When I ran a test segment through the function by outputting all of my array entries to see what their values are, it seems to be storing some absurd numbers. Here's the function of issue:
void calcFreq ( float found[] )
{
char infname[15], alpha[27];
char ch;
float count = 0;
FILE *fin;
int i = 0;
while (i < 26) {
alpha[i] = 'A' + i++;
}
printf("Please input the name of the file you wish to scan:\n");
scanf("%s", infname);
fin = fopen ( infname, "r");
while ( !feof(fin) ) {
fscanf(fin, "%c", &ch);
if ( isalpha(ch) ) {
count += 1;
i = 0;
if ( islower(ch) ) { ch = toupper(ch); }
while ( i < 26 ) {
if ( ch == alpha[i] ) {
found[i]++;
i = 30;
}
i++;
}
}
}
fclose(fin);
i = 0;
while ( i < 26 ) {
found[i] = found[i] / count;
printf("%f\n", found[i]);
i++;
}
}
At like... found[5], I get this hugely absurd number stored in there. Is there anything you can see that I'm just overlooking? Also, some array values are 0 and I'm pretty certain that every character of the alphabet is being used at least once in the text files I'm using.
I feel like a moron - this program should be easy, but I keep overlooking simple mistakes that cost me a lot of time >.> Thank you so much for your help.
EDIT So... I set the entries to 0 of the frequency array and it seems to turn out okay - in a Linux environment. When I try to use an IDE from a Windows environment, the program does nothing and Windows crashes. What the heck?
Here are a few pointers besides the most important one of initializing found[], which was mentioned in other comments.
the alpha[] array complicates things, and you don't need it. See below for a modified file-read-loop that doesn't need the alpha[] array to count the letters in the file.
And strictly speaking, the expression you're using to initialize the alpha[] array:
alpha[i] = 'A' + i++;
has undefined behavior because you modify i as well as use it as an index in two different parts of the expression. The good news is that since you don't need alpha[] you can get rid of its initialization entirely.
The way you're checking for EOF is incorrect - it'll result in you acting on the last character in the file twice (since the fscanf() call that results in an EOF will not change the value of ch). feof() won't return true until after the read that occurs at the end of the file. Change your ch variable to an int type, and modify the loop that reads the file to something like:
// assumes that `ch` is declared as `int`
while ( (ch = fgetc(fin)) != EOF ) {
if ( isalpha(ch) ) {
count += 1;
ch = toupper(ch);
// the following line is technically non-portable,
// but works for ASCII targets.
// I assume this will work for you because the way you
// initialized the `alpha[]` array assumed that `A`..`Z`
// were consecutive.
int index = ch - 'A';
found[index] += 1;
}
}
alpha[i] = 'A' + i++;
This is undefined behavior in C. Anything can happen when you do this, including crashes. Read this link.
Generally I would advise you to replace your while loops with for loops, when the maximum number of iterations is already known. This makes the code easier to read and possibly faster as well.
Is there a reason you are using float for counter variables? That doesn't make sense.
'i = 30;' What is this supposed to mean? If your intention was to end the loop, use a break statement instead of some mysterious magic number. If your intention was something else, then your code isn't doing what you think it does.
You should include some error handling if the file was not found. fin = fopen(..) and then if(fin == NULL) handle errors. I would say this is the most likely cause of the crash.
Check the definition of found[] in the caller function. You're probably running out of bounds.

Averaging 3 integers

My assignment is to fix the code. I have my edited code below and the original code below that. I figure I still have a few errors in here. My error checking doesnt seem to work, and I am not sure if my getchar() function is written or working properly.
Please assume I know nothing becasue that is fairly accurate.
The code compiles, but the answer is always 2. I am about 4 hours into this piece of code with 3 more to work after this.
My code
#include <stdio.h>
double get_number(double num);
main () {
double n1,n2,n3;
double average;
printf("\nCompute the average of 3 integers\n");
printf("--------------------------------\n");
n1 = get_number(1);
n2 = get_number(2);
n3 = get_number(3);
average = (n1 + n2 + n3)/3;
printf("The average is %0.2f\n",average);
}
double get_number(double num) {
double value = 0;
char c;
int i;
printf("Please input number %d: ", num);
while (c = getchar != '\n') {
if ( (c>9) || (c<0) ) {
printf("Incorrect character entered as a number - %c\n",c);
return(0);
}
else {
value = num;
}
}
return(value);
}
Original code
#include <stdio.h>
main () {
double n1,n2,n3;
double average;
printf("\nCompute the average of 3 integers\n");
printf("--------------------------------\n");
n1 = get_number(1);
n2 = get_number(2);
n3 = get_number(3);
average = (n1 + n2 + n3)/3;
printf("The average is %0.2f\n",average);
}
double get_number(int num) {
double value = 0;
char c;
printf("Please input number %d: ", num);
while (c = getchar() != '\n') {
if ( (c<=9) && (c>=0) ) {
printf("Incorrect character entered as a number - %c\n",c);
exit(-1);
}
else {
value = 10*value + c - '0';
}
}
return(value);
}
A few issues:
1. You should be using '9' and '0', since you want the ASCII values for digit '9' (0x39) and '0' (0x30), not 0x9 and 0x0.
if ( (c>'9') || (c<'0') ) {
2. != has higher precedence than =, so you need parens. Learn operator precedence, and if you're in doubt, use parens:
3. getchar is a function not a variable.
while ((c = getchar()) != '\n') {
4. You use the wrong conversion. num is a double, so you would need %f. Or, you could make num a int.
printf("Please input number %f: ", num);
5. You never actually use c in any way (except error checking). You always return 0 or num (see your else clause), which makes no sense. The else body of the original is correct.
You got the floating point parsing all wrong and shouldn't be doing it yourself. There's an easier way:
double get_number(double num) {
double value = 0.0;
printf("Please input number %lf: ", num);
scanf("%lf", &value);
return(value);
}
The issues with the original program are:
getchar() returns an ASCII code, and the condition was wrong. When checking for boundaries, use ((c<'0') || (c>'9')).
For the exit function you need to include "stdlib.h".
For the main function to understand what is get_number, you need to either move the function to be before the main function, or you can use a forward declaration.
The assignment operator (=) has lower precedence than the inequality operator (!=), so you need to use parenthesis, like: ((c = getchar()) != '\n')
You have actually created several more issues, so I wouldn't rely on your code.
In any case, in general - it is advised you study how to use a debugger. Once your code is compiling (and for that you'll need to get accustomed to the compilation error messages), you need to start debugging your code. I suggest you take some time to learn how to set breakpoints, set watches, and go step by step into your code. That skill is absolutely essential for a good developer.
Here's how I'd go about correcting the code ...
http://ideone.com/a0UMm -- compilation errors
http://ideone.com/ljUg1 -- warnings, but it works now
http://ideone.com/Qd0gp -- no errors, no warnings, test run ok
For 1. I used the "original code" as posted by you.
For 2. I used int main(void), declared the function get_number before defining main, added parenthesis in line 20, and added #include <stdlib.h>
For 3. I added return 0; before the final } of main. I also removed the extra output that messed up the ideone interface (it looks better on an interactive interface)
Edit more tests needed to complete the task of correcting the original code

Resources