Educational Blog

How to Use Data Types in C

Learn the practical C data types you will use every day, from integers and pointers to structs and enums.

C gives you a small set of data types, but they control almost everything about how your program stores values, reads input, performs calculations, and talks to memory. If you learn them well early, the rest of C becomes easier to reason about. If you ignore them, you eventually hit bugs that look random but are really just type mismatches, overflow, truncation, or incorrect format specifiers.

The basic idea is simple: every value in C has a type, and the type tells the compiler how many bytes to use, how to interpret the bits, and what operations make sense. That matters for integers, decimal numbers, characters, arrays, pointers, structures, and function return values. It also matters when you call printf, scanf, allocate memory, or pass arguments into a function.

The core categories of C data types

You can think about C types in layers.

CategoryExamplesWhat it controls
Basic typesint, char, float, doubleCommon numeric and character values
Type modifiersshort, long, signed, unsignedSize and range changes
Derived typesarrays, pointers, functionsHow values are organized or referenced
User-defined typesstruct, union, enum, typedefCustom organization and naming

That table is the big picture. The details matter because C does not hide memory from you. A type is not just a label. It is a contract.

Integers: char, int, short, long

Integers store whole numbers. In C, the exact size of an integer type can vary by platform, but the relative roles stay the same.

  • char is usually the smallest addressable integer type and is commonly used for characters.
  • short is at least as large as char and usually smaller than int.
  • int is the standard default integer type for general arithmetic.
  • long and long long are for larger integer ranges.

A useful habit is to choose the smallest type that safely holds your values, but do not guess. If you need exact ranges, use the types in <stdint.h> such as int32_t and uint64_t.

int main(void) {
    int count = 42;
    long population = 8000000000L;
    unsigned int score = 97;

    printf("count=%d\n", count);
    printf("population=%ld\n", population);
    printf("score=%u\n", score);
    return 0;
}

A few things to notice:

  • The literal 8000000000L uses L to make it a long.
  • printf needs the correct format specifier for each type.
  • unsigned changes the range by removing negative values.

Floating-point types: float and double

Use floating-point types when you need fractions. float uses less memory than double on many systems, but double is generally the better default for calculations because it gives you more precision.

Common mistakes with floating-point types include:

  • Assuming decimal numbers are exact.
  • Comparing floats with == when a tolerance is safer.
  • Using the wrong printf format specifier.
#include <stdio.h>

int main(void) {
    double price = 19.99;
    double tax = 1.60;
    double total = price + tax;

    printf("total=%.2f\n", total);
    return 0;
}

For most application code, double is the practical default. Reserve float for cases where memory layout or hardware constraints make it worthwhile.

Characters and strings

A char stores a small integer value, and in practice it often represents a single character. In C, strings are arrays of char ending with a null terminator \0.

#include <stdio.h>

int main(void) {
    char grade = 'A';
    char name[] = "Mia";

    printf("grade=%c\n", grade);
    printf("name=%s\n", name);
    return 0;
}

Remember the distinction:

  • 'A' is a character literal.
  • "A" is a string literal containing two bytes: A and \0.

That difference causes many beginner bugs. If you pass the wrong thing to printf, the output will be wrong or undefined.

Signed and unsigned values

Every integer type can usually be either signed or unsigned.

  • Signed types can represent negative and positive numbers.
  • Unsigned types represent only non-negative numbers, but with a larger positive range.

This sounds helpful, but unsigned types can surprise you when subtraction underflows or when mixed with signed values.

TypeExample range ideaCommon use
signed intnegative to positivegeneral arithmetic
unsigned intzero to large positivebit manipulation, counts
size_tnon-negative sizearray sizes, memory sizes

Use unsigned types deliberately, not automatically. In everyday C code, size_t is common for sizes and indexes returned by standard library functions.

Why overflow matters

If a value exceeds the range of its type, the result depends on the type and operation. Signed overflow is especially dangerous because it can produce undefined behavior. Unsigned arithmetic wraps around in a defined way, but that does not make it safer by default.

If you are writing robust code, check bounds before arithmetic when there is any chance of overflow.

How C chooses a type in expressions

C often promotes smaller types to larger ones during arithmetic. That means the type of an expression may be different from the type of one of its inputs.

#include <stdio.h>

int main(void) {
    char a = 10;
    char b = 20;
    int sum = a + b;

    printf("sum=%d\n", sum);
    return 0;
}

