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, andvoid. - 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.
| Type | Common Size | Minimum Required Range | printf Specifier |
|---|---|---|---|
short int | 2 bytes | -32,767 to 32,767 | %hd |
unsigned short int | 2 bytes | 0 to 65,535 | %hu |
int | 4 bytes | -32,767 to 32,767 | %d or %i |
unsigned int | 4 bytes | 0 to 65,535 | %u |
long int | 4 or 8 bytes | -2,147,483,647 to 2,147,483,647 | %ld |
unsigned long int | 4 or 8 bytes | 0 to 4,294,967,295 | %lu |
long long int | Usually 8 bytes | -9,223,372,036,854,775,807 to 9,223,372,036,854,775,807 | %lld |
unsigned long long int | Usually 8 bytes | 0 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:
#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.
| Type | Common Size | Typical Decimal Precision | printf Specifier | scanf Specifier |
|---|---|---|---|---|
float | 4 bytes | About 6 significant digits | %f | %f |
double | 8 bytes | About 15 significant digits | %f | %lf |
long double | 8, 12, or 16 bytes | Implementation-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:
#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.
| Type | Size | Minimum Range | Typical Use |
|---|---|---|---|
char | 1 byte | Same range as either signed char or unsigned char | Characters and strings |
signed char | 1 byte | -127 to 127 | Small signed integers |
unsigned char | 1 byte | 0 to at least 255 | Raw bytes and small nonnegative integers |
Example:
#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.
#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:
#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.
#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.
#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 = #. The corrected complete example is shown below.
#include <stdio.h>
int main(void) {
int num = 10;
int *ptr = #
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.
#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
#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
#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
#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
#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.
#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.
#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
| Requirement | Suitable Type | Reason |
|---|---|---|
| General whole-number arithmetic | int | Usually the natural integer type for the platform |
| Value cannot be negative | An unsigned type, when modulo arithmetic is acceptable | Provides a nonnegative range but requires care when mixing signed and unsigned values |
| Array index or object size | size_t | Type returned by sizeof and used by standard allocation and string APIs |
| Fractional calculation | double | Usually offers more precision than float |
| Text character or string element | char | Standard character and byte-sized string element type |
| Raw byte | unsigned char | Can inspect the object representation of any object |
| True or false state | _Bool or bool | Expresses Boolean intent directly |
| Exact-width binary field | A supported intN_t or uintN_t | Makes the required width explicit |
| Several related fields | struct | Each named member retains its own value |
| One of several alternative representations | union with a separate tag | Members share storage |
C Data Types and Format Specifier Mistakes
- Assuming every
intis 32 bits: Checksizeof(int)and the limits in<limits.h>, or use an appropriate fixed-width type. - Using the wrong variadic format: A mismatched
printforscanfconversion 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
charas always signed: Whether plaincharis 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
printfandscanfconversion 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
voidis 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.
TutorialKart.com