Вы находитесь на странице: 1из 28

1.Character data type.

Declaration and initialization of a character data


type variable.
-Character variable is defined to be of type char. For example: char ch; One character variable
occupies a single byte which contains the code for the character. This code is a numeric value
and depends on the character coding system being used (is machine-dependent). The most
common system is ASCII (American Standard Code for Information Interchange). In C language
does not exist data type string and therefore do not exist variables of string type but it is
possible to process strings. A string in C language represents a set of characters stored in
statically or dynamically allocated 1-D array of character type and terminated by null byte (null
character) and such a set of characters is considered as one object - a string.
A char can be initialized :
For example: char ch = b

2.Functions for inputting a char from the keyboard.


1. scanf( %c, &ch); Note using of format specification %c for character type variable;
2. ch = getchar( ); Note that after pressing a character key on the keyboard it is necessary to
press also the Enter key, because function getchar( ) uses buffer memory of console as the
function scanf( ) does;
3. ch = getch( ); Note that function getch( ) does not use buffer memory what is way after
pressing a character key its value is directly assigned to corresponding character variable ch
without additional pressing the Enter key;
4. ch = getche( ); Function getche( ) defers from function getch( ) only by showing on the
screen a character (echo) introduced from keyboard as functions scanf( ) and getchar( ) do.
Scanf and getchar are in the <stdio.h> , and getch + getche are in <conio.h>

3.Functions for outputting a char from the keyboard


Output (writing) a character on the screen is performed by using standard functions
printf( ), putchar( ) declared in header file stdio.h and function putch( ) declared in header
file conio.h. For example:
printf(%c, ch); or putchar(ch); or putch(ch); for output on the screen a character
stored in the character variable ch;
printf(%c, A); or putchar(A); or putch(A); for output on the screen character A;
printf(%c,\n); or putchar(\n); or putch(\n); for moving the cursor at the beginning of
the new line.

4.One dimensional array of characters and strings in C language.


In C language does not exist data type string and therefore do not exist variables of string type
but it is possible to process strings. A string in C language represents a set of characters stored
in statically or dynamically allocated 1-D array of character type and terminated by null byte
(null character) and such a set of characters is considered as one object - a string.
1-D statically allocated character array can be initialized as any array during declaration 1) by
assigning to it a string literal as we just considered before

1.char color[10] = blue


2) by assigning to it a set of characters ended by null byte.
For example: char color[10] = {b, l, u, e, \0};

5.Functions to input a string from keyboard.


We can use the function that is stored in the <stdio.h> file gets(str)
Its a function that returns a variable which points to the start of the string.
Input (reading) a string of characters from keyboard is performed by using standard function
scanf( ) and gets( ) declared in header file stdio.h. For example, a string can be introduced
from keyboard as follows:
scanf( %s, str);
or
gets(str); where str is the string name (name of character
array or pointer for dynamic array where the string is stored).
Note using of format specification %s in function scanf( ) call and absence of ampersand &
before str in both function calls, because name of string is a pointer( an address). It is also
important that function scanf( ) inputs(reads) a string from keyboard only till the first space, but
function gets( ) can input a string with spaces. It is recommended before functions scanf( ),
getchar( ) and gets( ) calls to use the function fflush(stdin) call for clearing the buffer
memory.

6.Functions to output a string on the screen.


The functions printf() and puts() can be used to output a literal on the screen. But if we
need to output a string that has a pointer pointing to its start we can do it like this
printf(%s, str); or puts(str);
Output (writing ) a string of characters on the screen is performed by using standard
functions printf( ) and puts( ) declared in header file stdio.h. For example:
printf(%s, str); or puts(str); for output on the screen a string named str (name of
character array or pointer for dynamic character array where the string is stored);
printf(Hello, my friends!\n); or puts(Hello, my friends!); for output on the screen
the string Hello, my friends! and for moving the cursor at the beginning of the new line.
printf(\n\n); or puts(\n); for output one blank line and for moving the cursor at the
beginning of the new line.

7.Standard library functions for character and string processing.


Character and string processing.

For character and string processing in C language can be used different functions from standard
library header files ctype.h (character handling library for character processing), stdlib.h
(general utilities library for string conversion functions) and string.h (string handling library for
string processing). Descriptions and examples of using of these functions presented in the Help
option of Main menu of Turbo C++ compiler.
The most useful functions for string processing from header file string.h are:
strlen( ) to determine string length (returns number n of characters in the string str); Ex.:
n=strlen(str);
strcat( ) to join (concatenate) string s1 and string s2 together in one string s1. Ex.:
strcat(s1, s2);
strcpy( ) to copy (assign) contents of string s2 to string s1; Ex.: strcpy(s1, s2);
strcmp( ) to compare string s1 and string s2 (returns k=0 if strings are the same, k<0 if
string s1 < string
s2 (upper in dictionary) and k>0 if string s1 > string s2 (lower in dictionary); Ex.:
k=strcmp(s1, s2);
stricmp( ) this function is the same as strcmp( ) but not case sensitive; Ex.: k =
stricmp(s1, s2);
strrev( ) to reverse the characters in string str; Ex.: strrev(str);
strupr( ) to convert all characters in string str from lowercase to uppercase; Ex.:
strupr(str);
strlwr( ) to convert all characters in string str from uppercase to lowercase; Ex.:
strlwr(str);

8.Classification of data types in C Language.


The C language provides many basic types. Most of them are formed from one of the four basic
arithmetic type specifiers in C (char, int, float and double), and optional specifiers
(signed,unsigned, short, long) . And there are data types defined by user : structures and unions.

Data types in C
1. Fundamental Data Types
o

Integer types

Floating Type

Character types

2. Derived Data Types


o

Arrays

Pointers

Structures

Enumeration

Syntax for declaration of a variable


data_type variable_name;

9.Data types defined by user in C language


Data types defined by user in C language are of 2 types. Structures and unions. Basicly structures and unions are used if
a user wants to group many variables together , but they are of different types , so he cannot use arrays, thus he uses
Structures and Unions.

10.Data type Struct.Declaration of Struct data type specifications and


variables. Using typedef statement.
A structure type is usually defined near to the start of a program using the struct statement or
the typedef statement, allowing its use throughout the program. These statements usually
occur just after the #include statements in a program. Here are two examples of the struct and
typedef specifications:

struct student
{char name[40];
int year;
int clas;
float average;
};
struct student st1, st2 , CL[26],*ps;

typedef struct student


{char name[40];
int year;
int clas;
float average;
} STUDENT;
STUDENT st1, st2 , CL[26], *ps;

These define new data type names struct student and STUDENT and declare variables of structure type. The
purpose of typedef is to form complex types from more-basic machine types and assign simpler names to
such combinations.
Use of typedef with structs

typedef is a powerful tool that allows programmers to define and then use their own data
types. For example:

typedef int Integer;

Integer nStudents, nCourses, studentID;

Note that in the typedef statement, the newly defined type name goes in the place where
a variable name would normally go.

There are a few benefits of using typedef with simple types such as the example above:

For readability, "Integer" may be easier to understand than "int".

The typedef can be easily changed later, ( say to "typedef long int Integer;" ), which
would then affect all variables of the defined type.

However the real benefit of typedef comes into play with complex data structures, such as
structs:

11. Fields of struct data type. Access operation to the fields of structure.
Using typedef statement.
Fields in a structure can be referenced by following the name of the structure by a dot and the
name of the field.
France.population = 0;
You can also declare a pointer to type 'struct country' and use that to reference the fields in a
structure of that type. In this case, you follow the pointer name by an arrow and the name of the
field.
struct country Russia, *sptr;
sptr = &Russia;
sptr->population = 0;
In the example above, Russia is of type 'struct country; sptr is of type 'pointer to struct country';
and sptr->population is of type integer.
Accessing data fields within structs

The dot operator ( period ) is used to access named fields within struct variables:
john.nClasses = 4;
totalGPA += sue.gpa;

Assigning one struct to another

If two variables are of the same struct type, then they can be directly assigned one to the
other.
o

See the variable definitions above to see why some of these are invalid.

( Note: There is a potential problem if the structs contain pointers. See below for
details. )
joe = sue;
mary = carla;
alice = bill;
alice = charlie;

// Legal, both of the same type


// Also legal, both of the same type
// Still legal. Both the same unnamed type
// Illegal.

Different types, even though identical

12. 1-D array of structures. Database in form of 1-D array of stuctures. Set of operations on
database.

Arrays of structures are possible, and are a good way of storing lists of data with regular fields, such as
databases. It is possible to define an array of structures for example if we are maintaining information of all the
students in the college and if 100 students are studying in the college. We can define an array S of structures as
shown in the following example.
typedef struct student
{ char name[40];
int year;
int clas;
float average;
} STUDENT;
STUDENT

S[100];

An array of structures in C language can be used for storing and processing information of the
same elements (structure objects) in a simple database. For creating a database using an array
of structures we have to determine a set of operations on it. Usually this set of operations on
an array of structures database can be represented as follows:

1. dynamic memory allocation for an array of n elements of the given structure.


2. input elements of array of structures from keyboard.
3. output elements of array on the screen.
4. searching an element in array.
5. modifying an element of array.
6. swapping two elements of array.
7. sorting elements of array.
8. writing (saving) elements of array in file.
9. reading (loading) elements of array from file.
10. freeing memory dynamically allocated for array.
11. appending an element to the end of array.
12. inserting an element into array.
13. deleting an element from array.
14. other operations related to determine some information (statistics) from database.

All these operations (options) can be implemented in a C language program for an array of
structures database processing by creating corresponding number of functions (subprograms)
and then by calling them from main( ) function in some order. Usually order and number of
these function calls (order and number of options needed to perform) depend on and are

determined by user during a working session with database. What is why it is necessary to
develop appropriate user interface for communication between user and program.

13. Infinit loop and switch statment for menu of operations on 1-D array of tructures
An array of structures in C language can be used for storing and processing information of the
same elements (structure objects) in a simple database. For creating a database using an array
of structures we have to determine a set of operations on it. Usually this set of operations on
an array of structures database can be represented as follows:

1. dynamic memory allocation for an array of n elements of the given structure.


2. input elements of array of structures from keyboard.
3. output elements of array on the screen.
4. searching an element in array.
5. modifying an element of array.
6. swapping two elements of array.
7. sorting elements of array.
8. writing (saving) elements of array in file.
9. reading (loading) elements of array from file.
10. freeing memory dynamically allocated for array.
11. appending an element to the end of array.
12. inserting an element into array.
13. deleting an element from array.
14. other operations related to determine some information (statistics) from database.

All these operations (options) can be implemented in a C language program for an array of
structures database processing by creating corresponding number of functions (subprograms)
and then by calling them from main( ) function in some order. Usually order and number of
these function calls (order and number of options needed to perform) depend on and are
determined by user during a working session with database. What is why it is necessary to
develop appropriate user interface for communication between user and program.
while( 1 ) // infinite while loop
{
clrscr( );
puts(\n \t \t menu:\n);

puts(\n 1. dynamic memory allocation );


puts(\n 2. input an array from keyboard);

14. Data type union. Declaration of union specification and variables.


Using typedef statement.
A union is the equivalent of an assembler org or a COBOL REDEFINE. It allows you to
handle an area of memory that could contain different types of variables. The syntax
for unions is identical to that for structures. You can use either typedef's or instream
definitions: simply replace the word struct with the word union.
You can contain unions within structures, or structures within unions. Either way, the C
union is an unwieldy mechanism.
A union might be used to group different record layouts from the same file, or to handle
a single field that could contain, for example, either numeric or character data.

typedef struct transaction


{
int

amount;

union
{
int

count;

char

name[4];

} udata;
char

discount;

} Transaction;

A union type definition contains the union keyword followed by an optional identifier (tag) and a
brace-enclosed list of members.
A union definition has the following form:

>>-union--+-identifier--------------------------+--------------><
|

.-----------.

'-+------------+--{----member--;-+--}-'
'-identifier-'
A union declaration has the same form as a union definition except that the declaration has no
brace-enclosed list of members.
The identifier is a tag given to the union specified by the member list. Once a tag is specified,
any subsequent declaration of the union (in the same scope) can be made by declaring the tag
and omitting the member list. If a tag is not specified, all variable definitions that refer to that
union must be placed within the statement that defines the data type.
The list of members provides the data type with a description of the objects that can be stored in
the union.
A union member definition has same form as a variable declaration.
15. Fields of union data type. Access and assignment operations for union data type.
Differenses between struct and union variables.

Difference between Union and Structure


A union is a class all of whose data members are mapped to the same address within its object. The size of an
object of a union is, therefore, the size of its largest data member.
In a structure, all of its data members are stored in contiguous memory locations. The size of an object of a
struct is, therefore, the size of the sum of all its data members.
This gain in space efficiency, while valuable in certain circumstances, comes at a great cost of safety: the
program logic must ensure that it only reads the field most recently written along all possible execution paths.
The exception is when unions are used for type conversion: in this case, a certain field is written and the
subsequently read field is deliberately different.
An example illustrating this point is:
+-----+-----+
gives | a | b |
+-----+-----+
^
^
|
|
memory location: 150
154
|

+-----+
union { int a; float b; } gives | a |
| b |
+-----+
struct { int a; float b; }

Structures are used where an "object" is composed of other objects, like a point object consisting of two
integers, those being the x and y coordinates:
typedef struct {
int x;
int y;
} tPoint;

// x and y are separate

Unions are typically used in situation where an object can be one of many things but only one at a time, such as
a type-less storage system:
typedef enum { STR, INT } tType;
typedef struct {
tType typ;
// typ is separate.
union {
int ival;
// ival and sval occupy same memory.
char *sval;
};
} tVal;

16. Preprocessor directives #include and #define. Macro-definition and pseudo-function

The C Preprocessor
Recall that preprocessing is the first step in the C program compilation stage -- this feature is
unique to C compilers.

The preprocessor more or less provides its own language which can be a very powerful tool to the programmer.
Recall that all preprocessor directives or commands begin with a #.
Use of the preprocessor is advantageous since it makes:

programs easier to develop,

easier to read,

easier to modify

C code more transportable between different machine architectures.

The preprocessor also lets us customise the language. For example to replace { ... } block statements delimiters
by PASCAL like begin ... end we can do:
#define begin {
#define end }

During compilation all occurrences of begin and end get replaced by corresponding { or } and so
the subsequent C compilation stage does not know any difference!!!.
Lets look at #define in more detail

#define
Use this to define constants or any macro substitution. Use as follows:

#define

<macro> <replacement name>

For Example
#define FALSE 0
#define TRUE !FALSE

#include
This directive includes a file into code.
It has two possible forms:
#include <file>
or
#include "file"
<file> tells the compiler to look where system include files are held. Usually UNIX
systems store files in

usr include

directory.

"file" looks for a file in the current directory (where program was run from)
Included files usually contain C prototypes and declarations from header files and not
(algorithmic) C code (SEE next Chapter for reasons)

Macros with arguments must be defined using the #define directive before they can be used. The argument list
is enclosed in parentheses and must immediately follow the macro name. Spaces are not allowed between and
macro name and open parenthesis. For example:
#define MAX(x,y) ((x) > (y) ? (x) : (y))

Macro Caveats:

Macro definitions are not stored in the object file. They are only active for the duration of a single
source file starting when they are defined and ending when they are undefined (using #undef), redefined,
or when the end of the source file is found.

Macro definitions you wish to use in multiple source files may be defined in an include file which may
be included in each source file where the macros are required.

Today, #define is primarily used to handle compiler and platform differences. E.g., a define might hold a
constant which is the appropriate error code for a system call. The use of #define should thus be limited unless
absolutely necessary; typedef statements and constant variables can often perform the same functions more
safely.

Another feature of the #define command is that it can take arguments, making it rather useful as a pseudofunction creator. Consider the following code:
#define ABSOLUTE_VALUE( x ) ( ((x) < 0) ? -(x) : (x) )
...
int x = -1;
while( ABSOLUTE_VALUE( x ) ) {
...
}

It's generally a good idea to use extra parentheses when using complex macros. Notice that in the above
example, the variable "x" is always within its own set of parentheses. This way, it will be evaluated in whole,
before being compared to 0 or multiplied by -1. Also, the entire macro is surrounded by parentheses, to prevent
it from being contaminated by other code. If you're not careful, you run the risk of having the compiler
misinterpret your code.
Because of side-effects it is considered a very bad idea to use macro functions as described above.
int x = -10;
int y = ABSOLUTE_VALUE( x++ );

17. File pointer. Functions fopen() and fclose() for opening and closing a file.
Opening a file.

If we want to store data in a file in the external memory, we must use the following general
format for opening a file:
FILE *fp; fp=fopen(filename,mode); if(fp= =NULL){puts(file was not
oppend); return;}
The first statement declares the variable fp called file pointer to the structure data type FILE
that is defined in the stdio.h. The second statement opens the file named filename of
corresponding mode by using standard function fopen( ) and determines the value of file
pointer fp for the given file. This pointer, which points to the data stracture FILE that contains all
the information about the file, is used as a communication link between the operating system
and the program. The third statement verifies if function fopen( ) returned NULL pointer and if
so it means that file was not opened. The mode of file can be of three main kinds:
r- the file for reading data ; w- the file for writing data; a- the file for appending data.
Consider the following statements:
FILE *fp1, *fp2;
fp2=fopen(results.txt,w);

fp1=fopen(data.txt,r);

In these statements the fp1 and fp2 are created and assigned to open the files data and
results respectively. The file data is opened for reading and results is opened for writing. In
case the file results already exists, its contents are deleted and the file is opened as a new file.
If file data does not exist fp1 recieves

NULL pointer value and file is not opened.

Closing a file.

The input output library stdio.h supports the function to close a file of the following format:
fclose(fp);
A file must be closed as soon as all operations on it have been completed. The function fclose( )
closes the file associated with the file pointer fp.
Observe the following part of program:
FILE *fp1 *fp2;
(results.txt,w);

fclose(fp1);

fp1=fopen (data.txt,r);

fp2=fopen

fclose(fp2);

The above program opens two files and closes them after all operations on them are completed.
Once a file is closed its file pointer can be reversed on other file.
The getc( ) and putc( ) functions are analogous to getchar( ) and putchar( ) functions and
handle one character at a time. The function call putc(ch, fp1 ); writes the character
contained in character variable ch to the file associated with the pointer fp1; similarly the
function getc( ) is used to read a character from a file that has been opened in read mode and
than to assign it to character variable ch = getc(fp2);

The fprintf( ) and fscanf( ) formatted functions for writing in and reading from file.
The fprintf( ) and fscanf( ) formatted functions are identical to printf( ) and scanf( )
formatted functions except that they work on files. The first argument of theses functions is a file
pointer fp which specifies the file to be used. The general form of fprintf( ) function call is:
fprintf(fp, control string, list);

Where fp is a file pointer associated with a file that has been opened for writing. The control string is file output
specifications, list may include variable, constant and string. For example:
fprintf(fp, %s %d %.2f\n, name, age, 7.5);
Here name is a character array, age is an integer variable and 7.5 is a float constant.
The general format of fscanf( ) function call is:
fscanf(fp, control string, list);
This statement would cause the reading of items of list conform the control string. For example:
fscanf(fp, %s%d, item, &quantity);

where item is a character array and quantity is an integer variable.


18. Functions for input and output operations using files.
Reading from or writing to a file:

Once a file has been successfully opened, you can read from it using fscanf() or write to it using fprintf().
These functions work just like scanf() and printf(), except they require an extra first parameter, a FILE *
for the file to be read/written.

Note: There are other functions in stdio.h that can be used to read or write files. Look them up
in a good C reference.

Continuing our example from above, suppose the input file consists of lines with a username and an integer test
score, e.g.:
in.list
-----foo 70
bar 98
...

and that each username is no more than 8 characters long.

We might use the files we opened above by copying each username and score from the input file to the output
file. In the process, we'll increase each score by 10 points for the output file:
char username[9];
int score;

/* One extra for nul char. */

...
while (fscanf(ifp, "%s %d", username, &score) != EOF) {
fprintf(ofp, "%s %d\n", username, score+10);
}
...

The function fscanf(), like scanf(), normally returns the number of values it was able to read in. However,
when it hits the end of the file, it returns the special value EOF. So, testing the return value against EOF is one
way to stop the loop.
The bad thing about testing against EOF is that if the file is not in the right format (e.g., a letter is found when a
number is expected):
in.list
-----foo 70
bar 98
biz A+
...
then fscanf()

will not be able to read that line (since there is no integer to read) and it won't advance to the
next line in the file. For this error, fscanf() will not return EOF (it's not at the end of the file)....

Errors like that will at least mess up how the rest of the file is read. In some cases, they will cause an infinite
loop.
One solution is to test against the number of values we expect to be read by fscanf() each time. Since our
format is "%s %d", we expect it to read in 2 values, so our condition could be:
while (fscanf(ifp, "%s %d", username, &score) == 2) {
...

Now, if we get 2 values, the loop continues. If we don't get 2 values, either because we are at the end of the file
or some other problem occurred (e.g., it sees a letter when it is trying to read in a number with %d), then the loop
will end.
Another way to test for end of file is with the library function feof(). It just takes a file pointer and returns a
true/false value based on whether we are at the end of the file.
To use it in the above example, you would do:
while (!feof(ifp)) {
if (fscanf(ifp, "%s %d", username, &score) != 2)
break;
fprintf(ofp, "%s %d", username, score+10);
}
Note that, like testing != EOF, it might cause an infinite loop if

the format of the input file was not as expected.


However, we can add code to make sure it reads in 2 values (as we've done above).

Note: When you use fscanf(...) != EOF or feof(...), they will not detect the end of the file
until they try to read past it. In other words, they won't report end-of-file on the last valid read,
only on the one after it.
Functions
File access
fopen

opens a file
(function)

freopen

open an existing stream with a different name


(function)

fclose

closes a file
(function)

fflush

synchronizes an output stream with the actual file


(function)

fwide

switches a file stream between wide character I/O and narrow


character I/O
(function)

setbuf

sets the buffer for a file stream

(function)
setvbuf

sets the buffer and its size for a file stream


(function)

Direct input/output
fread

reads from a file


(function)

fwrite

writes to a file
(function)

Unformatted input/output
Narrow character

fgetcgetc

gets a character from a file stream


(function)

fgets

gets a character string from a file stream


(function)

fputcputc

writes a character to a file stream


(function)

fputs

writes a character string to a file stream


(function)

getchar

reads a character from stdin


(function)

gets
(until C++14)

reads a character string from stdin


(function)

putchar

writes a character to stdout


(function)

puts

writes a character string to stdout


(function)

ungetc

puts a character back into a file stream


(function)

Wide character

fgetwcgetwc

gets a wide character from a file stream


(function)

fgetws

gets a wide string from a file stream


(function)

fputwcputwc

writes a wide character to a file stream


(function)

fputws

writes a wide string to a file stream


(function)

getwchar

reads a wide character from stdin


(function)

putwchar

writes a wide character to stdout


(function)

ungetwc

puts a wide character back into a file stream


(function)

Formatted input/output
Narrow/multibyte character

scanffscanfsscanf
vscanfvfscanfvsscanf
(C++11)(C++11)(C++11)
printffprintfsprintfsnprintf
(C++11)

reads formatted input from stdin, a file stream or a buffer


(function)
reads formatted input from stdin, a file stream or a buffer
using variable argument list
(function)
prints formatted output to stdout, a file stream or a buffer
(function)

vprintfvfprintfvsprintfvsnpri prints formatted output to stdout, a file stream or a buffer


ntf
using variable argument list
(function)
(C++11)
Wide character

wscanffwscanfswscanf

vwscanfvfwscanfvswscanf
(C++11)(C++11)(C++11)

reads formatted wide character input from stdin, a file stream or a


buffer
(function)
reads formatted wide character input from stdin, a file stream
or a buffer using variable argument list
(function)

wprintffwprintfswprintf

prints formatted wide character output to stdout, a file stream or a


buffer
(function)

vwprintfvfwprintfvswprintf

prints formatted wide character output to stdout, a file stream


or a buffer using variable argument list
(function)

File positioning
ftell

returns the current file position indicator


(function)

fgetpos

gets the file position indicator


(function)

fseek

moves the file position indicator to a specific location in a file


(function)

fsetpos

moves the file position indicator to a specific location in a file


(function)

rewind

moves the file position indicator to the beginning in a file


(function)

Error handling
clearerr

clears errors
(function)

feof

checks for the end-of-file


(function)

ferror

checks for a file error


(function)

perror

displays a character string corresponding of the current error to


stderr
(function)

Operations on files
remove

erases a file
(function)

rename

renames a file
(function)

tmpfile

creates and opens a temporary, auto-removing file


(function)

tmpnam

returns a unique filename


(function)

Types
Defined in header <cstdio>
Type Definition
FILE

type, capable of holding all information needed to control a C I/O stream

fpos_t

non-array type, capable of uniquely specifying a position in a file, including its multibyte
parse state

19. Bitwise operations in C language

Bitwise operators are special types of operators that are used in programming the processor. In processor,
mathematical operations like: addition, subtraction, addition and division are done using the bitwise operators
which makes processing faster and saves power.

The Bitwise operators supported by C language are listed in the following table. Assume variable A holds 60
and variable B holds 13, then:

Operator

Description
Example
Binary AND Operator copies a bit to the result if it exists in (A & B) will give 12 which is 0000
&
both operands.
1100
(A | B) will give 61 which is 0011
|
Binary OR Operator copies a bit if it exists in either operand.
1101
Binary XOR Operator copies the bit if it is set in one
(A ^ B) will give 49 which is 0011
^
operand but not both.
0001
(~A ) will give -61 which is 1100 0011
Binary Ones Complement Operator is unary and has the
~
in 2's complement form due to a
effect of 'flipping' bits.
signed binary number.
Binary Left Shift Operator. The left operands value is moved A << 2 will give 240 which is 1111
<<
left by the number of bits specified by the right operand.
0000
Binary Right Shift Operator. The left operands value is
A >> 2 will give 15 which is 0000
>>
moved right by the number of bits specified by the right
1111
operand.
20. Operators for bitwise logical operations

Four of the bitwise operators have equivalent logical operators. They are equivalent in that they have the same
truth tables. However, logical operators treat each operand as having only one value, either true or false, rather
than treating each bit of an operand as an independent value. Logical operators consider zero false and any
nonzero value true. Another difference is that logical operators perform short-circuit evaluation.
The table below matches equivalent operators and shows a and b as operands of the operators.
Bitwise

Logical

a & b

a && b

a | b

a || b

a ^ b

a != b

~a

!a

has the same truth table as ^ but unlike the true logical operators, by itself != is not strictly speaking a logical
operator. This is because a logical operator must treat any nonzero value the same. To be used as a logical
operator != requires that operands be normalized first. A logical not applied to both operands wont change the
truth table that results but will ensure all nonzero values are converted to the same value before comparison.
This works because ! on a zero always results in a one and ! on any nonzero value always results in a zero.
!=

The example below shows that the truth tables for these Bitwise and Logical operators are identical but also
demonstrates how they act on their operands differently. The need to normalize operands for != can be
demonstrated by introducing a char T2 = 0x02 and packing it in an array. Mixing T2 with T will show them
being treated the same unless the operand NOTs around != are removed.

21. Operators for bitwise shifting operations


In C-inspired languages, the left and right shift operators are "<<" and ">>", respectively. The number of places
to shift is given as the second argument to the shift operators. For example,
x = y << 2;

assigns x the result of shifting y to the left by two bits.


In C, the result of right-shifting a negative value is implementation-defined, and the result of left-shifting a
signed value is undefined if the result cannot be represented in the result type.
Left shift

Literally shifts the bits of the operand to the left.

For example, if b1 and b2 are unsigned char then


b2 = b1 << 2;
results in

b1

00011010

b2

01101000 104

26

Bits shifted out of the MSB are lost, bits shifted in through the LSB are always zero.

Notice b2 is equal to b1*4. Left shift performs multiplication by 2^n.


Right shift

Right shift is a little more complicated.

Shifts bits of the operand to the right.

Bits shifted out of the LSB are lost.

Bits shifted in through the MSB are

or

always 0 if the number is unsigned

either 1 ("right shift arithmetic")

x >> n

0 ("right shift logical") if the sign bit is 1 (i.e. signed)

signed char x = -75;

/* 1011 0101 */

signed char y = x >> 2;

/* 0010 1101 (logical shift) */

/* 1110 1101 (arithmetic shift) */

Result is implementation dependent (ie, different on different machines). Above example is 45 on


logical-shift machine, and -19 on an arithmetic shift machine.

It is usually preferred to use unsigned types for bitwise operations to avoid non-portable behaviour.

Note: right shift is equivalent to division by 2^n if operand is non-negative or machine uses arithmetic
right-shift.

22. Argument of function main()

Passing Arguments to

main()

is passed two arguments from the shell: an integer and a pointer to an array of strings. Traditionally
these are declared as follows:
main()

int main(int argc,char *argv[])

Here argc (``argument count'') contains one plus the number of arguments passed to the program from the
command line and argv (``argument vector'') contains a series of char pointers to these arguments. The first
element in argv is always the name of the program itself, so argc is always at least 1. The library function
getopt() can perform simple parsing of command-line arguments; see the listing in section 3c of the man
pages. Here's a more simple example of passing two numbers and a string. Note the error trapping to force the
user to conform to the expected usage:
#include <stdio.h>
#include <stdlib.h> /* for atoi() */
int main(int argc,char *argv[]) {
int m,n;
if (argc != 4) {
printf("Usage: %s m n filename\n",argv[0]);
return 1;
}
m = atoi(argv[1]); /* convert strings to integers */
n = atoi(argv[2]);
printf("%s received m=%i n=%i filename=%s\n",argv[0],m,n,argv[3]);
return 0;
}

23. Dynamic memory allocation 1-D array


To allocate dynamically a similar 1-D array having number of elements introduced from keyboard
the
following code is recommended:

int

*A, n;

printf(Enter number of elements of array: );

scanf(%d, &n);
A = (int*) malloc( n* sizeof(int) ); // or
if (A == NULL)

// or shorter

A = (int*) malloc( n*sizeof(*A) );

if ( !A)

{
puts( \n Memory was not allocated); // or using here return statement
}

After this code it is possible to use allocated memory having access to it by means of pointer A
which
can be used as name of dynamic array.
There are 2 kinds of memory allocation in C/C++ languages: a) static memory allocation and b)
dynamic memory allocation.
Static memory allocation refers to the process of allocating memory for the named variables at
compile time before the corresponding program is executed. Static memory allocation is
performed by compiler conform variable declaration statements for global and local variables.
Global variables, constants (specified by keyword const) and static memory class local variables
(specified by keyword static) having lifetime of a whole program are allocated in fixed memory,
but automatic memory class local variables (specified by keyword auto or by default) having
lifetime of a function call are allocated on the stack (is a part of computer memory where data is
added and removed in a Last-In-First-Out (LIFO) manner). Memory allocated statically can not be
reallocated or freed (deallocated) by program itself (by programmer).
Dynamic memory allocation is the allocation memory for the unnamed dynamic variables at
runtime,
during program execution. In C language dynamic memory allocation is performed by program
itself (by programmer) using special functions of standard library header file stdlib.h . Dynamic
memory is allocated from a large part of unused memory area called the heap (also called the
free store ). Dynamic memory is allocated, accessed, managed, reallocated and freed at runtime
by using pointer variables just allocated statically before at compile time.
Functions malloc( ) and free( ).
The function malloc( ) is the basic function used to allocate memory on the heap (on the free
store) in C language. Its prototype is:
void* malloc(int size);
where void* is the type of function which represents void pointer type of returning value and
size is the parameter variable name which represents the size of the block of memory needed in
bytes.
If the allocation is performed successfully, function malloc( ) returns the beginning address (of
void pointer type) of the block of memory allocated. Note that because malloc( ) function returns
a void pointer it is recommended to cast the type of returning value of function malloc( ) to a
needed pointer type especially for compatibility of C language programs with C++ language
programs.
If the allocation is not performed successfully function malloc( ) returns the NULL pointer value
to indicate that no memory was allocated and usually in this case the program execution is
terminated.
Memory allocated by malloc( ) function will continue to exist until the program terminates or
the memory explicitly deallocated by the programmer ( that is, the block is said to be freed).
This is achieved by use of the function free( ). Its prototype is:
void free ( void* p);

where p is the void pointer parameter for the beginning address of the block of memory just
allocated before by malloc( ) function or other functions used for dynamic memory allocation.
After free( ) function call, the memory pointed to by p is not more available for the program and
what is why, it is strictly recommended to assign NULL pointer value to the pointer p immediately
after free( ) function call.

24.Pointers and Arrays

In C/C++ languages the name (identifier) of an array is equivalent to the address of its first
element ,so in fact they are the same concept. For example, supposing these two declarations:
int A[20]; int * p;
The following assignment operations would be valid and equivalent: a) p=A; b) p=&A[0];
After that, p and A would be the same and would have the same properties so, that name of
pointer p can be used as another name of array A. The only difference is that we could change
the value of pointer p by another one, whereas A will always point to the first of the 20 elements
of type int with which it was defined. Therefore, unlike p, which is an ordinary pointer, A is an
array, and an array can be considered a constant pointer.
Therefore, the following assignments would not be valid: A=p; A=A+1;
Because A is an array, so it operates as a constant pointer, and we cannot assign values to
constants.
Concerning 1-D arrays we used square brackets [ ] in order to specify the index (subscript) of
an element of the 1-D array to which we wanted to refer. Well, this square brackets operator [ ]
or the indexation operator is also a dereferencing operator known as offset operator. It
dereferences the variable (name of array or pointer) it follows just as the dereferencing pointer
operator * does after adding the subscript to the name of array and thus obtaining the memory
address of the corresponding element.
So, the expression A[5] is equivalent to the expression * (A+5) both represents the value
of the 6-th element of int type counted from the starting address A. Analogically, expressions
&A[5] and (A+5) are equivalent and both represent the address of the memory where this
element is stored.
Pointers to Pointers
C allows the use of pointers that point to pointers, that these, in its turn, point to
data (or even to other pointers). In order to do that, we only need to add an asterisk
(*) for each level of reference in their declarations:
char a;
char * b;
char ** c;
a = 'z';
b = &a;
c = &b;
This, supposing the randomly chosen memory locations for each variable of 7230,
8092 and 10502, could be represented as:

The value of each variable is written inside each cell; under the cells are their
respective addresses in memory.
The new thing in this example is variable c, which can be used in three different levels
of indirection, each one of them would correspond to a different value:
- c has type char** and
a value of 8092
- *c has type char* and
a value of 7230
- **c has type char and
a value of 'z'
A NULL pointer is a regular pointer of any pointer type which has a special value that
indicates that it is not pointing to any valid reference or memory address.
int * p;
p = NULL;// p has a NULL pointer value
Do not confuse NULL pointers with void pointers. A null pointer is a value that any
pointer may take to represent that it is pointing to "nowhere", while a void pointer is
a special type of pointer that can point to somewhere without a specific type.

27.

Dynamically Allocating Multidimensional Arrays

We've seen that it's straightforward to call malloc to allocate a block of memory which can simulate an array,
but with a size which we get to pick at run-time. Can we do the same sort of thing to simulate multidimensional
arrays? We can, but we'll end up using pointers to pointers.
If we don't know how many columns the array will have, we'll clearly allocate memory for each row (as many
columns wide as we like) by calling malloc, and each row will therefore be represented by a pointer. How will
we keep track of those pointers? There are, after all, many of them, one for each row. So we want to simulate an
array of pointers, but we don't know how many rows there will be, either, so we'll have to simulate that array (of
pointers) with another pointer, and this will be a pointer to a pointer.
This is best illustrated with an example:
#include <stdlib.h>
int **array;
array = malloc(nrows * sizeof(int *));
if(array == NULL)
{
fprintf(stderr, "out of memory\n");
exit or return
}
for(i = 0; i < nrows; i++)
{
array[i] = malloc(ncolumns * sizeof(int));
if(array[i] == NULL)
{
fprintf(stderr, "out of memory\n");
exit or return
}
}

is a pointer-to-pointer-to-int: at the first level, it points to a block of pointers, one for each row. That
first-level pointer is the first one we allocate; it has nrows elements, with each element big enough to hold a
pointer-to-int, or int *. If we successfully allocate it, we then fill in the pointers (all nrows of them) with a
pointer (also obtained from malloc) to ncolumns number of ints, the storage for that row of the array. If this
isn't quite making sense, a picture should make everything clear:
array

Once we've done this, we can (just as for the one-dimensional case) use array-like syntax to access our
simulated multidimensional array. If we write
array[i][j]
we're asking for the i'th

pointer pointed to by array, and then for the j'th int pointed to by that inner pointer.
(This is a pretty nice result: although some completely different machinery, involving two levels of pointer
dereferencing, is going on behind the scenes, the simulated, dynamically-allocated two-dimensional ``array'' can
still be accessed just as if it were an array of arrays, i.e. with the same pair of bracketed subscripts.)
If a program uses simulated, dynamically allocated multidimensional arrays, it becomes possible to write
``heterogeneous'' functions which don't have to know (at compile time) how big the ``arrays'' are. In other
words, one function can operate on ``arrays'' of various sizes and shapes. The function will look something like
func2(int **array, int nrows, int ncolumns)
{
}
function does accept a pointer-to-pointer-to-int, on the assumption

This
that we'll only be calling it with
simulated, dynamically allocated multidimensional arrays. (We must not call this function on arrays like the
``true'' multidimensional array a2 of the previous sections). The function also accepts the dimensions of the
arrays as parameters, so that it will know how many ``rows'' and ``columns'' there are, so that it can iterate over
them correctly. Here is a function which zeros out a pointer-to-pointer, two-dimensional ``array'':
void zeroit(int **array, int nrows, int ncolumns)
{
int i, j;
for(i = 0; i < nrows; i++)
{
for(j = 0; j < ncolumns; j++)
array[i][j] = 0;
}
}

Finally, when it comes time to free one of these dynamically allocated multidimensional ``arrays,'' we must
remember to free each of the chunks of memory that we've allocated. (Just freeing the top-level pointer, array,
wouldn't cut it; if we did, all the second-level pointers would be lost but not freed, and would waste memory.)
Here's what the code might look like:
for(i = 0; i < nrows; i++)
free(array[i]);
free(array);

28. As we defined before (see lecture 2) a composed or structured variable represents named
location in the
memory of computer, where more than one value can be stored. There are
different kinds of composed variables which are also called data structures. One of these kinds is
an array.
In programming, an array is a composed variable or a data structure, which represents
named set of values ( also called elements or components) of the same type, located in the
memory of computer
continuously one after one. Arrays are very often used in programming for storing and
processing data.
In mathematics arrays are known as matrices and are used for solving different problems.
Usually in computer programming are used one-dimensional (1-D) and two-dimensional (bedimensional) arrays (2-D). Dimension of an array depends on the number of integer values called
indices (subscripts) used for determining the position of a given element and for accessing to the
corresponding element. One subscript is used for indicating elements of 1-D array (vector) and
two subscripts are used for elements of 2-D array(matrix). In mathematics 1-D arrays also called
vectors represent special kind of
matrices (2-D arrays) having only one line (row) or one column.
In C/C++ languages indices (subscripts) are enclosed in square brackets [ ] represented the
indexation
operator. In C/C++ languages values of subscripts start by 0.

Ex.: A[0] is the first element of an 1-D array named A;


B[3] is the forth element of an 1-D array named B;
C[2][3] is an element of the third row(line) and of the fourth column of an 2-D array
named C;

Array declaration and initialization

The general form of an array declarations in C/C++ languages are following:


for 1-D array is

type name[size(length) of array or number of elements];

and for 2-D array

type name[number of rows(lines)][number of columns];

Ex.: int A[20];


float B[50];

char C[10][30];
Arrays can be initialized during declaration in such a way:
int A[5]={3,-5,6,7, 0};
float B[2][3]={ {3.2, 2.5, 0},{-5.3, 9, 47.55 } };
or float B[2][3]={ 3.2, 2.5, 0, -5.3, 9, 47.55 };

Usually initialization of arrays is effectuated in run time by different ways, for


example by input elements from keyboard or from existing file or by using special
random function(program) for generating elements of an array.

30. Recursive function


A function can be called not only from by other function by also by itself. Such functions
are called recursive . A recursive function must have mandatory some condition to stop
the recursion, otherwise it will call itself till stack overflow occurs.
Example:
unsigned int Factorial (unsigned int a)
{
if (a<2) return a;
return a*Factorial(a-1);
}

The function factorial() gets called from main() with number having the value 4 as the
argument.
Within the factorial() function itself, because the argument is greater than 1, the
statement executed is: return a*Factorial(a-1);
This is the second return statement in the function, and it calls factorial() again with the
argument value 3 from within the arithmetic expression. This expression cant be
evaluated, and the return cant be completed until the value is returned from this call to
the function factorial() with the argument 3.
This continues until the argument in the last call of the factorial() function is 1. In this
case, the first return statement return a; is executed and the value 1 is returned to the
previous call point. This call point is, in fact, inside the second return in the factorial()
function, which can now calculate 2 * 1 and return to the previous call.
In this way, the whole process unwinds, ending up with the value required being returned
to main().

Вам также может понравиться