The code does not seem to execute properly - c

Gets stuck inside of the valid = 0 while loop where it does not get passed scanf and keeps asking for input. The program was designed to accept an integer value for the GPA and then calculate the frequency of each gpa among what had been given.
#include <stdio.h>
int main(void) {
int amount, i, count, valid;
int GPA[200], GPAFreq[4];
valid = 0;
i = 1;
count = 1;
GPA[1] = 0; GPA[6] = 0;
GPA[2] = 0; GPA[7] = 0;
GPA[3] = 0; GPA[8] = 0;
GPA[4] = 0; GPA[9] = 0;
GPA[5] = 0; GPA[10] = 0;
GPAFreq[1] = 0; GPAFreq[3] = 0;
GPAFreq[2] = 0; GPAFreq[4] = 0;
printf("Enter the number of students: ");
scanf("%d", &amount);
while ( i < (amount + 1))
{
i += 1;
while (valid == 0)
{
printf("%d", GPA[i]);
if ( (GPA[i] == 4) || (GPA[i] == 3) || (GPA[i] == 2) || (GPA[i] == 1) )
{
valid = 1;
}
else
{
printf("GPA of student # %d is: ", i);
scanf("%d", &GPA[i]);
}
}
count = 1;
while (count < 5)
{
if (GPA[i] == count)
{
GPAFreq[count] +=1;
}
}
}
count = 1;
while (count < 5)
{
printf("\nGPA %d --- %d student(s).", count, GPAFreq[count]);
count += 1;
}
return 0;
}

When I execute this it does not get stuck on the while(valid == 0) loop, it gets stuck in the 1st while(count < 5) because you do not increment count inside this loop.
There are a few other things that pop out immediately to me in this code that I might as well point out.
You can automatically have all elements of an array set to 0 by declaring like int array[10] = {0}. There are a few ways of doing this (including for loops), but you don't need to manually type each one out like you do in lines 11-18
Arrays are 0 indexed in c, so you start counting from 0, not 1
You increment i at the beginning of the while loop (line 26) before it is accessed. Thus meaning the first index actually being used is 2 (remember it should be 0)
If you are limiting your number of students to 200, you should make sure the user doesn't enter in a number larger than this.
EDIT:
You will also need to reset valid to 0 before the while(valid == 0) loop (you could also just do while(!valid) btw)

Related

A variable in a for loop is changing without being supposed to change in c

