The standard C language provides the following operators and punctuators:
{ } |
[ ] |
( ) |
(type) |
. |
-> |
++ |
-- |
& |
* |
+ |
- |
~ |
! |
sizeof |
/ |
% |
<< |
>> |
< |
> |
<= |
>= |
== |
!= |
^ |
| |
&& |
|| |
? : |
= |
*= |
/= |
%= |
+= |
-= |
<<= |
>>= |
&= |
^= |
|= |
, |
# |
## |
; |
: |
" " |
... |
In addition, GNU C also knows the typeof operator, and extends some existing operators.
The operators # and ## are
used only by the preprocessor.
Depending on context, the same operator can have more than one meaning. For
example, the ampersand ('&'
) can be interpreted as
a bitwise AND (A & B
);
an address operator (&A
);
In the first case, the '&'
is a unary operator; in the second, the '&'
is a
binary operator. Similarly, the comma ','
may act as an operator and as a
punctuator, etc.
Note: In GNU C the operator '&&' may also be used as unary operator for taking addresses of labels.
In the expression
& expr
which means "take the address of the expr", the expr operand must be one of the following:
a function designator;
an lvalue designating an object that is not a bit field and is not declared with the register storage class specifier.
If the operand is of type type, the result is of type "pointer to type".
The '&'
symbol is also used in C as a binary bitwise AND operator.
In the expression
* expr
which means "the object pointed to by expr",
the expr must have type "pointer to type," where type is any
data type. The result of the indirection is of type type.
If the operand is of type "pointer to function", the result is a function
designator. If the operand is a pointer to an object, the result is an lvalue
designating that object.
In the following situations, the result of indirection is undefined:
The expr is a null pointer.
The expr is the address of an automatic (local) variable and execution of its block has terminated.
You can also use the asterisk as an operator to dereference a pointer, or as the multiplication operator. Asterisk may be used also as a punctuator for creating pointer types.
In these unary + - expressions
+ expr - expr
the expr operand must be of arithmetic type.
The result is the value of the operand after any required integral
promotions for the unary plus ('+'
) operator, or
negative of the value of the operand after any
required integral promotions for the unary minus ('-'
) operator.
Floating point negation is internally executed using the fneg function.
Note that both '+' and '-' operators also have a binary form.
The increment operator may be used as a postincrement or preincrement operator:
expr ++ (postincrement) ++ expr (preincrement)
The expression is called the operand; it must be of scalar type (arithmetic
or pointer types) and must be a modifiable lvalue.
When postincrement operator form is used, the value of the whole expression is the
value of the postfix expression before the increment is applied.
After the postfix expression is evaluated, the operand is incremented by 1.
When preincrement operator form is used, the operand is incremented by 1 before the
expression is evaluated; the value of the whole expression is the incremented value
of the operand.
The increment value is appropriate to the type of the operand.
Pointer types follow the rules for pointer arithmetic. In other words, the actual
address on which a pointer points to is incremented by the size of the pointed object
(not by 1, except if the pointed object is one byte long), so after the incrementing, the
pointer points to the next object in a sequence (e.g. to a next element in an array, etc.).
Note: GNU C extends the pointer arithmetic to be valid even on void pointers and pointers to
functions (see extended pointer arithmetic for
more info).
The decrement operator may be used as a postdecrement or predecrement operator:
expr -- (postdecrement) -- expr (predecrement)
The decrement operator follows the same rules as the increment operator, except that the operand is decremented by 1 after or before the whole expression is evaluated.
In the expression
! expr
the expr operand must be of scalar type (i.e. not an array, a structure or an union).
The result is of type int
and is the logical negation of the operand:
0 if the operand is nonzero;
1 if the operand is 0.
The expression '!expr'
is equivalent to '(0 == expr)'
.
In the expression
~ expr
the expr operand must be of integral type. The result is the bitwise complement of the operand after any required integral promotions. Each 0 bit in the operand is set to 1, and each 1 bit in the operand is set to 0.
Both '+'
and '-'
uses the same syntax:
expr1 + expr2 expr1 - expr2
Note that both '+' and '-' operators also have an unary form.
Legal operand types for expr1 + expr2 are:
Both expr1 and expr2 are of arithmetic type;
expr1 is of pointer to object type, and expr2 is of integral type.
expr1 is of integral type, and expr2 is of pointer to object type;
In case 1, the operands are subjected to the standard arithmetical
conversions (for example, char
s are promoted to int
s), and the
result is the arithmetical sum of the operands.
In cases 2 and 3, the rules of pointer arithmetic apply. When expr1 is of
pointer type (case 2), the actual address on which a pointer points to is incremented by
expr2 multiplied by the size of the pointed object (not just by expr2,
except if the pointed object is one byte long). For example, if expr1 points
to an array, expr1 + 5 points to a fifth element of the array, no matter
how long are the particular elements of the array. The same rules are valid for the case 3.
Assuming that ptr is a pointer to type and that N is an integer,
and assuming that the CPU uses linear addressing (this is true on Motorola 68000, but not
on Intel 8086 for example), expression
ptr + N
is equal to
(type *) ((long) ptr + N * sizeof (type))
Legal operand types for expr1 - expr2 are:
Both expr1 and expr2 are of arithmetic type;
expr1 is of pointer to object type, and expr2 is integral type;
Both expr1 and expr2 are pointers to compatible object types;
In case 1, the operands are subjected to the standard arithmetic
conversions, and the result is the arithmetic difference of the operands.
In cases 2 and 3, the rules of pointer arithmetic apply. When expr1 is pointer
and expr2 is integral type (case 2), the actual address on which a pointer points to is decremented by
expr2 multiplied by the size of the pointed object (not just by expr2,
except if the pointed object is one byte long). For example, if expr1 points
to the fifth element of an array, expr1 - 2 points to a third element of the array, no matter
how long are the particular elements of the array. When both expr1 and expr2
are pointers, the result of the substraction is the difference of actual addresses divided by
the common size of pointed objects. For example, if expr1 and expr2 point to
two elements of the same array, then expr2 - expr1 will be equal
to the difference of actual indices of pointed elements.
The unqualified type 'type' is considered to be compatible with the
qualified types 'const type', 'volatile type', and
'const volatile type'.
Floating point addition and substraction are internally executed using the
fadd and fsub functions.
Note: GNU C extends the pointer arithmetic to be valid even on void pointers and pointers to
functions (see extended pointer arithmetic for
more info).
There are three multiplicative operators in C:
* (multiplication: the product of the two operands) / (division: the quotient of the first operand divided by the second operand) % (modulus: the remainder of the first operand divided by the second operand)
They use the following syntax:
expr1 * expr2 expr1 / expr2 expr1 % expr2
Note that '*' operator also has an unary form, and may be also
used as a punctuator for creating pointer types.
Operands for '*'
and '/'
are of arithmetical type, and operands of
'%'
are of integral type.
The usual arithmetic conversions are made on the operands.
For '/'
and '%'
, expr2 must be nonzero;
expr2 == 0 results in an error (you can't divide by zero).
When expr1 and expr2 are integers and the quotient
is not an integer:
If expr1 and expr2 have the same sign, expr1 / expr2 is the largest integer less than the true quotient, and expr1 % expr2 has the sign of expr1.
If expr1 and expr2 have opposite signs, expr1 / expr2 is the smallest integer greater than the true quotient, and expr1 % expr1 has the sign of expr1.
Note: Rounding is always toward zero.
Floating point multiplication and division are internally executed using the
fmul and fdiv functions; more detailed
info about rules of these operation is given with the description of these functions.
Bitwise shift operators in C use the following syntax:
expr1 << expr2 expr1 >> expr2
In the expressions expr1 << expr2 and
expr1 >> expr2, the operands expr1
and expr2 must be of integral type. The normal integral promotions are performed
on expr1 and expr2,
and the type of the result is the type of the promoted expr1.
If expr2 is negative or is greater than or equal to the width in bits of
expr1, the operation is undefined.
The result of the operation expr1 << expr2
is the value of expr1 left-shifted by expr2 bit positions,
zero-filled from the right if necessary.
The result of the operation expr1 >> expr2
is the value of expr1 right-shifted by expr2 bit positions.
The C language offers these bitwise and logical operators:
& (bitwise AND) ^ (bitwise exclusive OR) | (bitwise inclusive OR) && (logical AND) || (logical OR)
They use the following syntax:
expr1 & expr2 expr1 ^ expr2 expr1 | expr2 expr1 && expr2 expr1 || expr2
In first three expressions, both operands must be of integral type.
In fourth and fifth expressions, both operands must be of scalar type.
The usual arithmetical conversions are performed on expr1 and expr2.
For the bitwise operators, each bit in the result is:
Bit value | Results of | |||
in expr1 | in expr2 | expr1 & expr2 | expr1 ^ expr2 | expr1 | expr2 |
0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 1 | 1 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 0 | 1 |
'&&'
and '||'
guarantee left-to-right evaluation.
expr1 is evaluated first; if it is zero,
expr1 && expr2 gives 0 (false), and expr2 is
not evaluated at all. With expr1 || expr2, if
expr1 is nonzero, expr1 || expr2 gives 1 (true), and
expr2 is not evaluated at all.
There are 11 assignment operators in C language.
The '='
operator is the simple assignment operator; the other 10
('*='
, '/='
, '%='
, '+='
, '-='
,
'<<='
, '>>='
, '&='
,
'^='
and '|='
)
are known as compound assignment operators.
All of them use the following syntax:
expr1 assignment-operator expr2
In the expression expr1 = expr2, expr1 must be a modifiable lvalue. The value of expr2, after conversion to the type of expr1, is stored in the object designated by expr1 (replacing expr1's previous value). The value of the assignment expression is the value of expr1 after the assignment. That's why multiple assignments like
x = y = z = 10; a = b + 2 * (c = d - 1);
are possible. Note that the assignment expression is not itself an lvalue.
For both simple and compound assignment, the operands expr1 and expr2 must obey
one of the following sets of rules:
expr1 is of qualified or unqualified arithmetic type and expr2 is of arithmetic type.
expr1 has a qualified or unqualified version of a structure or union type compatible with the type of expr2.
expr1 and expr2 are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right.
One of expr1 or expr1 is a pointer to an object or incomplete type and the other is a pointer to a qualified or unqualified version of void. The type pointed to by the left has all the qualifiers of the type pointed to by the right.
expr1 is a pointer and expr2 is a null pointer constant.
The compound assignments are 'op='
, where op can be any one of
the ten operator symbols '*'
, '/'
, '%'
, '+'
,
'-'
, '<<'
, '>>'
, '&'
,
'^'
or '|'
. The expression
expr1 op= expr2
has the same effect as
expr1 = expr1 op expr2
except that the lvalue expr1 is evaluated only once. For example, expr1 += expr2 is the same as expr1 = expr1 + expr2.
The relational operators are used to compare relative values. They use the following syntax:
expr1 < expr2 expr1 > expr2 expr1 <= expr2 expr1 >= expr2
In all relational expressions, the operands must conform to one of the following sets of conditions:
Both expr1 and expr2 are of arithmetic type.
In this case, the usual arithmetic conversions are performed and the result
is of type int
.
Both expr1 and expr1 are pointers to qualified or unqualified versions of compatible object types.
When the operands are of arithmetic type:
expr1 < expr2 gives 1 (true) if the value of expr1 is less than value of expr2; otherwise, the result is 0 (false).
expr1 <= expr2 gives 1 (true) if the value of expr1 is less than or equal to the value of expr2; otherwise, the result is 0 (false).
expr1 > expr2 gives 1 (true) if the value of expr1 is greater than the value of expr2; otherwise, the result is 0 (false).
expr1 >= expr2 gives 1 (true) if the value of expr1 is greater than or equal to the value of expr2; otherwise, the result is 0 (false).
When the operands are of compatible pointer types,
the result depends on the relative addresses of the two
objects being pointed at.
Floating point comparisons are internally executed using the
fcmp function. See the description of this function for
more info about rules of comparisons for floating point values.
The operators '=='
and '!='
are used to test for equality or inequality between
arithmetic or pointer values, following rules similar to those for the relational operators.
However, the equality operators have lower precedence than the relational operators,
and you can also compare certain pointer types not allowed with relational operations.
In the expressions expr1 == expr2 and expr1 != expr2, the operands must conform to one
of the following sets of conditions:
Both expr1 and expr2 are of arithmetic type.
Both expr1 and expr2 are pointers to qualified or unqualified versions of compatible types.
One of expr1 and expr2 is a pointer to an object, and the other is a pointer to a qualified or unqualified version of void. In this case, the pointer to an object is converted to the type of the other operand (a void pointer).
One of expr1 or expr2 is a pointer and the other is a null pointer constant.
If expr1 and expr2 have types that are valid operand types for a relational
operator, the same comparison rules as for the relational operators apply.
If expr1 and expr2 are pointers to function types, expr1 == expr2 gives 1 (true) if they
are both null or if they both point to the same function.
Conversely, if expr1 == expr2 gives 1 (true), then either expr1 and expr2 point to the
same function, or they are both null.
The expression expr1 != expr2 follows the same rules, except that the result is 1
(true) if the operands are unequal, and 0 (false) if the operands are equal.
Floating point comparisons are internally executed using the
fcmp function. See the description of this function for
more info about rules of comparisons for floating point values.
The C language supports two selection operators:
. (direct member selector) -> (indirect, or pointer, member selector)
You use the selection operators '.'
and '->'
to access structure and union
members. Suppose that the object s is of struct type S and sptr is a pointer to
s. Then, if m is a member identifier of type M declared in S, these
expressions:
s.m sptr->m
are of type M, and both represent the member object m in s.
The expression
sptr->m
is a convenient synonym for (*sptr).m
.
The direct member selector ('.'
) uses the following syntax:
expresssion . identifier
The expr must be of type union or structure.
The identifier must be the name of a member of that structure or union type.
The indirect member operator ('->'
) uses the following syntax:
expr -> identifier
The expr must be of type pointer to structure or pointer to union.
The identifier must be the name of a member of that structure or union type.
The expression with selection operators designates a member of a structure or union object. The
value of the selection expression is the value of the selected member; it will be an
lvalue if and only if the expr is an lvalue. For example,
struct mystruct { int i; char str[21]; long d; } s, *sptr=&s; ... s.i = 3; // assign to the 'i' member of mystruct 's' sptr->d = 12345678; // assign to the 'd' member of mystruct 's'
The expression 's.m'
is an lvalue, provided that 's'
is an lvalue and
'm'
is not an array type.
The expression 'sptr->m'
is an lvalue unless 'm'
is an array type.
If structure B contains a field whose type is structure A, the members of
A can be accessed by two applications of the member selectors.
The conditional operator '?:'
is, in fact, a ternary operator.
It uses the following syntax:
expr1 ? expr2 : expr3
In the expression expr1 ? expr2 : Expr3, the operand expr1 must be of scalar type. The operands expr2 and Expr3 must obey one of the following sets of rules:
Both of arithmetic type. In this case, both expr2 and Expr3 are subject to the usual arithmetic conversions, and the type of the result is the common type resulting from these conversions.
Both of compatible structure or union types. In this case, the type of the result is the structure or union type of expr2 and expr3.
Both of void type. In this case, the result is of type void.
Both of type pointer to qualified or unqualified versions of compatible types. In this case, the type of the result is pointer to a type qualified with all the type qualifiers of the types pointed to by both operands.
One operand of pointer type, the other a null pointer constant In this case, the type of the result is pointer to a type qualified with all the type qualifiers of the types pointed to by both operands.
One operand of type pointer to an object, the other of type pointer to a qualified or unqualified version of void. In this case, the type of the result is that of the non-pointer-to-void operand.
In all cases, expr1 is evaluated first. If its value is nonzero (true), then expr2
is evaluated and expr3 is ignored (not evaluated at all). If expr1 evaluates
to zero (false), then expr3 is evaluated and expr2 is ignored.
The result of expr1 ? expr2 : expr3 will be the value of whichever of expr2 and
expr3 is evaluated.
Note: GNU C extends the usage of the conditional operator to allow
omitting the middle operand, so it may be used as
a binary operator too.
Most of these punctuators also function as operators.
Brackets indicate single and multidimensional array subscripts. When used as an operator, the expression
expr1[expr2]
is defined exactly as
*((expr1) + (expr2))
where either expr1 is a pointer and expr2 is an integer,
or expr1 is an integer and expr2 is a pointer. Of course,
the addition is performed in according to the pointer arithmetic rules
(see binary plus for more info).
Note that every array name, if used alone (without the array subscript operator), is
automatically interpreted as a pointer to the first element of the array.
When used as a punctuator, brackets are used for creating array types (see
asterisk for more info).
Note: The GNU C extends the usage of square brackets to allow
labeling elements in initializers.
Parentheses operators do the following:
group expressions (when necessary to change precedence);
isolate conditional expressions;
indicate function calls and function parameters.
Note that parentheses are also the part of the TypeCast operator.
When used as function-call operators, parentheses use the following syntax:
expr (arg-expression-list)
This is a call to the function given by the expr, which can be either the function name, or an expression which evaluates to a pointer-to-function type. In the second case, the function call is in fact translated to
(* expr) (arg-expression-list)
arg-expression-list is a comma-delimited list of expressions of
any type representing the actual (or real) function arguments. The value of the
function call expression, if it has a value, is determined by the
return
statement in the function definition.
arg-expression-list may even be empty, which is necessary when you
need to call an argument-less function:
expr ()
Note that every function name, if used alone (without the parentheses operator), is
automatically interpreted as a pointer to the function.
When used as a punctuator, parentheses are used for creating function types (see
asterisk for more info).
The { } braces indicate the start and end of a compound statement. Each sequence
of statements (terminated by semicolons) is treated as
a single statement, called compound statement. Compound statements may have its
own local variables as well.
Braces are also used in declaration of enumerations,
structures and unions,
as well as for function definitions. For example:
int square (int x); // This is a function prototype int square (int x) {return x*x;} // This is a function definition
Note: The GNU C extends the usage of braces (together with parentheses) to allow making statement expressions. They are also used in cast constructors, which are yet another GNU C extension.
The '='
(equal sign) used as a punctuator separates variable declarations from initialization
lists. For example,
int array[5] = { 1, 2, 3, 4, 5 }; char *name = "Fred"; int x = 12;
In a C function, no code can precede any variable declarations. Note that the GNU C,
in opposite to other C dialects, allow non-constant
initializers (like in C++).
The equal sign is also used in enumerations:
enum colors {Blue = 1, Red = 2, Green = 4, Light = 8};
It is also used as the assignment operator in expressions:
a = b + c;
or even:
a = b + 2 * (c = d - 1);
Note: The GNU C extends the usage of equal sign (as a punctuator) to allow labeling elements in initializers.
The comma, used as a punctuator, separates the elements of a function argument list,
the elements in array or struct initializers, or the variables in a data declaration.
The comma is also used as an operator in comma expressions. Mixing the two
uses of comma is legal, but you must use parentheses to distinguish them.
When used as an operator, the comma operator uses the following syntax:
expr1, expr2
The left operand expr1 is evaluated as a void expression (i.e. it is ignored if not contain side effects), then expr2 is evaluated to give the result and type of the comma expression. So, the result is just expr2. By recursion, the expression
expr1, expr2, ..., ExprN
results in the left-to-right evaluation of each Expr-i, with the value and type of ExprN giving the result of the whole expression. Comma operator is usually used in for-loops for multiple initializations. For example,
for (i = 0, j = 1024; i + j < 5; i++, j /= 2) ...
It also may be used to avoid making compound statements in simple conditional statements. For example,
if (x > 10) i = 1, j = 2, k = 3;
have the same effect as
if (x > 10) { i = 1; j = 2; k = 3; }
To avoid ambiguity with the commas used in function argument and initializer lists, parentheses must be used. For example,
func(i, (j = 1, j + 4), k);
calls 'func'
with three arguments, not four. The arguments are
'i'
, '5'
, and 'k'
.
The semicolon is a statement terminator. It is also used to separate three
expressions which are parts of a for-loop.
Any legal C expression (including the empty expression) followed by ; is
interpreted as a statement, known as an expression statement.
The expression is evaluated and its value is discarded. If the expression
statement has no side effects, it will be simply ignored.
Semicolons are often used to create an empty statement. For example, the body
of the following for-loop (which searches for a first non-zero element in the
array) is an empty statement:
for (i = 0; i < max || !a[i]; i++);
Use the colon (':'
) to indicate a labeled statement:
start: x=0; ... goto start;
Special case of labels are case-labels, which are used in multiple selection statements, for example,
switch (a) { case 1: puts("One"); break; case 2: puts("Two"); break; ... default: puts("None of the above!"); }
Note: The GNU C allows creating of local labels, which are useful in macro definitions.
The asterisk ('*'
) in a variable expression creates a pointer to a type.
For example,
int a, *b;
In this example 'a'
is an integer, but 'b'
is a pointer to
an integer.
Punctuators asterisk, brackets and parentheses
may be mixed together to create very complex data types (which are sometimes very hard to
understand). When mixed together, parentheses have the greatest precedence, then brackets,
and finally, asterisks. This will be illustrated with a set of examples, which are given in
the following table:
int x; |
A simple integer |
int x[5]; |
An array (with 5 elements) of integers |
int x[5][6]; |
An array (with 5 elements) of arrays (with 6 elements) of integers; such "array of arrays" may be interpreted as a 5x6 matrix |
int *x; |
A pointer to an integer |
int *x[5]; |
An array of pointers to integers |
int x(); |
A function (more precise, a prototype of a function) which returns an integer |
int x(int a); |
A function which accepts one integer argument, and which returns an integer |
int x(int a,int *b); |
A function which accepts two arguments, the first one is an integer, and second one is a pointer to an integer, and which returns an integer |
int x(int,int*); |
The same as above, but actual names of arguments may be omitted in function prototypes (but not in function definitions) |
int *x(); |
A function which returns a pointer to an integer |
int *x(int); |
A function which accepts one integer argument, and which returns a pointer to an integer |
int **x; |
A pointer to a pointer to an integer (this declaration is logically equivalent with the next one) |
int *x[]; |
An array of unknown size of pointers to integers (this declaration is logically equivalent with the previous one) |
int (*x)[5]; |
A pointer to an array (with 5 elements) of integers |
int (*x)(); |
A pointer to a function which returns an integer |
int (*x)(int,int); |
A pointer to a function which accepts two integer arguments and which returns an integer |
int (*x[5])(); |
An array of pointers to a function which returns an integer |
int (*x(*x())[5])(); |
A function which returns a pointer to an array of pointers to a function which returns an integer |
int (*x(*x(int))[5])(int*); |
A function which accepts one argument which is a pointer to an integer, and which returns a pointer to an array of pointers to a function which accepts one integer argument and which returns an integer |
int (*(*x[5])())[6]; |
An array (with 6 elements) of pointers to a function which returns a pointer to an array (with 5 elements) of integers |
'int*'
is anonymous pointer to an integer, 'int(*)()'
is anonymous pointer to
a function which returns an integer, and 'int(*[])(int*)'
is anonymous array (of
unknown size) of pointers to a function which returns an integer and which accepts one argument
which is a pointer to an integer.
Quotes are used for defining string constants. In the compile-time, the sequence of characters
between qoutes are stored somewhere in the executable file. In the run time, the "result" of
quotes is a pointer (of type 'char*'
) which points to the place where the sequence
of characters is stored. This interpretation of quotes differs significantly from the interpretation
of strings in other languages. That's why there is nothing wrong with the following C code (it
stores the address where the text "Hello" is stored, interpreted as an integer, in a
):
int a; a = (int)"Hello";
Such constructs are usually impossible in other languages. Note that sequences of characters between quotes behave similarly like arrays declared with the static keyword, i.e. they can survive the end of a function or program if they are changed somewhere in the program (anyway, it is very bad idea to change the content of a string constant). For example, the following code
for (i = 0; i < 2; i++) { char *str; str = "xyz"; printf (str); *str = 'a'; }
will display "xyzayz", although it seems that "xyzxyz" would be displayed. Such strange behaviour
is caused by the fact that "xyz" is initialized in the compile-time. Now, if you understand the
correct interpretation of what the quote punctuator does, you can explain this behaviour easily.
To learn: strings in C behave quite differently than in most other languages!
Note: These two statements are very different, although most books say
that they are nearly the same:
char str[] = "Hello"; char *str = "Hello";
Suppose that str is declared in the body of the function (i.e. it is an automatic
local variable). In both cases, the text "Hello" is stored somewhere in memory, and the "result"
of "Hello"
is the address where it is stored (we will call this address addr).
In the first case, str is a local array (i.e. it is created on the stack at run
time, and there will be 6 bytes reserved for it), whose content is initialized at run-time
(because it does not exist at compile-time) with the sequence of bytes located at addr.
In other words, it is the same as you wrote:
char str[6]; strcpy (str, "Hello");
The consequence is that if you change the content of str (note that this is not the same as changing bytes pointed to by addr), it will be reinitialized each time when this statement is encountered again. But, in the second case, str is a local pointer, whose content is initialized (at run-time) with addr! So, if the contents of the string "Hello" are changed, this change will be permanent, because when this statement is encountered again, str will simply be reinitialized (if changed) to addr but bytes pointed to by it are not restored! Confused? See the following code:
for (i = 0; i < 2; i++) { char str[] = "Hello"; printf (str); str[0] = 'a'; }
This program will work as expected (it will display "Hello" twice). But, if you change
'str[]'
to '*str'
, it will not work as expected (it will
display "Hello" and then "aello").
Generally, it is a very bad idea to change strings which are the result of quotes.
The reason is that usually equal strings are stored only once in the program.
This means that you can get unexpected results if you modify them.
If the '\' character is found inside a string literal, it is threated as the start
of an escape code. Here is an incomplete list of possible escape codes:
\\ |
Represents one '\' character.
|
\" |
Represents one '"' character. Needed in strings to represent
this character, because an unescaped '"' would end the string.
|
\n | Newline; for ASCII this is octal code 012. |
\b | Backspace; for ASCII this is octal code 010. |
\f | FormFeed; for ASCII this is octal code 014. |
\r | Carriage-Return; for ASCII this is octal code 015. |
\t | Horizontal Tab; for ASCII this is octal code 011. |
\ddd | An octal character code. The numeric code is 3 octal digits. |
\xdd... | A hex character code. All trailing hex digits are combined. |
An ellipsis ('...'
) consists of three successive periods with no whitespace
intervening.
You can use an ellipsis in the formal argument lists of function prototypes
to indicate a variable number of arguments, or arguments with varying types.
For example,
void func (int n, char ch, ...);
This declaration indicates that func will be defined in such a way that
calls must have at least two arguments, an int and a char, but can also have
any number of additional arguments.
Note: The GNU C extends the usage of ellipsis for making
case ranges and for
labeling elements in initializers.
The typecast operator forces an expression to behave as an object of a given type. It uses the following syntax:
(type) expr
The expression expr will be interpreted as having type type. It may be any simple type (modified or unmodified), enumeration, structure, union, user defined type created using typedef, void type, or an anonymous type (see asterisk for more information about anonymous types). Here is an example list of valid typecast operators:
(int) (unsigned long int) (signed) (enum foo) (struct foo) (mytype) assuming that 'mytype' is defined with 'typedef' (void) (char *) (void *) (struct foo *) (void (*)(int)) (int (*[])(char*))
Typecast operator is very powerful in C, and may be used for conversion nearly everything
to anything. For example, it is legal to convert an integer value to a pointer, so you
can perform direct access to the memory (don't do this if you don't know exactly what are you
doing). For example, '(char*)19456'
converts integer 19456 to a char pointer, which
may be dereferenced further using the dereference operator. So,
* (char*)19456 = 255;
stores 255 in the memory at the absolute address 19456 (this is the first byte of the LCD memory on TI-89 and TI-92+). The more drastic example is
((void(*)())10000)();
which calls the subroutine located at absolute address 10000 (first, the typecast operator
'(void(*)())'
converts 10000 to the pointer to the function, then the
parentheses operator '()'
is used to call the function).
Note that nearly the whole TIGCC library, when used in "nostub" mode,
is implemented using the typecast operator which converts TIOS jump table entries to pointers
to functions. For example, ClrScr is defined as
'(*(void(**)(void))(*(long*)0xC8+0x678))'
, which is nothing other than a complex
typecast. So, when you do
ClrScr ();
in your program, the preprocessor replaces it with
(*(void(**)(void))(*(long*)0xC8+0x678))();
However, typecast operator cannot be used to convert a scalar type to a
structure or union (and vice versa), or to convert one non-scalar type into an incompatible
non-scalar type. That's why casting to structures and unions are rarely valid.
Casting to a void means that you want to discard the result of the expression.
Casting to or from a floating point type are internally executed using the
flt and trunc functions. See the description of
these functions for more info.
Note: GNU C extends the usage of typecast operator to allow making
cast constructors, which are probably the most powerful
GNU C extensions. It also allows much more flexibility in
casting to an union types.
In the following table of operator precedence, the C operators are
divided into 15 categories. The #1 category has the highest precedence;
category #2 (Unary operators) takes second precedence, and so on to the
Comma operator, which has lowest precedence. The operators within each
category have equal precedence.
The Unary (category #2), Conditional (category #13), and Assignment
(category #14) operators associate right-to-left; all other operators
associate left-to-right.
All expressions in C language may be classified to lvalues and
rvalues.
An lvalue is an object locator: an expression that designates an object.
Any variable is an lvalue for example. Another example of an lvalue expression is
'*P'
, where P
is any expression evaluating
to a non-null pointer. See dereference operator for more information.
A modifiable lvalue is an identifier or expression that relates to an object
that can be accessed and legally changed in memory. A const pointer to a constant, for example,
is not a modifiable lvalue. A pointer to a constant can be changed (but its dereferenced value
cannot).
Historically, the "l" stood for "left", meaning that an lvalue could legally
stand on the left (the receiving end) of an assignment statement. Now, only
modifiable lvalues can legally stand on the left of an assignment statement.
For example, if 'a'
and 'b'
are nonconstant integer identifiers with properly
allocated memory storage, they are both modifiable lvalues, and assignments such as
a = 1; b = a + b;
are legal. From the other side, the expression
a + b
is not an lvalue: 'a + b = a'
is illegal because the expression on the left is
not related to an object. Such expressions are often called rvalues (short for "right values").
Note: In GNU C, the class of lvalue expressions is wider than in other C dialects; see section
Generalized Lvalues for more info.