Applications require different types of data to store information. For example, the name is an array of characters, but age is better stored as an integer. We can perform many operations (sum, average, concatenation, matching, etc.) if the data is stored in the correct format and with correct types. That is why we have so many data types in C so that we can differentiate and segregate data in the best possible way.
Data Types in C with Examples
There are 4 Data types in C:
- Basic
- Derived
- Void
- Enumeration
Most of the time, for small programs, we use the basic fundamental data types in C – int, char, float, and double.
For more complex and huge amounts of data, we use derived types – array, structure, union, and pointer.
Enumeration and void consist of enum and void, respectively. We will discuss these later in the article.
Basic Data Types
These are also termed as primary or fundamental data types. All the names mean the same thing. Suppose we have to store student details like name, id, group, avg_marks, interest_on_fees.
We can use basic data types to store each of these data:
char name[25]; int id; char group; float marks[5]; double interest;
int Data Type
Integer types can be signed (with negative values) or unsigned values (only positive). Int values are always signed unless specifically mentioned.
Integer types are further classified as –
Data type | Range |
int | |
signed int | −32,768 to 32,767 |
unsigned int | 0 to 65,535 |
short int | |
signed short int | -2,147,483,648 to 2,147,483,647 (4 bytes) |
unsigned short int | 0 to 4,294,967,295 (4 bytes) |
long int | |
signed long int | -2,147,483,648 to 2,147,483,647 (4 bytes) |
unsigned long int | 0 to 4,294,967,295 (4 bytes) |
Some examples:
int number = 456; long prime = 12230234029;
How to print integer variables? Here is a small program that you can try and tweak to get different results and understand the range of short, int, and long.
#include int main(void) { short int num1 = 10000; int number = 121113991; long prime = 49929929991; long notprime = 2300909090909933322; long long sum = prime + notprime; printf("num1 is %hd, number is %d, prime is %ld, notprime is %ld, sum is %lld", num1, number, prime, notprime, sum); return 0; }
We have used %hd for short, %d for int, and so on for printing each data type.
Note that we have used ‘long long’ for sum, which is 8 bytes, whereas long is 4 bytes. Though in practical situations, we may not use numbers that are this big, it is good to know the range and what data type we should use for programs with exponential calculations. We can use %u in place of %d for unsigned int but even %d works. Let us say the value of long notprime = -2300909090909933322; has a minus, but we print it as notprime is %lu, the correct value will not be printed. This is why it is safe to use %ld, unless you want the values to be always unsigned.
If we add more digits to short int num1 = 10000, it will be out of range and will print wrong value. ‘short int’ can be used to limit the size of the integer data type.
Float
The floating point data type allows the user to type decimal values. For example, average marks can be 97.665. if we use int data type, it will strip off the decimal part and print only 97. To print the exact value, we need ‘float’ data type.
Float is 4 bytes, and we can print the value using %f.
The float can contain int values too.
float average = 97.665; float mark = 67; printf("average is %f", average); printf(" mark is %f", mark);
However, you will get the result of the mark as 67.00000, which may not be a pleasant sight with a lot of redundant zeroes. If you try to print the value of mark as %d after declaring it as float, you will not get 67. Try to run this program and see what value you get.
Suggested Course
The Data Science Course 2024: Complete Data Science Bootcamp
Double
You can think of float, double and long double similar to short int, int, and long int. Double is 8 bytes, which means you can have more precision than float. This is useful in scientific programs that require precision. Float is just a single-precision data type; double is the double-precision data type. Long Double is treated the same as double by most compilers; however, it was made for quadruple data precision.
double average = 679999999.454; float score = 679999999.454; printf("average is %lf", average); printf(", score is %f", score);
The outputs are –
the average is 679999999.454000, the score is 680000000.000000
Note the difference in outputs – while double prints the exact value, float value is rounded off to the nearest number.
char
char stores a single character. Char consists of a single byte.
For example,
char group = ‘B’; To print a name or a full string, we need to define char array. char group = 'B'; char name[30] = "Student1"; printf("group is %c, name is %s", group, name);
Note that for a single character, we use single quotes, but for String (character array), we use double-quotes. Since its an array, we have to specify the length (30 in this case).
Just like the int data type, char can be signed (range from -128 to +127) or unsigned (0 to 255). C stores the binary equivalent of the Unicode/ASCII value of any character that we type. In our above example, the char group will be stored as a value ‘066’.
You can think of char also as an int value, as char takes int values too. The importance of signed and unsigned comes when you store an int between the specified range in a char.
Here is an example to help understand signed and unsigned chars better –
signed char char1 = -127; unsigned char char2 = -127; printf("char1 is %d, char2 is %d", char1, char2);
Note that since we are taking in int values, we will print as %d and not %c. Since char1 is signed, the printf will give value as -127. However, char2 is unsigned, which means the range is from 0 to 255, -127 is out of range. So, it will print 129. Same way, if you assign char2 as -1, you will get a value of 255.
Derived Data Types
Array, pointers, struct, and union are the derived data types in C.
Array
Same as any other language, Array in C stores multiple values of the same data type. That means we can have an array of integers, chars, floats, doubles, etc
int numbers[] = ; double marks[7]; float interest[5] = ;
The array needs to be either initialized, or the size needs to be specified during the declaration.
To understand one-dimensional Array operations, let us go through the following simple code –
#include int main(void) { // declare array with maximum 5 values int marks[5]; // get the size of the array int noOfSubjects = sizeof(marks)/sizeof(int); // let us get the inputs from user for(int i=0; i<noOfSubjects; i++) { printf("\nEnter marks "); scanf("%d", &marks[i]); } double average; double sum = 0; // fetch individual array elements for(int i=0; i<noOfSubjects; i++) // let us print the average of marks average = sum/noOfSubjects; printf("\nAverage marks = %lf", average); return 0; }
Few points to note here:
- If we don’t enter any value for marks, marks[i] will have defaulted to zero.
- If the sum is an int, sum/noOfSubjects will round off the average to nearest value and print only the value before decimal (even though average is of double data type). We can also do type casting to avoid this.
- Each element in the array is filled by using marks[i], where I correspond to the respective element. Same way, to fetch the data, we again loop through the array using marks[i] to get individual elements.
- sum += marks[i]; is same as writing sum = sum + marks[i];
In C, arrays can be multi-dimensional. For simplicity, we will restrict to a two-dimensional array.
dataType arrayName [rows][columns];
For example,
int matrix1[3][5] = { , //first row with index 0 , // second row with index 1 // third row with index 2 };
The index starts with 0 for both rows and columns. For example –
matrix1[0][0] will be 1. matrix1[1][1] will be 12. matrix1[2][2] will be 23. matrix1[2][4] will be 25.
If you have to access these values through a program, you will need two loop counters, the outer one for the rows, and the inner one for the columns.
Pointers
Pointers are considered by many to be complex in C, but that is not the case. Simply put, a pointer is just a variable that stores the address of another variable. A pointer can store the address of variables of any data types. This allows for dynamic memory allocation in C. Pointers also help in passing variables by reference.
The pointer is defined by using a ‘*’operator. For example –
int *ptr;
This indicates ptr stores an address and not a value. To get the address of the variable, we use the dereference operator ‘&.’ The size of a pointer is 2 bytes. Pointers cannot be added, multiplied, or divided. However, we can subtract them. This will help us know the number of elements present between the two subtracted pointers. Here is a simple program that illustrates pointer –
#include int main(void) { int *ptr1; int *ptr2; int a = 5; int b = 10; /* address of a is assigned to ptr1*/ ptr1 = &a; /* address of b is assigned to ptr2*/ ptr2 = &b; /* display value of a and b using pointer variables */ printf("%d", *ptr1); //prints 5 printf("\n%d", *ptr2); //prints 10 //print address of a and b printf("\n%d", ptr1); // prints address like -599163656 printf("\n%d", ptr2); // prints address like -599163652 // pointer subtraction int minus = ptr2 - ptr1; printf("\n%d", minus); // prints the difference (in this case 1) return 0; }
Structs
A struct is a composite structure that can contain variables of different data types. For example, all the student data that we declared earlier in basic data types can be put under one structure. Instead of having the information scattered, when we give it a structure, it is easier to store information about more students.
typedef struct{ char name[25]; int id; char group; float marks[5]; double interest; }Student;
A structure can be created outside the main method as well as inside, just before creating the variable to use it.
struct student1, student[20]; Structure members can be accessed using the dot(.) operator. For example, printf(“Student id is %d - ”, student1.id);
Elements in structure can be accessed using pointers too. There is no toString() method in C (like Java has), so to print struct values, we need to fetch them individually and print.
Here is a small program that shows the same (for simplicity, I have hard-coded the data, you can do a for loop and get the data from user too and store it the same as in an array).
int main(void) { // Store values in structures Student st1 = {"student1", 1, 'a', , 4.5}; Student st2 = {"student2", 2, 'b', , 9.5}; // Send structure values to the printing method print_student_details(&st1); print_student_details(&st2); return 0; } // get the address of structure data and print void print_student_details(Student *st) { printf("\Student details for %s are:\n", st->name); printf("id: %d\n",st->id); printf("group %c\n", st->group); // since marks is an array, loop through to get the data for(int i=0;i<5;i++) printf("marks %f\n", st->marks[i]); printf("interest %lf", st->interest); }
- Using the * operator, we are passing the value of student struct by reference, so that the correct values are retained.
- Instead of the dot operator, we are using ‘->’ operator to fetch the values.
Structs are simple to use and combine data in a neat way.
Union
With a union, you can store different data types in the same memory location. The union can have many members, but only one member can have a value at one time. Union, is thus, a special kind of data type in C.
The union is defined in the same way as a structure but with the keyword union.
union Student{ char name[25]; int id; char group; float marks[5]; double interest; }st1, st2;
When we assign values to union data, union allocates enough memory to accommodate the largest data type defined. For example, since the name takes the biggest space in the memory out of all the other data types, the union will allocate the space taken by name.
Let’s say we assign and print multiple values in the union at the same time.
st1.id = 1; st1.group = 'a'; strcpy(st1.name, "student1"); printf( "ID : %d\n", st1.id); printf( "Group : %c\n", st1.group); printf( "Name : %s\n", st1.name);
Unlike struct, this will fetch output as –
ID : 1685419123 Group : s Name : student1
Only the value of the member name is correct; other values have been corrupted. However, if we assign and print the values one by one, we will get all the values correctly.
st1.id = 1; printf( "ID : %d\n", st1.id); st1.group = 'a'; printf( "Group : %c\n", st1.group); strcpy(st1.name, "student1"); printf( "Name : %s\n", st1.name);
Now, we get the output as –
ID : 1 Group : a Name : student1
Read this blog to know more differences between structures and unions.
Enumeration
Enumeration data types enhance the readability of the code. If you have integer constants in the code that can be reused or clubbed together, we can use enums to define the constants. The most common example of this is the days of the week.
enum weekdays; enum weekend;
Internally, C will store MON as 0, TUE as one, and so on. We can assign values to the enum as well.
enum weekdays; If we print each of the enum values, the output will be – 1, 2, 6, 7, 8
Enums are very useful and can be used as flags. They provide flexibility and efficiency in the code.
Void
The void is just an empty data type used as a return type for functions. The absence of any other data type is void. When you declare a function as void, it doesn’t have to return anything. For example –
void swapNumbers(int a, int b){ //multiple lines of code here }
Same way, if a function does not have any parameters, that can be indicated with the void.
int getNumbers(void){ // some code }
We can declare a void pointer so that it can take a variable of any data type. A pointer declared as void becomes a general-purpose pointer –
char *ptr; int value; ptr = &value; //this will give error because we cannot point a char pointer to an int value However, void *ptr; will solve this problem and now we can write ptr = &value;
without any compilation errors. You can assign any data type to the void pointer.
Conclusion
In this blog, we have discussed all the data types in C in detail i.e., basic, derived, enumeration, and void. All the data types are useful in their own ways and make C the robust language it is. Check out C tutorials and best C books to further learn the language and clear your concepts. For a quick reference, use this diagram to remember all the data types in one go:
People are also reading: