Back to C Programming
2025-12-297 min read

enumeration (C Programming)

Learn enumeration (C Programming) step by step with clear examples and exercises.

Why This Matters

Enumerations are a powerful tool in C programming that allow developers to define custom data types with a set of named values. They make code more readable, maintainable, and less prone to errors when dealing with integer constants. By using enumerations, you can create self-documenting code that is easier for other developers to understand.

In this lesson, we will explore the syntax and usage of enumerations in C programming, providing practical examples and tips to help you master this essential concept.

Prerequisites

Before diving into enumerations, it's essential that you have a good understanding of the following topics:

  1. Basics of C programming, including variables, data types, and operators
  2. Control structures like loops and conditional statements
  3. Basic input/output operations using printf and scanf functions
  4. Understanding pointers and memory management in C
  5. Function definitions and call-by-value vs call-by-reference parameters
  6. Data Structures: Arrays, Strings, and Structures (for a better understanding of how enumerations can be used with other data structures)

Core Concept

What are Enumerations?

In C programming, an enumerated type is a user-defined data type consisting of a set of named values, also known as enumerators. These enumerators are represented as integers under the hood. The main advantage of using enumerations is that they make your code more readable by assigning meaningful names to integer constants.

Syntax

Declaring an enumerated type in C involves using the enum keyword followed by a name for the new data type and a list of enumerators enclosed in curly braces {}. Here's an example:

enum Color { RED, GREEN, BLUE };

In this example, we define a new data type called Color, which consists of three enumerators (RED, GREEN, and BLUE). By default, the first enumerator has a value of 0, and each subsequent enumerator is incremented by 1. However, you can manually assign values to your enumerators if needed.

enum Color { RED = 1, GREEN = 2, BLUE };

In this case, we've explicitly set the value of RED to 1 and GREEN to 2. The enumerator BLUE will then be assigned the next available integer (3).

Enumeration Variables

To declare a variable of an enumerated type, simply use the variable name followed by the data type in parentheses:

enum Color myColor; // Declares a variable named 'myColor' of type 'Color'

You can also initialize the variable with a specific enumerator value at the time of declaration:

enum Color myColor = RED; // Initializes 'myColor' to the 'RED' enumerator

Enumeration Type Scope

By default, an enumerated type is only visible within the scope in which it was declared. This means that if you declare an enumerated type inside a function, it can only be used within that function. To make the enumerated type visible throughout your entire program, you should declare it at the global level:

// Declare 'Color' as a global enumerated type
enum Color { RED, GREEN, BLUE };

void myFunction() {
// Use 'Color' here because it was declared globally
enum Color myColor = GREEN;
}

Enumeration Arithmetic Operations

Enumerators can be used in arithmetic expressions, but keep in mind that their underlying integer values may not always be what you expect due to custom enumerator assignments or enumerated types being declared in different scopes. It's essential to treat enumerations as distinct data types rather than just integers.

Enumeration Casting

When working with enumerations, it's important to cast one or both operands in arithmetic expressions if necessary:

// Correct usage (casting an enumerator to an integer)
int myInt = (int) RED;

// Incorrect usage (assuming RED is an integer)
int myInt = RED + 5; // This will not compile

// Correct usage (casting an integer to an enumerator)
enum Color myColor2 = (enum Color) 10;

Worked Example

Let's create a simple program that uses enumerations to represent the four suit types in a deck of cards (CLUBS, DIAMONDS, HEARTS, SPADES). Prompt the user for a card number between 1 and 52, and print out the corresponding card and suit:

#include <stdio.h>

// Declare 'Suit' as a global enumerated type
enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES };

int main() {
// Define constants for the face cards (J, Q, K, A)
enum Suit JACK_OF_SPADES = SPADES + 10;
enum Suit QUEEN_OF_DIAMONDS = DIAMONDS + 12;
enum Suit KING_OF_HEARTS = HEARTS + 13;
enum Suit ACE_OF_CLUBS = CLUBS + 14;

// Define an array to store the face values for cards 2-10
int faceValues[9] = { 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// Prompt the user for a card number between 1 and 52
enum Suit suit;
int faceValue;
printf("Enter a number between 1 and 52 representing the card:\n");
scanf("%d", &faceValue);

// Calculate the suit based on the card number's modulus
suit = (enum Suit) ((faceValue - 1) % 13 + CLUBS);

// Determine the face value based on the card number's quotient
if (faceValue <= 14) {
faceValue = faceValue;
} else if (faceValue <= 26) {
faceValue = faceValues[faceValue - 13];
} else if (faceValue == JACK_OF_SPADES || faceValue == QUEEN_OF_DIAMONDS || faceValue == KING_OF_HEARTS || faceValue == ACE_OF_CLUBS) {
faceValue = faceValue;
} else {
printf("Invalid card number. Please enter a value between 1 and 52.\n");
return -1;
}

// Print the card and suit
printf("Card: %d of %s\n", faceValue, getSuitName(suit));
return 0;
}

// Helper function to convert a Suit enumerator into its corresponding string name
const char* getSuitName(enum Suit suit) {
switch (suit) {
case CLUBS:
return "Clubs";
case DIAMONDS:
return "Diamonds";
case HEARTS:
return "Hearts";
case SPADES:
return "Spades";
default:
return "Invalid suit.";
}
}

Common Mistakes

  1. Forgetting to include the enumerated type in switch statements: When using enumerations in switch statements, it's essential that you include the enumerated type before each case label:
// Correct usage
switch (myEnum) {
case RED:
// Code for 'RED'
break;
}

// Incorrect usage (will not compile)
switch (myEnum) {
case 1: // This assumes RED has a value of 1, which may not be the case
// Code for 'RED'
break;
}
  1. Assuming enumerator values are always in sequential order: While enumerators are usually assigned sequential integer values by default, this is not always the case. If you manually assign values to your enumerators or include them in other scopes, their values may not be in a predictable order:
// Declare 'Color' with custom enumerator values
enum Color { RED = 10, GREEN = 20, BLUE };

// Declare 'Size' with default enumerator values
enum Size { SMALL, MEDIUM, LARGE };

int main() {
// Print the enumerator values
printf("RED: %d\n", RED);
printf("GREEN: %d\n", GREEN);
printf("BLUE: %d\n", BLUE);
printf("SMALL: %d\n", SMALL);
printf("MEDIUM: %d\n", MEDIUM);
printf("LARGE: %d\n", LARGE);

return 0;
}

Output:

RED: 10
GREEN: 20
BLUE: 21
SMALL: 0
MEDIUM: 1
LARGE: 2
  1. Mixing enumerated types and integers: When working with enumerations, it's important to treat them as distinct data types rather than just integers. This means that you should avoid mixing enumerators and integer constants in the same expression without properly casting one or both of them:
// Correct usage (casting an enumerator to an integer)
int myInt = (int) RED;

// Incorrect usage (assuming RED is an integer)
int myInt = RED + 5; // This will not compile

Practice Questions

  1. Write a program that uses enumerations to represent the four suit types in a deck of cards (CLUBS, DIAMONDS, HEARTS, SPADES). Prompt the user for a card number between 1 and 52, and print out the corresponding card and suit. Handle invalid input by repeatedly prompting the user until they enter a valid card number.
  1. Modify the example program from the "Worked Example" section to allow the user to specify the number of face cards (J, Q, K, A) in the deck. The user should be able to input the number of each face card separately.
  1. Create an enumerated type called Dice with six enumerators representing the six possible outcomes when rolling a six-sided die (1 through 6). Write a program that simulates rolling a die multiple times and calculates the average roll over a specified number of trials.

FAQ

Can I use enumerators in arithmetic expressions?

Yes, you can use enumerators in arithmetic expressions, but keep in mind that their underlying integer values may not always be what you expect due to custom enumerator assignments or enumerated types being declared in different scopes. It's essential to treat enumerations as distinct data types rather than just integers.

How can I check if a variable is of an enumerated type?

To check if a variable is of an enumerated type, you can use the typeof operator in C99 and later versions:

enum Color myColor = RED;

if (sizeof(myColor) == sizeof(int)) {
printf("'myColor' is of enumerated type 'Color'.\n");
} else {
printf("'myColor' is not of enumerated type 'Color'.\n");
}

Can I use enumerations with structures?

Yes, you can use enumerations as members of structures. This allows you to create complex data types that are easier to understand and manage. For example:

// Define an enumerated type for the four suit types in a deck of cards
enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES };

// Define a structure for a card with fields for face value and suit
struct Card {
int faceValue;
enum Suit suit;
};

// Create an instance of the 'Card' structure
struct Card myCard = { 7, DIAMONDS };