C Data Types

In C programming, a data type determines what kind of value an object can store, which operations are valid for that value, and how the compiler interprets its representation. C includes integer, floating-point, character, Boolean, enumeration, structure, union, array, pointer, function, and void types.

The exact storage size and range of several C types depend on the compiler and target platform. Use sizeof to inspect sizes on the current implementation, <limits.h> for integer limits, and <float.h> for floating-point characteristics.


Categories of Data Types in C

C data types are commonly organized into the following categories:

  • Basic types: Integer types, floating-point types, char, _Bool, and void.
  • Derived types: Arrays, pointers, and function types constructed from other types.
  • Enumeration types: Sets of named integer constants declared with enum.
  • Aggregate types: Structures and unions that combine multiple members.
  • Type aliases: Alternative type names introduced with typedef.

1 Primary C Data Types

The basic C types represent integers, characters, Boolean values, and real numbers. Type modifiers such as signed, unsigned, short, and long create additional integer variants.

Integer Types and Their Format Specifiers

Integer types store whole numbers. C guarantees minimum relative widths rather than one universal byte size: sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long). A byte is always the size of char, but it is not required to contain exactly eight bits.

TypeCommon SizeMinimum Required Rangeprintf Specifier
short int2 bytes-32,767 to 32,767%hd
unsigned short int2 bytes0 to 65,535%hu
int4 bytes-32,767 to 32,767%d or %i
unsigned int4 bytes0 to 65,535%u
long int4 or 8 bytes-2,147,483,647 to 2,147,483,647%ld
unsigned long int4 or 8 bytes0 to 4,294,967,295%lu
long long intUsually 8 bytes-9,223,372,036,854,775,807 to 9,223,372,036,854,775,807%lld
unsigned long long intUsually 8 bytes0 to 18,446,744,073,709,551,615%llu

Note: The sizes in the table are common values, not portable guarantees. The standard permits a signed integer type to have a wider range than the listed minimum.

Example:

</>
Copy
#include <stdio.h>

int main() {
    int a = 100;
    unsigned int b = 200;
    short c = -50;
    unsigned short d = 50;
    long e = 1234567890;
    unsigned long f = 1234567890;

    printf("int a = %d\n", a);
    printf("unsigned int b = %u\n", b);
    printf("short c = %hd\n", c);
    printf("unsigned short d = %hu\n", d);
    printf("long e = %ld\n", e);
    printf("unsigned long f = %lu\n", f);

    return 0;
}

Integer Example Output

int a = 100
unsigned int b = 200
short c = -50
unsigned short d = 50
long e = 1234567890
unsigned long f = 1234567890

Floating-Point Types in C

Floating-point types store values with fractional components and values across a large range of magnitudes. Their representations and exact precision are implementation-defined, although many systems use IEEE 754 formats.

TypeCommon SizeTypical Decimal Precisionprintf Specifierscanf Specifier
float4 bytesAbout 6 significant digits%f%f
double8 bytesAbout 15 significant digits%f%lf
long double8, 12, or 16 bytesImplementation-dependent%Lf%Lf

For printf, a float argument is promoted to double, so %f prints both float and double. The distinction matters with scanf: use %f for a float * and %lf for a double *.

Example:

</>
Copy
#include <stdio.h>

int main() {
    float f = 3.14159;
    double d = 3.14159265358979;
    long double ld = 3.14159265358979323846;

    printf("float f = %.5f\n", f);
    printf("double d = %.14lf\n", d);
    printf("long double ld = %.20Lf\n", ld);

    return 0;
}

Floating-Point Example Output

float f = 3.14159
double d = 3.14159265358979
long double ld = 3.14159265358979323846

The last digits printed for a floating-point value can vary because many decimal fractions cannot be represented exactly in binary and because long double precision differs between implementations.

The char Data Type

The char type stores one character-sized integer value and always occupies one byte. Character constants such as 'A' have integer codes in the execution character set. ASCII-based systems use 65 for 'A', but C does not require the execution character set to be ASCII.

C provides three distinct character types: char, signed char, and unsigned char. Plain char is either signed or unsigned depending on the implementation. Use unsigned char when processing raw bytes and char when storing text.

TypeSizeMinimum RangeTypical Use
char1 byteSame range as either signed char or unsigned charCharacters and strings
signed char1 byte-127 to 127Small signed integers
unsigned char1 byte0 to at least 255Raw bytes and small nonnegative integers

Example:

</>
Copy
#include <stdio.h>

int main() {
    char letter = 'A';
    printf("Character: %c\n", letter);
    printf("ASCII Value: %d\n", letter);

    return 0;
}

Character Example Output on an ASCII System

Character: A
ASCII Value: 65

The _Bool and bool Types

_Bool is C’s Boolean type. Assigning zero stores false, while assigning any nonzero scalar value stores true. In C99 through C17, including <stdbool.h> provides the convenient names bool, true, and false.

</>
Copy
#include <stdbool.h>
#include <stdio.h>

int main(void) {
    bool is_ready = true;
    printf("Ready: %d\n", is_ready);
    return 0;
}

