process exits prematurely C programming - c

there is a part where the program asks the user to enter Y or N and then loops beck when I choose N or else it will end the while loop and continue. when I choose the Y for the first time the program works fine but when I choose N and then Y after my program exits even if it does not encounter the return keyword from the main
and it exits with a garbage return value. It stops at system("cls");. Can anyone tell me what's wrong with this code. Note:
Statistician is an integer pointer type that I created with typedef. And, I've also declared the SIZE variable in the survey.h file
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include "survey.h"
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int main(int argc, char *argv[]) {
SIZE = 10;
int c, count = 0, item = 0;
Statistician arr;
float mea, med;
arr = (int*)calloc(10, sizeof(int));
printf("Enter 10 answers\n");
while(count < SIZE) // this is the while loop that loops until Y is chosen by the user in the add function
{
while(item > 9 || item < 1)
{
scanf("%d", &item);
}
++count;
add(arr, &count, &SIZE, item);
item = 0;
}
system("cls");
mea = mean(arr, count);
med = median(arr, count);
printf("mean = %f\n", mea);
printf("median = %f\n", med);
return 0;
}
definition of add() function:
void add(Statistician answer, int *count, int *SIZE, int item)
{
int i, j, temp;
bool swapped;
char choice;
answer[*count - 1] = item;
for(i = 0; i < *count - 1; i++)
{
swapped = false;
for(j = 0; j < *count - i - 1; j++)
{
if(answer[j] > answer[j + 1])
{
temp = answer[j];
answer[j] = answer[j + 1];
answer[j + 1] = temp;
swapped = true;
}
}
if(swapped == false)
break;
}
if(*count == *SIZE)
{
printf("Array is full do you want to compute now?\n");
while(toupper(choice) != 'N' && toupper(choice) != 'Y') // The part where the program ask for Y or N.
{
choice = toupper(getch());
}
if(toupper(choice) == 'Y') // returns without changing the value of SIZE thus ending the while loop at main
{
return;
}
else if(toupper(choice) == 'N') // adds 10 to SIZE thus continuing the while loop in main and returns
{
printf("add another 10 answers\n");
*SIZE += 10;
realloc(answer, *SIZE);
}
}
return;
}

