Lesson 4 - More on the C type system: Data types
In the previous exercise, Solved tasks for C lessons 1-3, we've practiced our knowledge from previous lessons.
Lesson highlights
Are you looking for a quick reference on data types in C instead of a thorough-full lesson? Here it is:
Creating variables of basic whole-number data types:
{C_CONSOLE}
char a = 15; // can store numbers from -128 to 127
short b = 10000; // -32 768 to 32 767
int c = 500000; // -2 147 483 648 to 2 147 483 647
long long int d = 10000000000; // very large numbers
printf("%d", a + b); // We can use basic arithmetics
{/C_CONSOLE}
Creating decimal variables:
{C_CONSOLE}
float f = 3.141592f; // single precision
double d = 3.14159265358979; // double precision
printf("%f \n", f);
printf("%lf \n", d); // note that not all digits are printed to save console space
{/C_CONSOLE}
Declaring characters:
{C_CONSOLE}
char a = 'A'; // One character
printf("%c \n", a);
printf("%d \n", a); // print as a characters code
{/C_CONSOLE}
Determining the variable size in bytes using
<limits.h>
:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(int argc, char** argv) {
// don't forget to #include <limits.h>
int intSize = sizeof(int); // Stores the int size
printf("Int occupies %d bytes \n", intSize);
return (EXIT_SUCCESS);
}
Would you like to learn more? A complete lesson on this topic follows.
In the previous lesson, Solved tasks for C lessons 1-3, we learned the basic data types of the C
language (int
, double
, and char
). In
today's tutorial, we're going to look at them in more detail and explain how to
use them correctly. Today is going to be more theoretical, and the next lesson
will be very practical. At the end, we'll make a few simple examples.
Note: Sizes and availability of the following data types may vary according to the used C standard and the computer processor's architecture.
Whole-number data types
Let's look at the table of all of the built-in whole-number data types in the
C language, notice the type int
, which is already known to us.
Data type | Range | Size |
---|---|---|
char | -128 to 127 | 8 bits |
short | -128 to 127 or -32 768 to 32 767 | 16 or 32 bits |
int | -32 768 to 32 767 or -2 147 483 648 to 2 147 483 647 | 16 or 32 bits (depends on the system) |
long int | -2 147 483 648 to 2 147 483 647 | 32 bits |
long long int | -9 223 372 036 854 775 808 to 9 223 372 036 854 775 807 | 64 bits |
Note: The data type sizes depends on the operating system, meaning whether it's 16-bit or 32/64-bit. The higher values are most probably the relevant ones for you.
You might be thinking it's odd that char
is a number since we
introduced it as a character in the previous lessons. In fact, we're able to use
char
as both a number or as a character (we'll either use the
"%d"
modifier or the "%c"
modifier when writing it to
the console). This is because characters are internally stored as their numeric
codes, those are called ASCII codes.
Another question might be: Why do we have so many data types for storing
numbers? The answer is simple, it depends on its size. If the number is large,
it consumes more memory. For a user's age, we should select byte
since no one can live more than 127
years. Imagine a database with
millions of users on some informational system. If we choose int instead of
char
, it'll occupy 4 times more space. Conversely, if we have a
function that calculates the factorial, the range of int
s will not
be enough for us and we'll have to use long int
.
We don't have to think hard about the data type choice since we'll use
int
almost every time. You have to think about it only in case the
variables are in an array or collection in general, and there are lots of them.
In that case, it's worth it to consider memory requirements. The tables I
provided here are mainly for the sake of completeness. The implicit conversion
also works between the types, so we can assign some int
to a
long int
variable directly, without having to convert it.
Decimal numbers
For decimal numbers, the choice is simpler, we can only choose between two
data types. They differ in the range of values, and also in precision, i.e. in
the number of decimal places. The datatype double
is twice as
precise as float
, which you probably deduced from its name.
Data type | Range | Precision | Size |
---|---|---|---|
float | 1.2E-38 to 3.4E+38 | 6 digits | 32 bits |
double | 2.3E-308 to 1.7E+308 | 15 digits | 64 bits |
long double | 3.4E-4932 to 1.1E+4932 | 19 digits | 80 bits |
Beware, due to the fact that decimal numbers are stored in your computer in a binary system, there is some precision loss. Although the deviation is almost negligible, if you're programming, e.g. a financial system, don't use these data types for storing money since it could lead to slight deviations.
When we need to assign a value to a float
variable in the source
code, we have to use the f
suffix. With double
s, we
don't write a suffix at all since double
is the default decimal
type:
float f = 3.14f; double d = 2.72;
As the decimal separator in a source code, we use dots, regardless of our OS regional settings.
Char
Let's take a closer look at the char
data type. Char represents
one character. Characters are declared with apostrophes in C:
{C_CONSOLE}
char c = 'A';
printf("%c", c);
{/C_CONSOLE}
Here's what we do when we need a char
to represent a number:
{C_CONSOLE}
char i = 127;
printf("%d", i);
{/C_CONSOLE}
Unsigned
types
Most of the data types can be prefixed with the unsigned
keyword. For example, we can create a variable of the unsigned int
type. Beware, this doesn't work for decimal numbers. Unsigned
means
that the number can't be negative (can't carry information about the +/- sign).
Therefore, the resulting variable is always non-negative, and it can carry a
number twice as big as before since the negative part of the type is not used.
Let's make an example with char
:
Type | Range |
---|---|
char | -128 to 127 |
unsigned char | 0 to 255 |
Now, let's start coding
We'll create a "table" of various data types and their sizes. First thing's
first, let's create a new project, name it Table
and modify the
code to look like this:
#include <stdio.h> #include <stdlib.h> #include <limits.h> int main(int argc, char** argv) { return (EXIT_SUCCESS); }
I removed the gray doc comments just to make the code clearer, feel free to
keep them in your project. The change here is in adding limits.h
which allows us to access functions for determining the highest possible value
of data types.
We use the sizeof()
function to determine the data type size, it
returns its size in bytes.
We're going to use constants (we'll cover them later on) from the
limits.h
file which we included.
Let's try it out:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(int argc, char** argv) {
int intSize = sizeof(int); // Stores the int size
printf("Int occupies %d bytes \n", intSize);
return (EXIT_SUCCESS);
}
The result should look like this:
Console application
Int occupies 4 bytes
Now, we've verified that the sizeof()
function returns the size
of a given data type. Let's try out the limits.h
constants which
return the highest possible value of a given type:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(int argc, char** argv) {
int maxValue = INT_MAX; // Stores the maximal value of int
printf("The maximal value stored in int is %d \n", maxValue);
return (EXIT_SUCCESS);
}
This should be the result (if you don't have a different processor):
Console application
The maximal value stored in int is 2147483647
Since we're now aware of how the constants work, we can get back to programming our console table The code will look like this:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(int argc, char** argv) {
int maxInt = INT_MAX;
short maxShort = SHRT_MAX;
char maxChar = CHAR_MAX;
char sizeInt = sizeof(int);
char sizeShort = sizeof(short);
char sizeChar = sizeof(char);
printf("INT: occupies %d bytes and the maximal value is %d\n", sizeInt, maxInt);
printf("SHORT: occupies %d bytes and the maximal value is %d\n", sizeShort, maxShort);
printf("CHAR: occupies %d bytes and the maximal value is %d\n", sizeChar, maxChar);
return (EXIT_SUCCESS);
}
The result:
Console application
INT: occupies 4 bytes and the maximal value is 2147483647
SHORT: occupies 2 bytes and the maximal value is 32767
CHAR: occupies 1 bytes and the maximal value is 127
There's still a lot to go over and lots of other data types that we haven't covered. Regardless, there is a time for everything. In the next lesson, Conditions (branching) in the C language, we'll introduce conditions and then loops, then we'll have enough knowledge to create interesting programs
Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.
Download
By downloading the following file, you agree to the license terms
Downloaded 3x (71.41 kB)
Application includes source codes in language C