Operators in C, Part 2

Tweet
This entry is part 4 of 10 in the series Fundamentals of C

Fundamentals of C

This article is a continuation of the previous article, Operators in C, where we began with Postfix Operators and discussed the Array Subscript Operator and the Function Call Operator. Continuing with postfix operators, the third operator is the dot operator (.) and the arrow operator (->), used to access structure and union members.

3. Structure and Union Members

A structure is a user-defined data type which  is a collection of an ordered group of data objects. Unlike the elements of an array, the data objects within a structure are of different data types. Each data object in a structure/union is called a member of the structure/union.

A union is also a user-defined type which is a collection of data objects that have different data types. However , unlike the structure, members of a union share the same storage area, even though the individual members may differ in type. Thus a union permits several different data items to be stored in the same portion of the computer’s memory at different times.

for example:

struct student{
               int student_id;
               char[] student_name;
               };

The above structure declaration creates a user-defined data type called student. The structure student has two members: student_id and  student_name.

To access the members of a structure we need to first declare a variable of the user-defined data type student, and then we shall use the dot operator (.) to access the individual members of the structure.

struct student student1;

The above statement creates a structure variable student1 of type student. Now to access each member of the structure we will use the dot operator.

The Dot Operator

The dot operator is used to access a structure or union member.

Syntax:

structurevariable.membername;

example:

                    student1.student_id=101;
                    student1.student_name="Alice";

The above two statements access the individual members of the structure and assign values to them.

A union is also accessed in the same way using the dot operator. A union is declared in the following way:

union  name{

datatype1 member1;

datatype2 member2;

.

.

.

datatypeN memberN;

};

Syntax to declare a variable of a union:

 union unionname  variable;

To access a union member:

   variable.member

The Arrow Operator

The beginning address of a structure/union variable can be stored in a pointer variable and the individual members of the structure/union can then be accessed using the pointer variable and the Arrow Operator -> .

For example:

struct student student1;
struct student *stud1;

declares a pointer to the structure student. To store the initial address of the structure variable student1 in the pointer variable *stud1 we will use the address of operator &.

*stud1=&student1;

Now , to access the individual members we can use the pointer *stud1 and the arrow operator in the following way:

stud1->student_id;
stud1->student_name;

The arrow operator is used in a similar way in case of unions. The dot operator and the arrow operator will be discussed in greater detail when we discuss structures and unions in a later article.

4. Postfix Increment and Decrement Operators

The postfix increment and the postfix decrement operators  operate on only one operand which can either be a pointer variable or a variable belonging to the real data types: integer types and the floating point types (int, float, double along with the various type modifiers).

The postfix increment operation (operand++) increases the value of the variable by 1 and the postfix decrement operation (operand –) decreases the value of the variable by1.

A postfix expression of the form E++  where E is a variable is equivalent to E=E+1. Similarly, a postfix expression of the form E–  is equivalent to E=E-1.

Therefore ,

int i=10;
i++;
printf("%d",i); //prints 11
i--;
printf("%d",i); //prints 10

The result of a postfix increment or decrement operation is different when combined with the assignment operator (=). In a  postfix increment/ decrement operation the previous value of the variable being incremented/decremented is first assigned to the variable containing the result of the postfix increment/decrement operation and then the increment/decrement operation is carried out; that is, assignment takes place first and then the increment/decrement. To understand this consider the following example:

#include<stdio.h>

int main()
{
int a, i=10;
a=i++;
printf("a=%d, i=%d", a,i);
a=i--;
printf("a=%d, i=%d", a,i);
return 0;
}
 Output:
a=10, i=11
a=11,i=10

This is because in a postfix increment/decrement operation the value of i is first assigned to a and then updated.

Therefore in the first statement, a=i++; a is first assigned the previous value of which is 10 and then  i is updated to 11.

In the second statement, a=i--; a is again assigned the previous value of i (i=11 now, due to the previous increment operation) and then i  is decremented to 10.

5. Compound Literals

A postfix expression that consists of a parenthesised data type name followed  by a brace enclosed list of initializers is called a compound literal. The data type can either be a complete type (char, signed and unsigned integer types , floating point types and a pointer type) or an array of unknown size, but not an array of variable length (we will discuss variable length arrays in a later article on arrays).

A compound literal initializes an unnamed object. If the data type name specifies an array of unknown size the size is determined by the number of elements in the initializer list.

Some examples of compound literals are:

Array of Unknown Size

     (int []){ 2,4,7,6};

The above compound literal is an integer type array of unknown size. The size of the array is determined to be 4 after the initialization is complete.

Creating Structure Objects Using Compound Literals

To create a structure object we initialize each member of the structure through separate initialization statements; such as

     struct student student1;
     student1.student_id=101;
     student2.student_name="Alice";