Boolean Example Output

Ready: 1

The void Type

The incomplete type void represents the absence of a value. It is used for a function that returns no value, a parameter list that explicitly accepts no arguments, and a generic object pointer written as void *. Standard C does not permit an ordinary variable whose type is void.

Example:

</>
Copy
#include <stdio.h>

void greet() {
    printf("Hello, World!\n");
}

int main() {
    greet();
    return 0;
}

Void Function Example Output

Hello, World!

2 Derived Data Types in C

Derived types are constructed from other C types. The principal derived types are arrays, pointers, and function types.

  • Arrays: Fixed-size sequences of elements that all have the same type. Array elements are stored contiguously and accessed by a zero-based index.
  • Pointers: Objects that store addresses. A pointer’s declared type identifies the type of object or function to which it may point.
  • Function types: Types determined by a function’s return type and parameter types. A function itself is not an object, but a pointer can point to it.

C Array Data Type Example

This example declares an array of five integers and accesses each element with an index.

</>
Copy
#include <stdio.h>

int main() {
    int numbers[5] = {10, 20, 30, 40, 50};

    // Accessing elements using a loop
    for (int i = 0; i < 5; i++) {
        printf("%d ", numbers[i]);
    }

    return 0;
}

Array Example Output

10 20 30 40 50

C Pointer Data Type Example

A pointer is initialized with the address-of operator &. Dereferencing the pointer with * accesses the object stored at that address.

</>
Copy
#include <stdio.h>

int main() {
    int num = 10;
    int *ptr = # // Pointer stores the address of num

    printf("Value of num: %d\n", num);
    printf("Value using pointer: %d\n", *ptr);

    return 0;
}

Correction: In a compilable pointer declaration, the initialization line must be int *ptr = &num;. The corrected complete example is shown below.

</>
Copy
#include <stdio.h>

int main(void) {
    int num = 10;
    int *ptr = &num;

    printf("Value of num: %d\n", num);
    printf("Value using pointer: %d\n", *ptr);

    return 0;
}

Pointer Example Output

Value of num: 10
Value using pointer: 10

C Function Type Example

In the declaration int add(int, int), the function type describes a function that accepts two int arguments and returns an int. A compatible function pointer can store its address.

</>
Copy
#include <stdio.h>

int add(int left, int right) {
    return left + right;
}

int main(void) {
    int (*operation)(int, int) = add;
    printf("Result: %d\n", operation(7, 5));
    return 0;
}

Function Pointer Example Output

Result: 12

3 User-Defined and Programmer-Named C Types

C programs can define structures, unions, and enumerations and can assign alternative names to types with typedef. Strictly speaking, typedef creates an alias rather than a new, distinct type.

  • typedef: Introduces an alternative name for an existing type.
  • enum: Declares an enumeration type and a set of named integer constants.
  • struct: Groups members, potentially of different types, in one object.
  • union: Overlays all members in the same storage so that only one member value is normally active at a time.

Creating a C Type Alias with typedef

The typedef keyword can shorten a declaration or provide a domain-specific name for an existing type.

Example: Creating a new name for unsigned int

</>
Copy
#include <stdio.h>

typedef unsigned int uint; // Defining an alias for unsigned int

int main() {
    uint age = 25; // Now we can use uint instead of unsigned int
    printf("Age: %u\n", age);
    return 0;
}

typedef Example Output

Age: 25

Defining Named Constants with a C enum

An enumeration declares named integer constants. Unless values are assigned explicitly, the first enumerator has the value zero and each following enumerator increases by one.

Example: Defining an enumeration for days of the week

</>
Copy
#include <stdio.h>

enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY };

int main() {
    enum Day today = WEDNESDAY;
    
    printf("Today is day number %d of the week.\n", today);
    return 0;
}

enum Example Output

Today is day number 3 of the week.

Grouping Related Data with a C struct

A structure places its members in one object. Each member has separate storage, although the compiler may insert padding between members to satisfy alignment requirements.

Example: Defining a structure for a student

</>
Copy
#include <stdio.h>

struct Student {
    char name[50];
    int age;
    float marks;
};

int main() {
    struct Student s1 = {"Alice", 20, 88.5};

    printf("Name: %s\n", s1.name);
    printf("Age: %d\n", s1.age);
    printf("Marks: %.2f\n", s1.marks);

    return 0;
}

struct Example Output

Name: Alice
Age: 20
Marks: 88.50

Sharing Storage with a C union

A union provides storage shared by all its members. Its size is sufficient for its largest member, plus any alignment requirements. Writing one member normally makes that member the active value, so code should track which member currently contains meaningful data.

Example: Defining a union

</>
Copy
#include <stdio.h>

union Data {
    int i;
    float f;
    char str[20];
};

int main() {
    union Data data;

    data.i = 10;
    printf("Integer: %d\n", data.i);

    data.f = 20.5;
    printf("Float: %.2f\n", data.f);

    return 0;
}

union Example Output

Integer: 10
Float: 20.50

The program prints data.i before assigning data.f. After the floating-point assignment, the stored integer value should no longer be treated as the current union value.

