C Programming/Variables

From Wikiversity
Jump to navigation Jump to search
Completion status: About halfway there. You may help to clarify and expand it.

Objective[edit | edit source]

  • Learn about variables.
  • Learn about primitive types.

Lesson[edit | edit source]

Introduction[edit | edit source]

The most fundamental concept in C (and most other programming languages) is the variable. A variable is like a container. You can store things in it for later use, particularly numbers. The concept of a variable is borrowed from mathematics. A statement such as

x = 1

stores the value 1 in the variable x. In C, it is much the same. To assign a value to a variable, you can write:

x = 1;

But before you can do this, you must declare a variable. You declare a variable by specifying it's data type and name, like so:

data_type variable_name;

The programmer may combine declaration and assignment, which is known as initialization. Here is the variable x being declared and initialized:

int x = 1;

Data Types and Qualifiers[edit | edit source]

C is strongly typed, which means that variables must be explicitly assigned a data type. Data types indicate the type of data a variable can hold. When a variable is defined, a memory location will be assigned to the newly defined variable and it will also define the type of data that memory location will hold.

C has following data types:

  • int - an integer; reflects size of integers on host machine.
  • float - single-precision floating point.
  • double - double-precision floating point.
  • char - character, a single byte.

In addition to basic data types C also defines certain qualifiers to these data types. Qualifiers are used to make variable declaration more specific to variable uses.

Qualifiers available in the C language are:

  • short (applied to integers).
  • long (applied to integers).
  • signed (applied to char, or any integer).
  • unsigned (applied to char, or any integer).

Using these qualifiers, basic data types can be flavoured in many ways as shown in the table below. Note that the values given are acceptable minimum magnitudes defined by the C Standard - each implementation will define values greater or equal in magnitude.

Data Type Bits Range Begin Range End
char 8 -128 127
unsigned char 8 0 255
short int 16 -32768 +32767
unsigned short int 16 0 65,535
int 16 -32,768 32,767
unsigned int 16 0 65,535
long int 32 -2,147,483,648 2,147,483,647
unsigned long int 32 0 4,294,967,295
float 32 1e-37 1e+37
double 32 1e-37 1e+37
long double 32 1e-37 1e+37


C type qualifiers add special properties to the variables being declared. C provides the following two keywords:

  • const - the const qualifier is used to indicate the variable value can not be changed after its initialization. As an alternative, the #define preprocessor directive can be used to define constant values and these will consume no memory space.
  • volatile - the volatile qualifier indicates that variable values can be changed without the current program's knowledge and so the compiler should not optimize away uses of that variable.

Note: a Standard conforming compiler can ignore these qualifiers; nevertheless, it must issue a message when an attempt is made to alter an object declared as const.

Storage Classes[edit | edit source]

Storage classes define the longevity and scope of variables and functions. There are two types of storage classes: automatic and static. There are several storage class specifiers:

  • auto: this is the default storage class specifier for variables defined inside a function. auto can be used only inside functions. Variables declared auto will automatically have their storage allocated on entry to a function and deallocated when the function exits. auto variables contain garbage until explicitly initialised. Use of auto is archaic and there is no need to use it.
  • register: this storage class specifier can be used to indicate to the compiler that the variable will be used frequently and it should be placed in a CPU register, if possible. However, defining a variable with this specifier does not guarantee that it will be stored in a CPU register (a compiler can ignore it) and modern compilers should allocate registers much better than a programmer can.
  • static - this storage class specifier is used for two main purposes as given below
    • For local variables: when a local variable is defined with the static storage class specifier, it is initialized to 0 by default in the absence of an explicit initialisation value. A static variable in a function definition will retain its value across multiple calls to the function.
    • For global variables and functions: When a global variable or a function is defined as static, its scope is reduced to the C program file in which it is defined. Thus even though it is a global variable, it can not be accessed from another module (it is said to have internal linkage).
  • extern - this storage class specifier is used to declare a variable or function that is defined in another module. For function declarations, the storage class extern can be omitted.

Storage classes can be remembered easily by remembering mnemonic RASE, i.e., register, auto, static, and extern.

Example: the arithmetic mean of two numbers[edit | edit source]

The following source code is compiled with GCC:

#include <stdio.h>

void main(void)
{
     int a, b;
     float avg;  // data type

     printf("Enter the a:");
     scanf("%d", &a);

     printf("Enter the b:");
     scanf("%d", &b);

     avg = (a + b) / 2;  // expression

     printf("%f", avg);
     getch();  // getchar() may work instead

     return 0;
}

Expressions[edit | edit source]

To manipulate the variable, ‘a’, declared and defined in the previous section, an expression is needed. By definition, an expression, in C, is an interpreted combination of values, variables, operators or functions. There are a number of operators available including addition, ‘+’, subtraction, ‘-‘, division ‘/’, and multiplication ‘*’. In an expression, the variable name on the left side of the assignment operator represents the area of memory that stores interpreted results. Variable and constants on the right side of the assignment operator are interpreted to determine a result prior to assignment. Note these definitions and declarations:

int a;
int b;

a = 0;
b = 8;

What follows is a statement which manipulates storage in memory (an expression becomes a statement when it is followed by a semicolon):

a = b + 24;

In this statement, the constant ‘24’, is added to the value stored in the variable ‘b’. The result of that calculation, then, is assigned to a memory location, symbolically represented by the variable ‘a’. After the interpretation of the statement, the variable 'a' is assigned the value 32.

Typecasting[edit | edit source]

C has the concept of data types:

int a;
float b;

When you assign b to a:

a = b;

An int is converted to a float implicitly. However, (potentially) dangerous conversions are forbidden and stopped by the compiler:

/* * means pointer, you will learn them later. 
Assigning between pointers of different types is dangerous unless their layout is compatible */
int* x;
float* y;
y = x;

Converting a float* to an int* is dangerous and will be blocked by the compiler. If you must perform this operation, use the following typecast:

y = (float*) x;

A type inside a pair of () is to force change x to a float* so that it can be assigned to y. If the compiler doesn't know how to convert, the result is unspecified. One can use casts to circumvent the type system of C.

Casts are dangerous, but sometimes needed.

External resources[edit | edit source]

YouTube: Learn C Programming Tutorial 1.11 Math Operators

Assignments[edit | edit source]

  • What data type(s) could you use if you were creating a program that stored monetary sums (Dollars, Euros, etc.)?
  • What data type could you use to store if you wanted someone to type their name into your program?
  • What data type(s) could you need if you wanted to count from 0 to 100?
  • Compiler dependent: Modify the "arithmetic mean" example program in order to get the right result even if a and b differ by an odd number (e.g. a=1 and b=2).