0

I still pretty new to programming and my only prior experience before C was Javascript. I'm doing the CS50 Introduction to Computer Science and in one of the lectures there's an example code that computes the average of some user input. It looks like this:

#include <cs50.h>
#include <stdio.h>

const int TOTAL = 3;

float average(int length, int array[])
int main(void)
{
    int scores[TOTAL];
    for (int i = 0; i < TOTAL; i++)
    {
      scores[i] = get_int("Score: ");
    }

    printf("Average: %f\n", average(TOTAL, scores);
}

float average(int length, int array[])
{
    int sum = 0;
    for (int i = 0; i < length; i++)
    {
        sum += array[i];
    }
    return sum / (float) length;
}

The feature that I'm trying to add is to dynamically store the size of the array depending of the user input, instead of having one variable (TOTAL in this case). For example: I need to have a loop that is always asking the user for a score (instead of just 3 times like the code above), and when the user types zero(0), the loops breaks and the size of the array is defined by how many times the user has typed some score.

This is what I've done:

int main(void)
{
    int score;
    // start count for size of array
    int count = - 1;

    do
    {
        score = get_int("Score: ");
        // add one to the count for each score
        count++;
    }
    while (score != 0);
    
    // now the size of the array is defined by how many times the user has typed.
    int scores[count];

    for (int i = 0; i < count; i++)
    {
        // how do I add each score to the array???
    }
}

My problem is how to add each score that the user types to the array. In advance thanks!!!

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Rafael Madriz
  • 51
  • 1
  • 6
  • regarding: `float average(int length, int array[]) int main(void)` This is missing a semicolon `;` after the first statement so does not compile – user3629249 Feb 01 '21 at 06:09
  • regarding: `printf("Average: %f\n", average(TOTAL, scores);` This is missing a closing paren before the semicolor `;` so does not compile! – user3629249 Feb 01 '21 at 06:20
  • regarding: `return sum / (float) length;` This causes the compiler to output the warning message: *untitled1.c:30:16: warning: conversion from ‘int’ to ‘float’ may change value [-Wconversion]* When compiling, always enable the warnings, then fix those warnings. ( for `gcc`, at a minimum use the options: `-Wall -Wextra -Wconversion -pedantic -std=gnu11` ) Note: other compilers use different options to produce the same results – user3629249 Feb 01 '21 at 06:25
  • Note that to just calculate the average, you only need to keep the sum of the values entered and the number of values entered; you don't need the array with the saved values. You can then simply read numbers until EOF (or an input error, such as a letter or punctuation character) and then print the average by computing `(double)sum / count`. – Jonathan Leffler Apr 09 '21 at 16:13

3 Answers3

2

You need a "dynamic data structure" that can expand as required. These are two ways:

  1. Allocate an array of initial size with malloc and realloc when there is not enough room.

  2. Use a linked list

(there are more ways, but these are quite common for this problem)

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
1

You need to have data structure which will keep track of the size and stores the data.

Here you have a simple implementation:

typedef struct
{
    size_t size;
    int result[];
}SCORES_t;

SCORES_t *addScore(SCORES_t *scores, int score)
{
    size_t newsize = scores ? scores -> size + 1 : 1;
    scores = realloc(scores, newsize * sizeof(scores -> result[0]) + sizeof(*scores));
    if(scores)
    {
        scores -> size = newsize;
        scores -> result[scores -> size - 1] = score;
    }
    return scores;
}

double getAverage(const SCORES_t *scores)
{
    double average = 0;
    if(scores)
    {
        for(size_t index = 0; index < scores -> size; average += scores -> result[index], index++);
        average /= scores -> size;
    }
    return average;
}

int main(void)
{
    int x;
    SCORES_t *scores = NULL;

    while(scanf("%d", &x) == 1 && x >= 0)
    {
        SCORES_t *temp = addScore(scores, x);
        if(temp)
        {
            scores = temp;
        }
        else
        {
            printf("Memery allocation error\n");
            free(scores);
        }
    }
    if(scores) printf("Number of results: %zu Average %f\n", scores -> size, getAverage(scores));
    free(scores);
}

https://godbolt.org/z/5oPesn

0___________
  • 60,014
  • 4
  • 34
  • 74
  • do NOT assign the returned value from `realloc()` directly to the target pointer. Rather, check it for (!=NULL). If NULL, then handle error, otherwise, update the target pointer – user3629249 Feb 01 '21 at 07:23
  • regarding: `scores = realloc(scores, newsize * sizeof(scores -> result[0]) + sizeof(*scores));` this will add another instance of the struct SCORES_t for each time it is called. This is an error – user3629249 Feb 01 '21 at 07:25
  • @user3629249 both of your comments make no sense at all and show that you have no clue what this 0 lines program do. 1. Do you really think that I do not know how to use `realloc`? read the code and tell me **where** you see the potential leak? The check is done on the "caller" level. 2. It issigns **local variable** `scores` with pointer to newly allocated area. This pointer **is returned** to the caller. The caller has both - new and old. Then it decides if new is not NULL. I think you should put some effort in reading the code before commenting. – 0___________ Feb 01 '21 at 10:49
0

regarding:

int main(void)
{
    int score;
    // start count for size of array
    int count = - 1;

    do
    {
        score = get_int("Score: ");
        // add one to the count for each score
        count++;
    }
    while (score != 0);
    
    // now the size of the array is defined by how many times the user has typed.
    int scores[count];

    for (int i = 0; i < count; i++)
    {
        // how do I add each score to the array???
    }
}

this does not compile and contains several logic errors

it is missing the statements: #include <cs50.h> and #include <stdio.h>

regarding:

    int score;
    // start count for size of array
    int count = - 1;

    do
    {
        score = get_int("Score: ");
        // add one to the count for each score
        count++;
    }
    while (score != 0);

This only defines a single variable: score and each time through the loop that single variable is overlayed. Also, the first time through the loop, the counter: count will be incremented to 0, not 1

on each following time through the loop, the variable score will be overlayed (I.E. all prior values entered by the user will be lost)

suggest using dynamic memory. Note: to use dynamic memory, will need the header file: stdlib.h for the prototypes: malloc() and free(). Suggest:

#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
    
int main( void )
{
    // pointer to array of scores
    int * score = NULL;

    // start count for size of array
    int count = 0;

    while( 1 )
    {
        int score = get_int("Score: ");

        if( score != 0 )
        {  // then user has entered another score to put into array
            count++;
            int * temp = realloc( scores, count * sizeof( int ) )
            if( ! temp )
            { // realloc failed
                // output error info to `stderr`
                // note: `perror()` from `stdio.h`
                perror( "realloc failed" );

                // cleanup
                free( scores );

                // `exit()` and `EXIT_FAILURE` from `stdlib.h`
                exit( EXIT_FAILURE );
            }

            // implied else, 'realloc()' successful, so update the target pointer
            scores = temp;

            // insert the new score into the array
            scores[ count ] = score;
        }

        else
        { // user entered 0 so exit the loop
            break;
        }
    }

note: before exiting the program, pass scores to free() so no memory leak.

user3629249
  • 16,402
  • 1
  • 16
  • 17
  • Thanks, this solution makes more sense for a beginner. Still there's a few things that I don't know or seen on the CS50 course about C, like pointers and the use of malloc, realloc, etc. Regarding the "missing arguments" I didn't put it on the comment because it wasn't relevant but I had those on my code. And count being equal to ` - 1 ` was because when I typed 0 to exit the loop, that 0 will still add to the count, then instead of count 3 for 3 scores for example, it would be 4 for 3 scores. Then the average would be wrong because of dividing for the wrong number. My logic was wrong anyway – Rafael Madriz Feb 02 '21 at 13:04