-1

Im trying to create a program that has 2 options, view and compute. Right now im trying to figure how to turn my array where i will input my values into a function, so i can go in and out several times to store the values. I also want to view to be a function where i can view the values several times.

i've managed to get the computing part to work in my main, now i need to turn it into a function. Secondly how do i create a second function to view it?

My code is a bit mess please bear with me.

#include <stdio.h>
#define LENGTH 10

int enterMeasurements();

int main(void)
{
char input;
int nrMeasurements=0;
int arrayTable[LENGTH] = {0};
//main menu
do
{
    char input;
    printf("\nMeasurement tool 1.0\n");
    printf("V for (View)\n");
    printf("E for (Enter Values)\n");
    printf("C for (Compute Values)\n");
    printf("R for (Reset Values)\n");
    printf("Q for (Quit)\n");
    printf("\nEnter input: ");
    scanf(" %c", &input);

    if(input == 'v' || input == 'V')
    {
    // function to print array values
    printf("[      ]\n");
    }
    else if(input == 'e' || input == 'E')
    {
    // enter values here
        nrMeasurements = enterMeasurements(arrayTable,nrMeasurements); // my function for entering values
    }
    else if (input == 'c' || input == 'C')
    {
    // enter function to calc min, max and avg and prints it.
    printf("[   min max avg   ]\n");
    }
    else if (input == 'r' || input == 'R')
    {
    // enter function that erase the entire array.
    printf("[   erase array   ]\n");
    }
}
while (input !='q' && input != 'Q');
return 0;
}

int enterMeasurements()
{
int enterMeasurements(int arrayTable[], int nrMeasurements)
{
int i;

for (i = 0; i < LENGTH; i++)
{
    printf("Enter Measurement #%i (or 0): ", i+1);
    scanf("%d", &arrayTable[i]);


    if (arrayTable[i] == 0 )
        break;
}


return i;


}
xxFlashxx
  • 261
  • 2
  • 13
  • 4
    Do you know how to pass arguments to functions? Do you know how to create functions that takes one or more arguments? – Some programmer dude Sep 21 '16 at 07:56
  • @JoachimPileborg Hi im reading on the topic but i'm not really getting the hang of it. not sure when to declare it as int or void. i guess when i print something i should declare it as void. Not sure about my compute function though. – xxFlashxx Sep 21 '16 at 08:04

2 Answers2

1

To help you get started (you should really read a beginners book on the subject) I will show you the printArray function.

First of all the printArray function needs to know the actual array to print. it also needs to know the number of elements in the array. This can be accomplished in two ways: Global variables (which no-one is really recommending) or with function arguments.

You first need to tell the compiler that the function takes arguments:

void printArray(int *array, size_t numElements)

The above line tells the compiler that the printArray function takes two arguments: One which is called array and is a pointer to int (arrays "decays" to pointers to their first element when passed to functions), and one argument that is named numElements and is of type size_t (which is a good type for sizes and number of elements and similar things). The function is declared to return nothing with the void keyword.

The declared arguments can then be used inside the function like any other variables in the scope of the function, and are in fact just like any other local variable defined inside the function. So you can then use them like e.g.

void printArray(int *array, size_t numElements)
{
    for (size_t i = 0; i < numElements; ++i)
    {
        printf("array[%d] = %d\n", i, array[i]);
    }
}

To call this function you need to pass the array and the number of elements, much like you pass arguments to any other function like scanf or printf:

printArray(arrayTable, i);

Note that the function doesn't return anything, which means you can't use it in printf, or any other expression that expects a value.

You should of course also make your forward function prototype declaration match the actual function definition.

Community
  • 1
  • 1
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • thanks man. sort of get what you did. Now im printing out the values of my arrays, which is a great leap forward for me. I still dont understand how to turn my main array into a function. Shall i move the entire code in main down like you did with the print function and add `int input()` or something like that. Then afterwards calling it in my main? – xxFlashxx Sep 21 '16 at 08:47
  • No, that's where your conceptual train-wreck is occurring. You will not turn your array into anything -- it's an array and will always be an array. That said, you can pass your array to a function as above, and do to the numbers anything you like. You can also create several functions and pass the same array to them (e.g. `void printarray (...)` and `int arraymax (...same stuff...)`, etc.) But regardless, you are not turning your array into anything other that what it already is. Perhaps you can explain more what you need to accomplish? – David C. Rankin Sep 21 '16 at 08:50
  • Additionally, the [**c tag wiki**](http://stackoverflow.com/tags/c/info) contains a list of good books and links that can help you learn the basics of C. Drop by and take a look. – David C. Rankin Sep 21 '16 at 08:54
  • @DavidC.Rankin Hi David, thanks for the input. Well im trying to build a simple menu where i have the option to view my arrray or store values into the array. so if i input say 'c' for compute, the computer asks me to input values, i can input say 1 2 3 4 then i type 0 to quit. I will now be back at the menu and be asked the same thing ie type V to view or C to compute, i type V now they print the values such as 1 2 3 4. I return to the main and now i get into C (compute) again and continue to store my 5th 6th values etc. Im not sure how to do this. – xxFlashxx Sep 21 '16 at 09:00
  • That makes more sense. All of that can be handled with a simple *loop*. You can enter an endless loop (e.g. `for (;;) { code }` or `while (1) { code }` and take input and use conditionals (e.g. `if, else` or `switch` to determine what actions to take, and finally, `if (input == '0') break;` to exit the continual loop (you use `goto` to break out of *nested* loops). Your `code` above is simply that logic that takes input and makes decisions based thereon and takes the appropriate actions (hopefully). Drawing out a flow-chart of your inputs and actions can help. – David C. Rankin Sep 21 '16 at 09:08
1

Alex, continuing from your last comment, to display a menu that will allow you to add values to your array, delete values from your array and view the array (along with the max, min and average of the values), can do something similar to the following. Note: the command line isn't a windowed user interface, so your menu operations are more like a printed receipt of your transactions with it. (you can do nice text windows and stationary menus, but that generally requires an text library, such as ncurses which is well beyond the scope of your question.

As explained in the comment, your basic approach is simply to create a loop that repeats continually. It will display your menu and allow you to enter your selection from a list, e.g.:

 ======== Program Menu =========

  V)  View the Array.
  I)  Insert New Value.
  D)  Delete Existing Value.
  N)  Display Minimum Value.
  X)  Display Maximum Value.
  A)  Display Average of Values.
  S)  Display Sum of Values.

  Q)  Quit.

 Selection: 

After the user enters the selection, to make the comparison easier, the user's input in converted to lower-case. Also note, that the input is read as a string using fgets (a line-oriented input function) which makes taking user input much easier than having to worry about whether the '\n' remains in the input buffer (stdin) just waiting to cause problems for your next input. (you can use the scanf family of functions, but YOU are the one responsible for accounting for each character entered by the user (and emptying the input buffer).

Reading input with fgets will read up to and including the '\n', so their is no chance of the '\n' being left unread in stdin. Also note that fgets will read a string or characters, where you are only interested in the first. That is easily handled simply by referencing the first character in the buffer. (e.g. if you are reading user-input into a buffer called buf, you can simply use buf[0] to access the first character, or simply *buf for that matter)

After the user input is read, the first character is passed to a switch statement, where each case of the statement is compared against the first character. If the character matches a case, then the actions associated with that case are taken, ending with the break (you can read about fall-through processing if the break is omitted on your own)

As mentioned in the comment, if you simply need to break out of one loop, then break is all you need. However here, your switch statement is inside the loop. A single break will only get you out of the switch but not the outside for loop. To break out of nested loops, use the goto statement. (you could also add more variables and set some type of exit flag, but why? This is what the goto was meant to do. (there are some cases where a flag is equally good as well)

In each case within the switch, you are free to call whatever code is needed to handle that menu selection. You will note we simply call short helper functions from within the switch to print the array, insert values, remove values, etc. You can put all the code in the switch if you like, it just rapidly become unreadable.

Putting that altogether, you can do something like the following:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>

enum { MAXN = 64 };  /* constant - max numbers of vals & chars */

void showmenu ();
void prnarray (int *a, int n);
int addvalue (int *a, int n, int newval);
int delvalue (int *a, int n, int index);
int minvalue (int *a, int n);
int maxvalue (int *a, int n);
int sumvalues (int *a, int n);

int main (void) {

    int vals[MAXN] = { 21, 18, 32, 3, 9, 6, 16 }, /* the array */
        n = 7;

    for (;;) {  /* loop until user quits or cancels, e.g. ctrl+d */

        showmenu();                         /* show the menu */

        char buf[MAXN] = "";
        fgets (buf, MAXN, stdin);           /* read user input */
        /* convert to lower-case for comparison of all entries */
        switch (tolower (buf[0])) {         /* 1st char is entry */
            case 'v' :  prnarray(vals, n);
                        break;
            case 'i' :  printf ("\n enter the new value: ");
                        if (fgets (buf, MAXN, stdin) &&
                            isdigit (buf[0])) {
                            n = addvalue (vals, n, atoi (buf));
                        }
                        break;
            case 'd' :  printf ("\n enter the index to delete: ");
                        if (fgets (buf, MAXN, stdin) &&
                            isdigit (buf[0])) {
                            n = delvalue (vals, n, atoi (buf));
                        }
                        break;
            case 'n' :  printf ("\n Mininum of '%d' values is : %d\n",
                                n, minvalue (vals, n));
                        break;
            case 'x' :  printf ("\n Maxinum of '%d' values is : %d\n",
                                n, maxvalue (vals, n));
                        break;
            case 'a' :  printf ("\n Average of '%d' values is : %.2lf\n",
                                n, (double)sumvalues (vals, n)/n);
                        break;
            case 's' :  printf ("\n Sum of '%d' values is : %d\n",
                                n, sumvalues (vals, n));
                        break;
            case 'q' :  printf (" that's all folks...\n");
                        goto done; 
            default  :  if (!buf[0]) {  /* check for manual EOF */
                            putchar ('\n');  /* tidy up */
                            goto done;
                        }
                        fprintf (stderr, "error: invalid selection.\n");
        }
    }
    done:;  /* goto label - breaking 'for' and 'switch' */

    return 0;
}

void showmenu ()
{
    fprintf(stderr, "\n ======== Program Menu =========\n\n"
                    "  V)  View the Array.\n"
                    "  I)  Insert New Value.\n"
                    "  D)  Delete Existing Value.\n"
                    "  N)  Display Minimum Value.\n"
                    "  X)  Display Maximum Value.\n"
                    "  A)  Display Average of Values.\n"
                    "  S)  Display Sum of Values.\n"
                    "\n"
                    "  Q) Quit.\n"
                    "\n"
                    " Selection: ");
}

void prnarray (int *a, int n)
{
    int i;

    printf ("\n there are '%d' values in the array:\n\n", n);

    for (i = 0; i < n; i++)
        printf (" array[%2d] : %d\n", i, a[i]);
}

int addvalue (int *a, int n, int newval)
{
    if (n == MAXN) {
        fprintf (stderr, "error: all '%d' values filled.\n", n);
        return n;
    }
    a[n++] = newval;

    return n;
}

int delvalue (int *a, int n, int index)
{
    if (index < 0 || index > n - 1) {
        fprintf (stderr, "error: index out of range.\n");
        return n;
    }

    int i;

    for (i = index + 1; i < n; i++)
        a[i-1] = a[i];
    a[i] = 0;

    return --n;
}

int minvalue (int *a, int n)
{
    int i, min = INT_MAX;
    for (i = 0; i < n; i++)
        if (a[i] < min)
            min = a[i];

    return min;
}

int maxvalue (int *a, int n)
{
    int i, max = INT_MIN;
    for (i = 0; i < n; i++)
        if (a[i] > max)
            max = a[i];

    return max;
}

int sumvalues (int *a, int n)
{
    int i, sum = 0;
    for (i = 0; i < n; i++)
        sum += a[i];

    return sum;
}

(note: there are always additional validation checks you can add to test whether you have read all the input the user provided, etc.. But given the crux of your question I'll leave that learning to you)

Example Use/Output

$ ./bin/menusimple

 ======== Program Menu =========

  V)  View the Array.
  I)  Insert New Value.
  D)  Delete Existing Value.
  N)  Display Minimum Value.
  X)  Display Maximum Value.
  A)  Display Average of Values.
  S)  Display Sum of Values.

  Q)  Quit.

 Selection: v

 there are '7' values in the array:

 array[ 0] : 21
 array[ 1] : 18
 array[ 2] : 32
 array[ 3] : 3
 array[ 4] : 9
 array[ 5] : 6
 array[ 6] : 16

 ======== Program Menu =========

  V)  View the Array.
  I)  Insert New Value.
  D)  Delete Existing Value.
  N)  Display Minimum Value.
  X)  Display Maximum Value.
  A)  Display Average of Values.
  S)  Display Sum of Values.

  Q)  Quit.

 Selection: i

 enter the new value: 77

 ======== Program Menu =========

  V)  View the Array.
  I)  Insert New Value.
  D)  Delete Existing Value.
  N)  Display Minimum Value.
  X)  Display Maximum Value.
  A)  Display Average of Values.
  S)  Display Sum of Values.

  Q)  Quit.

 Selection: v

 there are '8' values in the array:

 array[ 0] : 21
 array[ 1] : 18
 array[ 2] : 32
 array[ 3] : 3
 array[ 4] : 9
 array[ 5] : 6
 array[ 6] : 16
 array[ 7] : 77