The same can be accomplished in a more compact form using compound literals in the following way:

(struct student1){.student_id=101,
.student_name="Alice"};

Notice that the dot operator is still being used within the braces.

Pointer to a Structure Used as a Compound Literal

To  initialize a structure member using pointers we declare a pointer to a structure object and then initialize each member in separate initialization statements using the arrow operator; as in:

struct student student1, *stud1;
*stud1=&student1;
stud1->student_id=101;
stud1->student_name="Alice";

To perform the same job using compound literals we do not use the arrow operator. Rather, the same thing can be done in a very compact way using the dot operator and the address of operator (&) as shown below:

&(struct student1){.student_id=101, .student_name="Alice"};

Creating a Constant Compound Literal

A read-only compound literal; that is, a constant compound literal, can be specified by prefixing the const keyword:

(const int[]){1,2,3,4,5};
(const char[]){"Temperature"};

Coding becomes far more compact when compound literals are used. There are some more points related to a compound literal such as passing them to functions, their scope, and so on, which will be discussed later when we have understood functions.

Unary Operators

The unary operators operate on only one operand. There are four unary operators:

1. Prefix increment and decrement operators

2. Address of and indirection operators

3. The sizeof and alignof operators

4. Unary Arithmetic Operators

Prefix Increment and Decrement Operators

The prefix increment and decrement operators operate on only one operand which can either be a pointer variable or a variable belonging to the real data types: integer types and the floating point types (int, float, double along with the various type modifiers).

The  prefix increment operation (++ operand) increases the value by 1 and the prefix decrement operation (– operand) decreases the value by 1. A postfix expression of the form ++E  where E is a variable is equivalent to E=E+1. Similarly, a postfix expression of the form –E  is equivalent to E=E-1.

It was seen that in case of postfix increment/decrement assignment takes place first and then the increment/decrement. However, in case of a prefix increment or decrement operation the previous value is first incremented/decremented and then the assignment takes place.

To understand this consider the following piece of code.

#include<stdio.h>

int main()
{
int i=10,a;
  ++i;
printf("Value of i=%d",i);//prints 11
  --i;
printf("Value of i=%d",i);//prints 10
a=++i;
printf("Value of a=%d",a);//prints 11
printf("Value of i=%d",i);//prints 11
a=--i;
printf("Value of a=%d",a);//prints 10
printf("Value of i=%d",i);//prints 10
return 0;
}

 

Here, we can see that the value of i was first updated and then assigned  to a. Hence, a contains the updated value of i and not the previous value as was the case with postfix increment/decrement.

Address of and Indirection Operators

The address of operator & is used to evaluate the address of its operand.

The indirection operator * is used to evaluate the value stored at the address given by its operand. The operand must be of pointer type; ie, it can either be an array (which is a self-referential pointer), a pointer to a variable (data pointer) or a pointer to a function (function pointer).

Example of a data pointer:

#include<stdio.h>

int main()

{

int val, a=10;

int *p;                       //declares a pointer variable

p=&a;                      //now p stores the address of a

val=*p;                  //now val stores the value of a

printf(" Address of a: %X", p);

printf("Value of a: %d",val);

return 0;

}

 

In the above program the statement int *p declares an integer pointer (a pointer that stores the address of an integer variable).

To store the address of a in p, the address of operator is applied to  a and the result is stored in p as shown in the instruction p=&a;

Now p=&a;

Suppose the address of a is 1004 i.e . &a=1004

Since  p stores  the address of a, then p=&a p=1004

Now the value present at the address 1004 is the value stored in a which is 10(a=10).

To access the value stored in a using the pointer variable p we need to apply the indirection operator * on p. When the indirection operator is applied on p (*p), it reads the value stored at the address contained in p; ie, the value stored at the address 1004; ie, the value of a. The result of indirection is stored in the integer type variable val  as shown in the statement val =*p;. The indirection operator is also called the value at operator as it gives the value stored at a particular address.

To read the address stored in p, the format specifier %X is used in the printf statement as addresses are generally in hexadecimal.

The relationship between pointers and arrays has been discussed to some extent while discussing the array subscript operator. Function pointers is an advanced concept that will be discussed in a later article on pointers.

The next article will continue with the unary operators and the other operators in C.

 

 

 

 

Fundamentals of C

<< Operators in COperators in C, Part 3 >>

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Toni

    int i=10;
    printf(“%d”,i++); //prints 11
    printf(“%d”,i–); //prints 10

    That would be true with PREfix operators, ++i and –i.

    • http://www.myblogonunix.blogspot.com Surabhi Saxena

      Thank you for pointing that out. I have updated the code.