0

Update: It could be complied in OS X but could not in Linux and Windows with MinGW.


Given the rainfall in mm for each month, display a horizontal, text-based histogram showing the rainfall per month.

Here's my code

    // This variation prints out the actual names of the months instead of numbers.

    #include <stdio.h>
    #include <string.h>

    int main(int argc, char *argv[])
    {
        const int WIDTH = 70;
        const int NUM_MONTHS = 12;
        int max = 0;
        int rainfall[NUM_MONTHS];
        char months[NUM_MONTHS][11] = { "January", "Febuary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
        int i;

        for(i = 0; i < NUM_MONTHS; i++)
        {
            printf("Enter %s rainfall: ", months[i]);
            scanf("%d", &rainfall[i]);
            if(rainfall[i] > max)
            {
                max = rainfall[i];
            }
        }

        for(i = 0; i < NUM_MONTHS; i++)
        {
            printf("%s", months[i]);
            int len = strlen(months[i]);
            int j;
            for(j = len; j < 10; j++)
            {
                printf(" ");
            }
            int num_stars = WIDTH * (rainfall[i]/(float)max);
            for(j = 0; j < num_stars; j++)
            {
                printf("*");
            }
            printf("\n");
        }

    }

When I try to compile it with gcc, it shows error and warning.

.\rainfall-graph-names.c: In function 'main':
.\rainfall-graph-names.c:12:4: error: variable-sized object may not be initialized
    char months[NUM_MONTHS][11] = { "January", "Febuary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };

.\rainfall-graph-names.c:12:4: warning: excess elements in array initializer [enabled by default]
.\rainfall-graph-names.c:12:4: warning: (near initialization for 'months') [enabled by default]

I don't know why it doesn't work and I don't know why. Is there anyone could help? Thanks

Fingalzzz
  • 109
  • 14
  • It says you didn't initialize month before using it, like you did with everything else. – Drazisil Oct 13 '15 at 04:23
  • I compiled the code on OS X (using Xcode 7) and it ran fine. – waterjuice Oct 13 '15 at 04:29
  • @waterjuice: this question is tagged C, not C++, and this is one of those questions where it does make a difference. – rici Oct 13 '15 at 04:37
  • @rici good point, but in this case I actually was compiling it as C and not C++. Although to be honest I don't use Xcode and OS X compiling a great deal, so I'm not familiar with the intricacies of the compiler. I do all my work in Visual Studio on Windows. I just used Xcode for this because I browse the web on a Mac :-) – waterjuice Oct 13 '15 at 04:40
  • @waterjuice: That's curious: I compiled it on OS X 10.11 El Capitan (using gcc and clang from XCode 7.0.1 — for example, using `clang -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror osx-months.c -o osx-month`) and it failed to compile with `error: variable-sized object may not be initialized` and two complaints about `argc` and `argv` being unused too (`int main(void)` is sensible here). _[…time passes…]_ Oh; it compiles OK if you use `-std=gnu11` (and not the other compilation options). – Jonathan Leffler Oct 13 '15 at 06:33

2 Answers2

3

The declaration

char months[NUM_MONTHS][11] = {...};

makes months a variable length array even though NUM_MONTHS is declared as

const int NUM_MONTHS = 12;

The C99 standard does not allow initialization of variable length arrays using the syntax:

char months[NUM_MONTHS][11] = {...};

From the standard (emphasis mine):

6.7.8 Initialization

3 The type of the entity to be initialized shall be an array of unknown size or an object type that is not a variable length array type.

You can use a pre-processor macro.

#define NUM_MONTHS 12

and remove the line

const int NUM_MONTHS = 12;

The effectively makes months:

char months[12][11] = {...};

Since months is not a variable length array any more, it can be initialized using the syntax you have in your posted code.

Update

It's better still to use (Thanks @JonathanLeffler):

enum {NUM_MONTHS = 12};

When you use an enum, NUM_MONTHS becomes part of the debugger's symbol table and you can see its value in the debugger. You cannot do that if you use a pre-processor macro.

See this answer to another SO question for further details.

Community
  • 1
  • 1
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 1
    Why do you suggest this? To the reader who doesn't understand the nuance, this is just magic incantations. Explain please. – David Heffernan Oct 13 '15 at 04:30
  • 1
    Thanks, it helps. But why I need a macro here? – Fingalzzz Oct 13 '15 at 04:31
  • 1
    @Finger_5792 `const int` means an int that may not be modified, however this does not count as a *constant expression* for purposes of creating an array. For example you could have written `const int i = func_taht_reads_keyboard(); char months[i]` – M.M Oct 13 '15 at 05:22
  • Why not `enum { NUM_MONTHS = 12 };` which gets the symbol into the debugger table? (See also [`static const` vs `#define` in C](https://stackoverflow.com/questions/1674032/)). – Jonathan Leffler Oct 13 '15 at 06:35
0

The NUM_MONTHS is a variable. For array size you must define it as a integer constant.


See http://randu.org/tutorials/c/arrays.php for examples of declaration. Hope it helps.

atamit81
  • 207
  • 1
  • 2
  • 7