There are probably other issues (I'm not going to look too closely), but you certainly need to fix:
while(item > 9 || item < 1)
{
scanf("%d", &item);
}
If scanf matches zero items, then that is an infinite loop, with scanf repeatedly returning 0, reading the same data and not changing item. You must always check the value returned by scanf.

This is a serious bug:
realloc(answer, *SIZE);
You don't save the return value so you have lost the allocated memory. Further, you forgot the object size.
In principle you should do
Statistician tmp = realloc(answer, *SIZE * sizeof(int));
if (tmp == NULL)
{
// Error handling
// or just
exit(1);
}
answer = tmp;
However, that doesn't fully help. The problem is that it will only change the value of answer inside the function but not the value of arr in main. In order to change the value of arr you'll have to pass the address of arr to the function. Similar to what you have done with SIZE. BTW: Why do you pass counter as a pointer? You never change it in the function, so it unnecessary to pass a pointer.
Also your current code doesn't initialize choice.
Change
printf("Array is full do you want to compute now?\n");
while(toupper(choice) != 'N' && toupper(choice) != 'Y') // The part where the program ask for Y or N.
to
printf("Array is full do you want to compute now?\n");
choice = ' ';
while(toupper(choice) != 'N' && toupper(choice) != 'Y') // The part where the program ask for Y or N.
or better:
printf("Array is full do you want to compute now?\n");
do
{
choice = toupper(getch());
} while(toupper(choice) != 'N' && toupper(choice) != 'Y');
BTW:
Since you have choice = toupper(getch()); you don't need toupper(choice) != 'N'. Simply do choice != 'N'
All that said - why do you want to ask the question inside the function? Your code will be much simpler if you do it in main.
Something like:
int main(void) {
int SIZE = 10;
int c, count = 0, item = 0;
int* arr;
float mea, med;
arr = calloc(10, sizeof(int));
printf("Enter 10 answers\n");
while(count < SIZE)
{
while(item > 9 || item < 1)
{
if (scanf("%d", &item) != 1) exit(1);
}
++count;
add(arr, count, item);
item = 0;
if (count == SIZE)
{
printf("Array is full do you want to compute now?\n");
char choice;
do
{
choice = toupper(getch());
} while(choice != 'N' && choice != 'Y');
if(choice == 'N')
{
printf("add another 10 answers\n");
SIZE += 10;
int* tmp = realloc(arr, SIZE * sizeof *arr);
if (tmp == NULL) exit(1); // or error handling
arr = tmp;
}
}
}
system("cls");
mea = mean(arr, count);
med = median(arr, count);
printf("mean = %f\n", mea);
printf("median = %f\n", med);
return 0;
}
void add(int* answer, int count, int item)
{
int i, j, temp;
bool swapped;
answer[count - 1] = item;
for(i = 0; i < count - 1; i++)
{
swapped = false;
for(j = 0; j < count - i - 1; j++)
{
if(answer[j] > answer[j + 1])
{
temp = answer[j];
answer[j] = answer[j + 1];
answer[j + 1] = temp;
swapped = true;
}
}
if(swapped == false)
break;
}
return;
}

Related

why can't my program recognize similar words in a string?

I want to write a program that will take an input T. In the next T lines, each line will take a string as an input. The output would be how many ways the string can be reordered.
#include <stdio.h>
#include <stdlib.h>
int main() {
int T, i, l, count = 1, test = 0, word = 0, ans;
char line[200];
scanf("%d", &T);
for (i = 0; i < T; i++) {
scanf(" %[^\n]", line);
l = strlen(line);
for (int q = 0; q < l; q++) {
if (line[q] == ' ') {
word++;
}
}
ans = fact(word + 1);
word = 0;
for (int j = 0; j < l; j++) {
for (int k = j + 1; k < l; k++) {
if (line[k] == ' ' && line[k + 1] == line[j]) {
int m = j;
int n = k + 1;
for (;;) {
if (line[m] != line[n]) {
break;
} else
if (line[m] == ' ' && line[n] == ' ') {
test = 1;
break;
} else {
m++;
n++;
}
}
if (test == 1) {
count++;
ans = ans / fact(count);
count = 0;
test = 0;
}
}
}
}
printf("%d\n", ans);
}
}
int fact(int n) {
if (n == 1) {
return 1;
} else {
return n * fact(n - 1);
}
}
Now, in my program,
my output is like this:
2
no way no good
12
yes no yes yes no
120
if T = 2 and the 1st string is no way no good, it gives the right output that is 12 (4!/2!). That means, it has identified that there are two similar words.
But in the 2nd input, the string is yes no yes yes no. that means 3 yes and 2 nos. So the and should be 5!/(3!2!) = 10. But why is the answer 120? and why can't it recognize the similar words?
The main problem in your duplicate detector is you test the end of word with if (line[m] == ' ' && line[n] == ' ') but this test fails to identify a duplicate that occurs with the last word because line[n] is '\0', not ' '.
Note these further problems:
you do not handle words that occur more than twice correctly: you should perform ans = ans / fact(count); only after the outer loop finishes. For example, if a word is present 3 times, it will be detected as 3 pairs of duplicates, effectively causing ans to be divided by 23 = 8, instead of 3! = 6.
you should protect against buffer overflow and detect invalid input with:
if (scanf(" %199[^\n]", line) != 1)
break;
the range of type int for ans is too small for a moderately large number of words: 13! is 6227020800, larger than INT_MAX on most systems.
The code is difficult to follow. You should consider parsing the line into an array of words and using a more conventional way of counting duplicates.
Here is a modified version using this approach:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int cmpstr(const void *p1, const void *p2) {
char * const *pp1 = p1;
char * const *pp2 = p2;
return strcmp(*pp1, *pp2);
}
unsigned long long factorial(int n) {
unsigned long long res = 1;
while (n > 1)
res *= n--;
return res;
}
int main() {
int T, i, n, begin, count;
unsigned long long ans;
char line[200];
char *words[100];
if (!fgets(line, sizeof line, stdin) || sscanf(line, "%d", &T) != 1)
return 1;
while (T --> 0) {
if (!fgets(line, sizeof line, stdin))
break;
n = 0;
begin = 1;
for (char *p = line; *p; p++) {
if (isspace((unsigned char)*p)) {
*p = '\0';
begin = 1;
} else {
if (begin) {
words[n++] = p;
begin = 0;
}
}
}
qsort(words, n, sizeof(*words), cmpstr);
ans = factorial(n);
for (i = 0; i < n; i += count) {
for (count = 1; i + count < n && !strcmp(words[i], words[i + count]); count++)
continue;
ans /= factorial(count);
}
printf("%llu\n", ans);
}
return 0;
}

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.

Why is my "c" variable growing exponentially when it reaches the 3rd cycle in the for loop?

I am having a problem, here with a program that is meant to be a data entry routine, the problem in question, is the variable c that goes to the capac function to ask the user for the maximum capacity of the string, when it reaches the 3rd cycle of the for it starts to grow god knows how, making my for, something unusable.
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<string.h>
int func_carac(int *car) //function that catches characters introduced by the user
{
int caracter;
printf("\nType the character you want: \n");
caracter = getche();
*car = caracter;
return *car;
}
//________________________________________________________\\
int func_capac(int *cap) //function to ask the user for the amount of characters
{
int quant;
printf("\nDetermine the maximum character capacity you want to write: ");
scanf("%d",&quant);
*cap = quant;
return *cap;
}
int main()
{
int car, pos, c, total;
char vetor[] = {'\0'};
func_capac(&c);
total = c + 1;
vetor[total];
vetor[total] = '\0';
printf("%i", c);
for(pos = 0; pos < c; pos++)
{
func_carac(&car);
if((car >= 97) && (car <= 122) || (car == 32))
{
printf("\n%c - Tabela ASCII, %d \n",car ,car);
printf("%i", c);
vetor[pos] = (char) car;
}
else if(car == 8)
{
printf("Successfully removed the previous character.");
pos = pos-2;
}
else
{
pos--;
}
}
printf("Frase: %s\n",vetor);
}
If someone could help me, I would be grateful
#Someprogrammerdude nailed it. vector[] = { '\0' } means that vector is an array of length 1. As you write to vector after position 0 you end up with undefined behavior (i.e. overwriting c somehow). Here is the minimal fix:
int main()
{
int car, pos, c, total;
func_capac(&c);
total = c + 1;
char vetor[total];
for(int i = 0; i < total; i++) vetor[i] = 0; // or memset(vector, 0, total);
...

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.

Reverse Polish converter

I am trying to make a reverse Polish printer which can perform the following operation-
Inputs:
(a+(b*c))
((a+b)*(z+x))
((a+t)*((b+(a+c))^(c+d)))
Outputs:
abc*+
ab+zx+*
at+bac++cd+^*
This is my code:
#include <stdio.h>
#include <string.h>
char pop(int t);
void push(int c, int t);
int main()
{
int z;
scanf("%d", &z);
char *a[100];
int i = 0;
int q = z;
while (q-- > 0)
{
char v[400];
scanf("%s", &v);
int t;
for (t = 0; t < strlen(v); t++) //loop to put the values and signs in the 2 stacks
{
if ((v[t] == '*') || (v[t] == '+') || (v[t] == '-') || (v[t] == '^'))
{
push(v[t], 2);
}
else if (v[t] == ')')
{
int y = pop(2);
push(y, 1);
}
else
{
push(v[t], 1);
}
}
int k = 0;
char c;
while ((c = pop(1)) !='\0') //loop to put elements in the array v
{
if (c != '(')
{
v[k++] = c;
}
}
v[k--] = '\0';
int m;
for (m=0; m != k; m++, k--) //for reversing the string
{
char t = v[m];
v[m] = v[k];
v[k] = t;
}
a[i++] =v;
printf("%s",a[i - 1]);
}
int p;
for (p = 0; p <z ; p++) //printing the elements
printf("%s\n",*a[p]);
return 0;
}
char ac[400];
char as[400];
int ic = 0;
int is = 0;
void push(int c,int t)
{
if (t == 1 && ic != 400)
ac[ic++] = c;
else if (t == 2 && is != 400)
as[is++] = c;
}
char pop(int t)
{
if (t == 1 && ic != 0)
return ac[--ic];
if (t == 2 && is != 0)
return as[--is];
return '\0';
}
But it is not even inputting properly and I am not able to figure out what are the mistakes in this code.Please help to figure out what are the problems.
after inputing the no of test cases i.e.int z and first line if input
it crashes
This is due to the
printf("%s\n",*a[p]);
as BLUEPIXY noticed, *a[p] is a char; but %s expects a char *, thus you need
printf("%s\n", a[p]);
and regarding v is out of scope, the crucial factor is not the scope (visibility), but the storage duration (lifetime) of v - its lifetime ends when execution of the block with which it is associated ends, and the value of a pointer a[i] to it becomes indeterminate; by changing
a[i++] =v;
to
a[i++] = strdup(v);
you can remedy that.

Resources