Look things over and let me know if you have any questions. Also, as you are just learning, make sure you are compiling your code with compiler warnings enabled and that you don't consider your code reliable until it compiles without warning. That means you should be compiling with at least the -Wall -Wextra flags set. If you are using gcc and the command line, then it would be:

gcc -Wall -Wextra -O2 -o simplemenu simplemenu.c

To compile the code in simplemenu.c into an executable named simplemenu with the -O2 optimizations applied. If you are really wanting to eliminate all warnings, add -pedantic as well. For codeblock or other IDE, look through the compiler menu options, they all provide a place to input all of the options you would like. Good luck with your code.


Procedural Approach Without Functions & Input With scanf

OK, now that we know how far we need to backup, let's look at rewriting the code in a bare minimum, top-down approach without using functions and taking user input with scanf (which will cause you more grief, especially taking mixed character and numeric input, but it can be done, if you account for the '\n' left in stdin)

First a note about taking input with scanf. When you ask for user input, like with the menu selection, and the user enters V and presses Enter, the input buffer stdin contains "V\n" (the '\n' as the result of pressing Enter). When you then use scanf to read a character (e.g. char sel; scanf ("%c", &sel);) the 'V' is taken from stdin and stored in sel leaving '\n' in stdin. If you then attempt to read another character (e.g. char nextch; scanf ("%c", &nextch);) it will appear that scanf has skipped reading nextch because it never allow you to enter a value. What has actually happened is scanf ("%c", &nextch); has read the '\n' that remained in stdin as your next character and is quite content with the value of 0xa (10 decimal) in nextch.

You must always account for the '\n' when using scanf. You have two options, 1) leave a space before the conversion specifier (e.g. scanf (" %c", &nextch); or 2) use the assignment suppression operator '*' (e.g. scanf ("%c%*c", &nextch);), the second %*c telling scanf to read and discard the following character without adding the conversion to the match count (which is the integer value returned by scanf). Which brings up the most important point of all, always check the return of scanf. (otherwise, you have no clue whether you have an actual value to work with or just garbage) I will leave the reading of man scanf to you for further details on the effect of the space before the conversion specifier, and the assignment suppression operator.

The return for scanf (the match count) is the number of successful conversions performed based on the number of conversion specifiers contained within the format string (e.g. scanf (" %c %d", &somechar, &someint); contains 2 conversion specifiers %c and %d, so the return for scanf after successful conversion of both would be 2. If a matching or conversion failure occurs, the return will be less than 2 and if an error condition is encountered reading from the stream (stdin in this case) EOF is returned (generally a value of -1) All of this, and more, is why scanf is NOT the preferred method for taking user input in C. (that being said, it is what most tutorials, and most teachers, make the poor choice to expose new C programmers to without an understanding of the pitfalls)

With that out of the way, if you work through the example below, you will see that I have simply moved the code from the functions to within the if ... else if ... else framework. (look at the one-to-one relationship from where I call functions from the switch in the first example and the code below) This should also show why breaking the code up into logical functions, improves readability and improves code re-use. Compare the use of the switch statement with the if ... else if ... else daisy chain. Both are fine, but to me, the switch is more easily readable at a glance.

You should make sure you understand both versions as they are both basic entry level approaches to using C. Take your time going through each and if you have questions that you cannot answer by consulting one of the references provided in the tag-wiki link, just ask.

#include <stdio.h>
#include <stdlib.h> /* for atoi */
#include <limits.h> /* for INT_MIN/INT_MAX */

enum { MAXN = 64 };  /* constant - max numbers of vals & chars */

int main (void) {

    int vals[MAXN] = { 21, 18, 32, 3, 9, 6, 16 }, /* the array */
        n = 7;

    for (;;) {

        char c;

        /* show the menu */
        fprintf(stderr, "\n ======== Program Menu =========\n\n"
                        "  V)  View the Array.\n"
                        "  I)  Insert New Value.\n"
                        "  D)  Delete Existing Value.\n"
                        "  N)  Display Minimum Value.\n"
                        "  X)  Display Maximum Value.\n"
                        "  S)  Display Sum of Values.\n"
                        "  A)  Display Average of Values.\n"
                        "\n"
                        "  Q) Quit.\n"
                        "\n"
                        " Selection: ");

        /* read selection (inside of if is OK), check EOF or quit */
        if (scanf (" %c", &c) == EOF || c == 'q' || c == 'Q') {
            printf ("\n that's all folks...\n");
            break;
        }

        if (c == 'v' || c == 'V') {         /* view array code */
            printf ("\n there are '%d' values in the array:\n\n", n);
            int i;
            for (i = 0; i < n; i++)
                printf (" array[%2d] : %d\n", i, vals[i]);
        }
        else if (c == 'i' || c == 'I') {    /* insert value code */
            if (n == MAXN) {
                fprintf (stderr, "error: all '%d' values filled.\n", n);
                continue;
            }
            int newval = 0;
            printf ("\n enter the new value: ");
            if (scanf (" %d", &newval) == 1) {
                vals[n] = newval;
                n++;
            }
            else
                fprintf (stderr, "error: invalid input.\n");
        }
        else if (c == 'd' || c == 'D') {    /* delete value code */
            int i, index = 0;
            printf ("\n enter the index to delete: ");
            if (scanf (" %d", &index) != 1) {
                fprintf (stderr, "error: invalid input.\n");
                continue;
            }
            if (index < 0 || index > n - 1) {
                fprintf (stderr, "error: index out of range.\n");
                continue;
            }
            for (i = index + 1; i < n; i++)
                vals[i-1] = vals[i];
            vals[i] = 0;
            n--;
        }
        else if (c == 'n' || c == 'N') {    /* display minimum code */
            int i, min = INT_MAX;
            for (i = 0; i < n; i++)
                if (vals[i] < min)
                    min = vals[i];
            printf ("\n Mininum of '%d' values is : %d\n",
                    n, min);        
        }
        else if (c == 'x' || c == 'X') {    /* display maximum code */
            int i, max = INT_MIN;
            for (i = 0; i < n; i++)
                if (vals[i] > max)
                    max = vals[i];
            printf ("\n Maxinum of '%d' values is : %d\n",
                    n, max);        
        }
        else if (c == 's' || c == 'S') {    /* compute sum code */
            int i, sum = 0;
            for (i = 0; i < n; i++)
                sum += vals[i];
            printf ("\n Sum of '%d' values is : %d\n",
                                n, sum);
        }
        else if (c == 'a' || c == 'A') {    /* compute avg code */
            int i, sum = 0;
            double avg = 0.0;
            for (i = 0; i < n; i++)
                sum += vals[i];
            avg = (double)sum/n;
            printf ("\n Average of '%d' values is : %.2lf\n",
                    n, avg);
        }
        else    /* if not matched, then invalid selection */
            fprintf (stderr, "error: invalid selection.\n");

    }

    return 0;
}

(the operation and output from both program versions will be identical)

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Hi @David C. Rankin thanks detailed code but its a bit advance for me as we haven't gone through pointers yet. I written the base of the code but i have trouble to define my function at the bottom. Can you take a look, I've edited my code at the top – xxFlashxx Sep 21 '16 at 14:44
  • You redefine `char input;` twice. Just define it within the `do` loop as it isn't needed outside the loop. You place your function prototypes (e.g. `int enterMeasurements();` at the TOP of the code so when you use `enterMeasurements()` within the code, it is defined (even though you put the actual code for the function at the bottom - if you define the function above `main`, then there is no need for a prototype). If you are NOT using functions (e.g. you are putting all your code in `main`) -- you do not need prototypes or functions at all. Give it another go. – David C. Rankin Sep 21 '16 at 18:35