Even though a and b are char, the expression a + b is promoted to an int in most cases. This is one reason C feels precise but occasionally unintuitive. The compiler is not ?guessing.? It follows promotion rules.

Practical rule

When mixing types, make the intended type obvious. Do not rely on implicit conversions to save you.

  • Use casts sparingly and intentionally.
  • Match format specifiers to the actual argument types.
  • Prefer clearer declarations over clever expressions.

Pointers and data types

Pointers hold memory addresses, and the pointed-to type tells C what kind of object lives at that address.

#include <stdio.h>

int main(void) {
    int value = 7;
    int *ptr = &value;

    printf("value=%d\n", value);
    printf("ptr points to %d\n", *ptr);
    return 0;
}

The pointer type matters because it controls dereferencing and pointer arithmetic.

  • int * points to an int.
  • char * points to a char.
  • double * points to a double.

This is why a pointer is not just an address. It is an address plus type information. That type information tells the compiler how many bytes to read and how to step through memory.

Arrays and their types

An array type describes a sequence of elements of the same type. A int scores[5] array stores five integers in contiguous memory.

#include <stdio.h>

int main(void) {
    int scores[3] = {91, 88, 95};
    printf("%d %d %d\n", scores[0], scores[1], scores[2]);
    return 0;
}

Arrays and pointers are related, but they are not the same thing. That distinction is important when you pass arrays to functions or compute sizes with sizeof.

A quick comparison

  • Arrays have fixed size in their declaration scope.
  • Pointers can be reassigned to point elsewhere.
  • sizeof(array) gives total array size when the array is still an array.
  • sizeof(pointer) gives the pointer size, not the size of the data it points to.

That last point is a classic trap.

User-defined types: struct, union, enum, typedef

Once the built-in types are familiar, you can combine them into more useful shapes.

struct

A structure groups related fields together.

#include <stdio.h>

struct Person {
    char name[20];
    int age;
};

int main(void) {
    struct Person p = {"Ava", 28};
    printf("%s is %d\n", p.name, p.age);
    return 0;
}

Use struct when a value has multiple attributes that belong together.

enum

An enumeration gives readable names to integer constants.

#include <stdio.h>

enum Direction { NORTH, EAST, SOUTH, WEST };

int main(void) {
    enum Direction d = SOUTH;
    printf("direction=%d\n", d);
    return 0;
}

Use enum for states, flags, or limited option sets.

typedef

typedef creates a new name for an existing type.

#include <stdio.h>

typedef unsigned long ulong;

int main(void) {
    ulong total = 1000;
    printf("%lu\n", total);
    return 0;
}

typedef does not create a new type category. It creates an alias, which can improve readability when the type is complex.

Choosing the right type

The best type depends on the job, not on habit. Here is a practical guide.

Use caseGood choiceWhy
Counting itemssize_t or unsigned intNon-negative by nature
General whole numbersintSimple and readable
Large whole numberslong or int64_tMore range
Fractional valuesdoubleBetter precision
Single characterscharCompact and natural
Packed data or flagsunsigned typesBitwise operations

If portability matters, prefer standard headers like <stdint.h> and <stddef.h> over guessing the size of int or long.

Common beginner mistakes

These are the mistakes that show up again and again:

  1. Using the wrong printf or scanf format specifier.
  2. Confusing 'x' with "x".
  3. Assuming all integer types have the same size.
  4. Treating float as exact decimal math.
  5. Mixing signed and unsigned values without checking the result.
  6. Forgetting the null terminator in strings.
  7. Using sizeof(pointer) when you meant sizeof(array).

If you avoid those, your C code will already be much more reliable than most beginner code.

A simple workflow for using data types well

When you add a variable, follow this process:

  1. Decide what kind of value it stores.
  2. Decide whether it can be negative.
  3. Decide whether it needs fractions.
  4. Decide how large the possible range can be.
  5. Pick the smallest type that safely fits the data.
  6. Use the matching format specifier.
  7. Re-check conversions when passing the value to a function.

That workflow prevents a lot of debugging later.

Bottom line

C data types are not just syntax. They define memory layout, arithmetic behavior, valid operations, and how your program talks to the rest of the system. Start with the basics: int, char, float, double, pointers, arrays, and struct. Then build the habit of checking range, precision, and conversion rules before you write the code.

If you understand data types, you understand one of the main ways C stays powerful and one of the main ways it can hurt you. The language gives you control. The types are how you use it responsibly.

Written by

c-double.com Editorial Team

Editorial team

c-double.com publishes practical how-to guides and educational articles with clear steps and useful context.