Here is the code:
#include <stdio.h> // printf
#include <cs50.h> // get_long
#include <string.h> // strlen
#include <stdlib.h> // stdlib
int credit_test(string input);
int main(void)
{
string userInput;
// Gets user input, and tests if input is valid
bool isInvalid = false;
do
{
userInput = get_string("Number: "); // Prompts user for input
for(int i = 0, evenIndex = strlen(userInput); evenIndex > i; i++)
{
if(userInput[i] - 48 >= 0 && userInput[i] - 48 <= 9 && (strlen(userInput) == 15 || strlen(userInput) == 16)) // Tests if input is valod
{
isInvalid = false;
}
else
{
isInvalid = true;
break;
}
}
}
while(isInvalid);
int keyValidity = credit_test(userInput);
}
int credit_test(string input)
{
int inputLen;
inputLen = strlen(input);
// Even number calculation
int evenArr[16];
int evenSum = 0;
int evenIndex = 0;
printf("Length: %i\n", inputLen);
for(int i = 0; inputLen > i; i++)
{
int n = i * 2;
evenArr[evenIndex] = input[n] * 2;
if(evenArr[evenIndex] > 0)
{
evenArr[evenIndex] -= 96;
}
if(evenArr[evenIndex] > 9) // Code to split doubles
{
int doubleNum = evenArr[evenIndex];
evenArr[evenIndex] = 1;
evenIndex++;
evenArr[evenIndex] = doubleNum % 10;
}
evenIndex++;
evenSum += evenArr[i];
printf("%i\n", evenArr[i]);
printf("Length: %i\n", inputLen);
}
printf("Length: %i\n", inputLen);
printf("Even Sum: %i\n", evenSum);
// Odd number calculation
int oddArr[16];
int oddSum = 0;
int oddIndex = 1;
for(int i = 0; 16 > i; i++)
{
oddArr[i] = input[oddIndex];
if(oddArr[i] > 0)
{
oddArr[i] -= 48;
}
oddSum += oddArr[i];
oddIndex += 2;
printf("%i\n", oddArr[i]);
}
printf("Odd Sum: %i\n", oddSum);
// Validity test
int finalSum = evenSum + oddSum;
int cardType = finalSum % 10;
printf("Final Sum: %i\n", finalSum);
if(cardType == 0 && (input[0] - 48) == 5)
{
printf("MasterCard \n");
}else if (cardType == 0 && (input[0] - 48) == 4)
{
printf("Visa \n");
}else if(cardType == 0 && (input[0] - 48) == 3)
{
printf("Amex \n");
}else
{
printf("Invalid \n");
}
return 0;
}
I just cannot wrap my head around why, but if you run the code, and keep an eye on the "inputLen" variable it stays what it should be, but in the first for loop which gets the even number in the input, the inputLen stays the same, which is correct, but when the loop finishes, for some reason, the variable changes to 0? So would anyone mind to explain as to why its happening? And sorry if the code is all wonky and bad :)
Thanks so much.
This part of the loop
for(int i = 0; inputLen > i; i++)
{
int n = i * 2;
evenArr[evenIndex] = input[n] * 2;
//...
invokes undefined behavior because the expression input[n] can access memory beyond the used array due to using the expression i * 2 as an index. For example then i is equal to inputLen - 1 then n will bi initialized by the expression 2 * ( inputLen - 1 ) and the value of the expression you are using as an index to access elements of the array input but the array does not have so many elements.
Also in this code snippet
if(evenArr[evenIndex] > 9) // Code to split doubles
{
int doubleNum = evenArr[evenIndex];
evenArr[evenIndex] = 1;
evenIndex++;
evenArr[evenIndex] = doubleNum % 10;
}
evenIndex++;
the variable evenIndex can be incremented twice that again can be a reason of undefined behavior when this variable is used as an index to access elements of the array evenArr.

Is there a way to include more than one 'if' conditional for output?

I have this code below (whole code after this section). I am wanting to include more than one casse for this section of the code:
for(i = 0; i < length; i++)
{
if(numberArray[i] == 1)
{
casse = 2;
}
if(numberArray[i] == 2)
{
casse = 3;
}
if(numberArray[i] == 1 || numberArray[i] == 2)
{
casse = 4;
}
}
So far, the above prints '4' when the value '8213' is entered. This is expected since for each round of for loop the 'casse' variable gets updated, by the time it runs the last integer in the array, the value for 'casse' has undergone many replacements and the end result is the last replacement of '4'.
The objective of the code is to determine which cases (casse) have
been met. There can be more than one case (casse) being met, but as it
stands now, it only has room for one case.
#include <stdio.h>
#include <math.h>
int main(void) {
int odo, value, casse;
int i;
printf("please enter a value for the odometer:\n");
scanf("%d", &odo);
value = odo;
casse = 0;
int length = floor(log10(abs(odo))) + 1;
/* count number of digits */
int c = 0; /* digit position */
int n = value;
while (n != 0)
{
n /= 10;
c++;
}
int numberArray[c];
c = 0;
n = value;
/* extract each digit */
while (n != 0)
{
numberArray[c] = n % 10;
n /= 10;
c++;
}
for(i = 0; i < length; i++)
{
printf("%d, ", numberArray[i]);
}
for(i = 0; i < length; i++)
{
if(numberArray[i] == 1)
{
casse = 2;
}
if(numberArray[i] == 2)
{
casse = 3;
}
if(numberArray[i] == 1 || numberArray[i] == 2)
{
casse = 4;
}
}
printf("\n%d\n", casse);
return 0;
}
Output:
please enter a value for the odometer:
8213
3, 1, 2, 8,
4
Expected output:
please enter a value for the odometer:
8213
3, 1, 2, 8,
Not only '4', but also '3', '2'.
Rather than a single variable that keeps track of the last case, you want an array which keeps track of all cases. For a small number of cases, the array can be a fixed size, with the index as case number and the value in the array as the number of times that case was triggered:
int cases[5] = {0};
for(i = 0; i < length; i++)
{
if(numberArray[i] == 1)
{
cases[2]++;
}
if(numberArray[i] == 2)
{
cases[3]++;
}
if(numberArray[i] == 1 || numberArray[i] == 2)
{
cases[4]++;
}
}

Sum of integers, not counting 13 and the number after 13

I am new to C and trying to Write a program that reads in a series of integers until a value of zero is encountered and then prints the sum of all the numbers except those that are equal to 13 or that come immediately after a 13. It is guaranteed that there is at least one zero in the input.
At most 100 lines of input, each line containing a single integer. At least one of the lines will contain the integer 0.
My code is like this:
#include <stdio.h>
int main ()
{
int sum = 0;
int data[100];
int i = 0;
scanf("%d\n", &data[i]);
while (data[i] != 0 && i < 100) {
if (data[i] == 13) {
sum = sum;
} else if (i > 0 && data[i-1] == 13) {
sum = sum;
} else {
sum += data[i];
i++;
}
scanf("%d\n", &data[i]);
}
printf("%d",sum);
}
I tried to get rid of the number after 13 but failed... Please help.
You could also try this:
// extra flag outside loop
int found13 = 0;
while (data[i] != 0 && i < 100) {
if (data[i] == 13) {
found13 = 1; // set flag
} else if (found13) {
found13 = 0; // clear flag
} else {
sum += data[i];
i++;
}
scanf("%d\n", &data[i]);
}
Improvements:
Doesn't peek back at the previous element
Doesn't need to constantly check i > 0):
EDIT: further refactor
int sum = 0;
int found13 = 0;
int data;
while (scanf("%d\n", &data) == 1 && data != 0) {
if (data == 13) {
found13 = 1; // set flag
} else if (found13) {
found13 = 0; // clear flag
} else {
sum += data;
}
}
Improvements:
As #PaulOgilvie pointed out, you no longer need an array to store your results
... neither do you need i
... nor the extra call to scanf outside the loop
Now works for any number of inputs
It is easiest to collect all conditions in one boolean expression of the if-statement:
if (data[i] != 13 && (i == 0 || data[i-1] != 13){
sum += data[i];
}
i++;
... and move i outside the if body.

How to store values in dynamic array in C

I am trying to assign values to elements in dynamic array, but can't find solution. There are many videos showing how it works if value is entered by the user via scanf, but here it's not the case. I really tried to find info here and there and solve it myself so any help will be highly appreciated.
Here is my code:
//Program co convert decimal number to binary and count zeros
int main()
{
int decimalNum;
int *binaryNum;
int zeroCounter = 0;
int i = 0;
int sizeOfArray;
int decimalNumCopied;
printf("Please enter a number from 0 to 255: ");
scanf("%d", &decimalNum);
decimalNumCopied = decimalNum;
while(decimalNum != 0)//checking number of bits;
{
decimalNum = decimalNum / 2;
i++;
}
sizeOfArray = i;
//Trying to allocate just enough memory
binaryNum = (int*)malloc(sizeOfArray * sizeof(int));
while(decimalNumCopied != 0)
{
/*At next step I am trying to assign values to each element of the
array and it doesn't work
*/
binaryNum[i] = decimalNumCopied % 2;
decimalNumCopied = decimalNumCopied / 2;
i--;
}
for(i = 0; i <= sizeOfArray; i++)
{
printf("%d", binaryNum[i]);
if(binaryNum[i]== 0){zeroCounter++;}
}
printf("\nThere are %d zeroes", zeroCounter);
free(binaryNum);
return 0;
}
Your first assignment is outside the bounds of the array. This gives you undefined behavior.
Remember that arrays are indexed from zero, so if i is the length of the array it is not a valid index (it's one beyond the last valid index).
There are two errors here.
First, when you start assigning values to the array i is equal to the number of elements in the array. Since arrays in C have indexes from 0 to n-1, where n is the length, you're writing one element past the end of the array. Doing so invokes undefined behavior, which in this case (lucky for you) manifests in a crash.
You need to decrement i once before entering the loop to start writing at the proper offset.
i--;
while(decimalNumCopied != 0)
{
...
The second issue is with the printing. Your for loop starts at 0 (as it should), but stops when i <= sizeOfArray is no longer true. So on the last iteration i is equal to sizeOfArray, so read one element past the end of the array. Again, this invokes undefined behavior.
Change the condition to < to prevent this:
for(i = 0; i < sizeOfArray; i++)
I felt this was a useful program so incorporating the answer by dbush and others, here it is fixed, valgrind checks good, with some user input error handling, some stylistic changes, and alternatively also accepts input from the command line.
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char**argv) {
int decimalNum;
int *binaryNum;
int zeroCounter = 0;
int i = 0;
int sizeOfArray;
int decimalNumCopied;
if (argc == 2) {
decimalNum = atoi(argv[1]);
}
if(argc == 1 || decimalNum < 0 || decimalNum > 255) {
printf("Please enter a number from 0 to 255: ");
scanf("%d", &decimalNum);
while (decimalNum < 0 || decimalNum > 255) {
printf("Program is expecting an int from 0 to 255 inclusive\n"
"Please enter a number from 0 to 255: ");
scanf("%d", &decimalNum);
}
}
decimalNumCopied = decimalNum;
while (decimalNum != 0) {
decimalNum /= 2;
i++;
}
sizeOfArray = i;
binaryNum = malloc(sizeOfArray * sizeof(int));
i--;
while (decimalNumCopied != 0) {
binaryNum[i] = decimalNumCopied % 2;
decimalNumCopied /= 2;
i--;
}
for (i = 0; i < sizeOfArray; i++) {
printf("%d", binaryNum[i]);
if (binaryNum[i] == 0) { zeroCounter++; }
}
printf("\nThere are %d zeroes\n", zeroCounter);
free(binaryNum);
return 0;
}

Segmentation fault in base number program?

I keep trying to test this code but I keep getting a segmentation fault in my power() function. The code is supposed to take a word made up of lowercase letters and change the word to a number of base 10. The word is supposed to take on the form of a number of base 20, where 'a' = 0, 'b' = 1,...., 't' = 19;
int power(int i){
if(i==1){
return 20;
}else{
return 20*power(i--);
}
}
int main(){
int len;
char mayan[6];
int n;
int val;
while(scanf("%s", mayan)){
val = 0;
n = 0;
for(len = 0; mayan[len] != '\0'; len++){
mayan[len] = tolower(mayan[len]);
mayan[len] = mayan[len] - 'a';
}
for(i = 0; len >= 0; len--, i++){
if(mayan[len] <= 19){
n = n + mayan[len] * power(i);
}else{
fprintf(stderr, "Error, not a base 20 input \n");
val = 1;
break;
}
}
if(val==0){
printf("%d \n", n);
}
}
return val;
}
There were three mistakes in your code.
Case for i==0 not added in the power function, which basically translates to any number to the power of zero is one i.e. x^0 = 1;.
Instead of using return 20*power(i--); for your recursive call, use return 20*power(i-1);. i-- is post decrement operator, which means that, it will return the value of i as it is and will the decrement it for further use, which is not what you want. Also, you altogether don't even want to change the value of i for this iteration too; what you want to do is use a value one less than i for the next iteration, which is what, passing i-1, will do.
Add a len-- in the initialization of the for(i = 0; len >= 0; len--, i++) loop, because len is now over the last index of the input because of the previous loop.
Correcting these mistakes the final code is:
#include<stdio.h>
int power(int i)
{
if(i==0)
{
return 1;
}
if(i==1)
{
return 20;
}
else
{
return 20*power(i-1);
}
}
int main()
{
int len,i;
char mayan[6];
int n;
int val;
while(scanf("%s", mayan))
{
val = 0;
n = 0;
for(len = 0; mayan[len] != '\0'; len++)
{
mayan[len] = tolower(mayan[len]);
mayan[len] = mayan[len] - 'a';
}
for(i = 0, len--; len >= 0; len--, i++)
{
if(mayan[len] <= 19)
{
n = n + mayan[len] * power(i);
}
else
{
fprintf(stderr, "Error, not a base 20 input \n");
val = 1;
break;
}
}
if(val==0)
{
printf("%d \n", n);
}
}
return val;
}
Note that, your code would essentially only work for at most a five digit base 20 number, because, the array mayan that you are using to store it has size 6, of which, one character will be spent for storing the terminating character \0. I recommend that you increase the size of the array mayan unless you want to support only five digit base 20 numbers.

Resources