-3

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;
}
Hans
  • 5
  • 4
  • Read [*Modern C*](https://modernc.gforge.inria.fr/), see [this C reference](https://en.cppreference.com/w/c), read the documentation of your C compiler (e.g. [GCC](http://gcc.gnu.org/)...) and of your debugger (e.g. [GDB](https://sourceware.org/gdb/)) and **use your debugger** – Basile Starynkevitch Sep 11 '20 at 12:30
  • Can you show the definition of `Statistician`? – David Ranieri Sep 11 '20 at 12:30
  • Enable also all warnings and debug info when compiling. With [GCC](http://gcc.gnu.org), compile using `gcc -Wall -Wextra -g`. Provide some [mre] in your question – Basile Starynkevitch Sep 11 '20 at 12:30
  • `choice` is uninitialized when you are using it for the first time. – Roy Avidan Sep 11 '20 at 13:18
  • Have you tried running your code line by line in a debugger while monitoring the values of all variables, in order to determine at which point your program stops behaving as intended? If you did not try this, then you may want to read this: [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/q/25385173/12149471) You may also want to read this: [How to debug small programs?](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). With the information obtained through the debugger, you can then create a [mre] of your problem. – Andreas Wenzel Sep 11 '20 at 13:21
  • Welcome to Stack Overflow. When you write code, it is a good idea to implement new functionality *in isolation* as much as possible. If you have trouble with reading {Y,N} and exiting cleanly, then try writing a program that does that and nothing else. Bugs are much easier to find in small programs. – Beta Sep 11 '20 at 13:22

2 Answers2

2

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.

William Pursell
  • 204,365
  • 48
  • 270
  • 300
1

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;
}
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • I tried printing the 'arr' in main it still works because the Statistician is a pointer. I've already written this in **survey.h**. `typedef int* Statistician;`. Also, I have initialized `choice` and changed `while` into `do...while`. It still stops at `system("cls");` in main. – Hans Sep 11 '20 at 13:35
  • @Hans No, `arr` in `main` can't be changed with your code. So your `realloc` will never be seen in `main`. It doesn't matter that `arr` is a `int*`. – Support Ukraine Sep 11 '20 at 14:26