Checking C Data Type Sizes with sizeof

The sizeof operator reports the size of a type or object in bytes of type size_t. Print a size_t value with %zu. Results vary by compiler, architecture, application binary interface, and compilation mode.

</>
Copy
#include <stdio.h>

int main(void) {
    printf("char: %zu byte(s)\n", sizeof(char));
    printf("short: %zu byte(s)\n", sizeof(short));
    printf("int: %zu byte(s)\n", sizeof(int));
    printf("long: %zu byte(s)\n", sizeof(long));
    printf("long long: %zu byte(s)\n", sizeof(long long));
    printf("float: %zu byte(s)\n", sizeof(float));
    printf("double: %zu byte(s)\n", sizeof(double));
    printf("long double: %zu byte(s)\n", sizeof(long double));
    printf("void pointer: %zu byte(s)\n", sizeof(void *));
    return 0;
}

Do not use sizeof(void) in portable C because void is incomplete and has no defined object size. Some compilers accept it as a nonstandard extension.

Fixed-Width Integer Types for Portable C Programs

When a program requires an integer with an exact width, include <stdint.h> and use a type such as int8_t, uint16_t, int32_t, or uint64_t. An exact-width type is defined only when the implementation supports an integer type with that width and no padding bits.

Use the formatting macros from <inttypes.h> instead of assuming that a fixed-width type corresponds to int, long, or long long.

</>
Copy
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>

int main(void) {
    int32_t temperature = -12;
    uint64_t file_size = UINT64_C(5000000000);

    printf("Temperature: %" PRId32 "\n", temperature);
    printf("File size: %" PRIu64 " bytes\n", file_size);
    return 0;
}

Choosing a Suitable C Data Type

RequirementSuitable TypeReason
General whole-number arithmeticintUsually the natural integer type for the platform
Value cannot be negativeAn unsigned type, when modulo arithmetic is acceptableProvides a nonnegative range but requires care when mixing signed and unsigned values
Array index or object sizesize_tType returned by sizeof and used by standard allocation and string APIs
Fractional calculationdoubleUsually offers more precision than float
Text character or string elementcharStandard character and byte-sized string element type
Raw byteunsigned charCan inspect the object representation of any object
True or false state_Bool or boolExpresses Boolean intent directly
Exact-width binary fieldA supported intN_t or uintN_tMakes the required width explicit
Several related fieldsstructEach named member retains its own value
One of several alternative representationsunion with a separate tagMembers share storage

C Data Types and Format Specifier Mistakes

  • Assuming every int is 32 bits: Check sizeof(int) and the limits in <limits.h>, or use an appropriate fixed-width type.
  • Using the wrong variadic format: A mismatched printf or scanf conversion can produce incorrect output or undefined behavior.
  • Mixing signed and unsigned arithmetic: Integer conversions can turn a negative signed value into a large unsigned value before comparison or calculation.
  • Expecting exact decimal floating-point results: Binary floating-point types cannot represent every decimal fraction exactly.
  • Treating char as always signed: Whether plain char is signed is implementation-defined.
  • Reading an inactive union member: Keep a separate tag or other program state indicating which union member currently holds the intended value.

Frequently Asked Questions About C Data Types

What are the main data types in C?

C has basic types such as integer, character, floating-point, Boolean, and void types. It also has derived types such as arrays, pointers, and functions, plus enumeration, structure, and union types. typedef can give an existing type another name.

How many data types are there in C?

There is no single useful count because basic types can be modified and combined to create many additional types. For example, every array length and element type creates a different array type, and every compatible parameter and return-type combination can produce a different function type.

What does %d mean in C?

In printf, %d converts an int argument to signed decimal notation. In scanf, %d reads a signed decimal integer into an int *. It is a format conversion specifier, not a data type.

Are C data type sizes the same on every system?

No. The C standard specifies minimum ranges and ordering relationships for many types but allows implementations to choose their sizes. Use sizeof, <limits.h>, <float.h>, and, when suitable, the integer types from <stdint.h>.

What is the difference between derived and user-defined data types in C?

Arrays, pointers, and function types are derived from other types. Structures, unions, and enumerations are declared by the programmer and are often described as user-defined types in introductory material. A typedef supplies another name for a type but does not by itself create a distinct type.

C Data Types Editorial QA Checklist

  • Confirm that storage sizes are described as common implementation values rather than universal C guarantees.
  • Verify that each printf and scanf conversion matches the corresponding argument or pointer type.
  • Compile pointer examples and confirm that addresses use the & operator and dereferences use *.
  • Check that character-code examples are identified as ASCII-specific when they rely on ASCII numeric values.
  • Confirm that void is not presented as a standard object type with a portable size.
  • Test code under the intended C language version with compiler warnings enabled.

Summary of C Data Types

C provides basic numeric and character types, derived array, pointer, and function types, and programmer-declared enumeration, structure, and union types. Choose a type according to the required range, precision, representation, and operations rather than assuming a fixed byte size. For portable programs, inspect implementation limits, match format specifiers to argument types, and use the standard fixed-width integer facilities when an exact supported width is required.