You are on page 1of 258

C is a relatively minimalist programming language that operates close to the hardware, and is more similar to assembly language than

most high-level languages are. Indeed, C is sometimes referred to as "portable assembly," reflecting its important difference from low-level languages such as assembly languages: C code can be compiled to run on almost any computer, more than any other language in existence, while any given assembly language runs on at most a few very specific models of computer. For these reasons C has been called a medium-level language. We briefly list some of C's characteristics that define the language and also have lead to its popularity as a programming language. Naturally we will be studying many of these aspects throughout the course.
Programming Language Book IT Training Certification Guides Online Books & Courses at SkillSoft
www.skillsoft.com Ads by Google

Java Programming Google is Looking for Java Experts for Hyderabad/Bangalore. Apply Now!
www.Google.co.in/jobs

Online Video Tutorials Pro Software Tuts Unbeatable Value Flash, Excel, Dreamweaver & More
www.quantunet.com

Selective gas sensors For dissolved CO2, N2, He, H2 and D2 low level measurement
www.hachultra.com

Small size Extensive use of function calls Loose typing -- unlike PASCAL Structured language Low level (BitWise) programming readily available Pointer implementation - extensive use of pointers for memory, array, Structures and functions

C has now become a widely used professional language for various reasons.

It has high-level constructs. It can handle low-level activities. It produces efficient programs. It can be compiled on a variety of computers.

Its main drawback is that it has poor error detection which can make it off putting to the beginner. However diligence in this matter can pay off handsomely since having learned

the rules of C we can break them. Not many languages allow this. This if done properly and carefully leads to the power of C programming.
A Brief History of C

C is a general-purpose language which has been closely associated with the UNIX operating system for which it was developed - since the system and most of the programs that run it are written in C. Many of the important ideas of C stem from the language BCPL, developed by Martin Richards. The influence of BCPL on C proceeded indirectly through the language B, which was written by Ken Thompson in 1970 at Bell Labs, for the first UNIX system on a DEC PDP-7. BCPL and B are "type less" languages whereas C provides a variety of data types. In 1972 Dennis Ritchie at Bell Labs writes C and in 1978 the publication of The C Programming Language by Kernighan & Ritchie caused a revolution in the computing world In 1983, the American National Standards Institute (ANSI) established a committee to provide a modern, comprehensive definition of C. The resulting definition, the ANSI standard, or "ANSI C", was completed late 1988.

UNIX developed c. 1969 -- DEC PDP-7 Assembly Language BCPL -- a user friendly OS providing powerful development tools developed from BCPL. Assembler tedious long and error prone. A new language ``B'' a second attempt. c. 1970. A totally new language ``C'' a successor to ``B''. c. 1971 By 1973 UNIX OS almost totally written in ``C''

C program can be viewed as a block of building blocks called functions. A function is a subroutine that may include one or more statement designed to perform a specific task.

To write a C program we first create a function and then put them together. A C program may contain one or more section as below. Documentation Section Link Section Definition Section Global Declaration Section main() Function Section { Declaration Part Executable Part } Subprogram section Function 1 Function 2 Function n Documentation section consist of set of comment, purpose of the program, Program logic etc. The link section provide instruction to the compiler to link function from the system library. The definition section define all symbolic constants. There are some variable that are used in more than one function such variable are called global variable and are declared in the global declaration section that is outside of the functions. Every C program must have one main() function section. This section contains two parts declaration part and executable part. The declaration part declare all the variable used in the executable part. There is at lest one statement in the executable part. These two part must appear between the opening and the closing brace. The program execution begin at

the opening braces and end in the closing brace. The closing brace of the main function section is the logical end of the program. All statement in the declaration section and executable parts end with semicolon. The subprogram section contain all the user-defined function that are called in the main function.User defined functions are generally placed immediately after the main function. Although they may apper any order.
C's Character Set

C does not use, nor requires the use of, every character found on a modern computer keyboard. The only characters required by the C Programming Language are as follows:

A-Z a -z 0-9 space . , : ; ' $ " # % & ! _ {} [] () < > | +-/*=

The use of most of this set of characters will be discussed throughout the course.
C Language Keywords

The following names are reserved by the C language. Their meaning is already defined, and they cannot be re-defined to mean anything else.

auto do for return typedef

break goto short union

case if sizeof

char enum int static

continue default extern long struct volatile float register switch while

double else

unsigned void

Other than these names, you can choose any names of reasonable length for variables, functions etc. The names must begin with a letter or underscore (letters are better), and then can contain letters, numbers and underscores.

Running C Program

Developing a program in a compiled language such as C requires at least four steps: 1. 2. 3. 4. editing (or writing) the program compiling it linking it executing it

We will now cover each step separately.

Editing

You write a computer program with words and symbols that are understandable to human beings. This is the editing part of the development cycle. You type the program directly into a window on the screen and save the resulting text as a separate File. This is often referred to as the source File (you can read it with the TYPE command in DOS or the cat command in unix). The custom is that the text of a C program is stored in a File with the extension .c for C programming language
Compiling

You cannot directly execute the source File. To run on any computer system, the source File must be translated into binary numbers understandable to the computer's Central Processing Unit (for example, the 80*87 microprocessor). This process produces an intermediate object File - with the extension .obj, the .obj stands for Object.
Linking

The first question that comes to most peoples minds is Why is linking necessary? The main reason is that many compiled languages come with library routines which can be added to your program. Theses routines are written by the manufacturer of the compiler to perform a variety of tasks, from input/output to complicated mathematical functions. In the case of C the standard input and output functions are contained in a library (stdio.h) so even the most basic program will require a library function. After linking the file extension is .exe which are executable files.

Executable files

Thus the text editor produces .c source files, which go to the compiler, which produces .obj object files, which go to the linker, which produces .exe executable file. You can then run .exe files as you can other applications, simply by typing their names at the DOS prompt or run using windows menu.
Using Microsoft C Edit stage:

Type program in using one of the Microsoft Windows editing packages.


Compile and link:

Select Building from Make menu. Building option allows you to both compile and link in the same option. Execute: Use the Run menu and select Go option. Errors: First error highlighted. Use Next Error from Search menu for further errors if applicable. If you get an error message, or you find that the program doesn't work when you finally run it (at least not in the way you anticipated) you will have to go back to the source file the .c file - to make changes and go through the whole development process again!
Using Unix

Please note that Unix is a case sensitive operating system and files named firstprog.c and FIRSTPROG.c are treated as two separate files on these system. By default the Unix system compiles and links a program in one step, as follows: cc firstprog.c This command creates an executable file called a.out that overwrites any existing file called a.out. Executable files on Unix are run by typing their name. In this case the program is run as follows a.out To change the name of the executable file type: cc -o firstprog firstprog.c This produces an executable file called firstprog which is run as follows: firstprog

On all Unix systems further help on the C compiler can be obtained from the on-line manual. Type man cc
Conditional Operator: ? :

Syntax of Conditional operators is logical-or-expression ? expression : conditional-expression The conditional operator (? :) is a ternary operator (it takes three operands). The conditional operator works as follows

The first operand is implicitly converted to bool. It is evaluated and all side effects are completed before continuing. If the first operand evaluates to true (1), the second operand is evaluated. If the first operand evaluates to false (0), the third operand is evaluated.

The result of the conditional operator is the result of whichever operand is evaluated the second or the third. Only one of the last two operands is evaluated in a conditional expression. #include<stdio.h> void main() { int a,b; printf("Enter value of a); scanf("%d",&a); printf("Enter value of b); scanf("%d",&b); (a>b)?printf("%d is big",a):printf("%d is big",b); getch(); } BITWISE OPERATORS C has a distinction of supporting special operators known as bitwise operators for manipulation of data at bit level. These operators are used for testing the bits, or shifting

them right or left. Bitwise operators may not be applied to float or double. Bitwise operators are Operators & | ^ << >> ~ More about bitwise operators User Defined Type Declaration C support the feature known as type definition that allows user to define an identifier that would represent an exiting data type. The user defined datatype isentifier can later be used to declare variables. It takes the general form. typedef type identifier; Where type refers to an existing data type may belong to any class of type , including the user defined ones. Remember that the new type is 'new' only in name , but not the data type. typedef can not create a new type. Some example of type definition are typedef int unit; typedef float marks; Here , unit symbolizes int and mark symbolizes folat. They can be later used to declare variables as follows. units batch1, batch2; marks name1[50], name2[50]; Bacth1 and batch2 are declare as int variable and name1[50] and name2[50] are declared as 50 element of floating point array variables. The main advantage of typedef is that we can create meaningful data type name for increasing the readability of the program Meaning bitwise AND bitwise OR bitwise exclusive OR Shift left Shift right One's complement

Another user-defined data type is enumerated data type provided by ANSI standard. It is defined as follows. enum identifier { value1,value2,....valuen }; The identifier is user -defined enumerated data type which can be used to declare variable that can have one of the value enclosed with in the braces ( known as enumeration constant). After this we can declare variables to be of this new type as below.

enum identifier v1,v2,...vn. The enumerated variable v1,v2,..vn can only have one of the following types are valid; v1= value3; v3= value1; An example

enum day { Monday, Tuesday,...,Sunday}; enum day week_st, Week_end; Weel_st= Monday; week_end= Friday; if(week_st==Tuesday) week_end=Saturday; The compiler automatically assign integer digit beginning with 0 to all the enumeration constants that is , the enumeration constant value1 is assign 0, value 1 , and so on. However the automatic assignment can be overridden by assigning values explicitly to the enumeration constant For example enum day { Monday=1, Tuesday,...Sunday };

Here, the constant Monday is assigned the value of 1. The remaining constants are assigned values that increase successively by 1. The definition and deceleration of enumerated variable can be combined in one statement enum day { Monday,....Sunday} Week_st, Week_end;

Variables and Data Type

The first thing you need to know is that you can create variables to store values in. A variable is just a named area of storage that can hold a single value (numeric or character). Every variable has a name and a value. The name identifies the variable, the value stores data. There is a limitation on what these names can be. Every variable name in C must start with a letter, the rest of the name can consist of letters, numbers and underscore characters. No Space allowed in variable name. C recognizes upper and lower case characters as being different. Finally, you cannot use any of C's keywords like main, while, switch etc as variable names. It demands that you declare the name of each variable that you are going to use and its type, or class, before you actually try to do anything with it. There are five basic data types associated with variables
int float

integer: a whole number. floating point value: ie a number with a fractional part. a single character. valueless special purpose type which we will examine closely in later sections.

double - a double-precision floating point value. char void -

Integer Number Variables The first type of variable we need to know about is of class type int - short for integer. An int variable can store a value in the range -32768 to +32767. You can think of it as a largish positive or negative whole number: no fractional part is allowed. To declare an int

you use the instruction: int variable name; For example: int a; declares that you want to create an int variable called a.To assign a value to our integer variable we would use the following C statement. a=10; The C programming language uses the "=" character for assignment. A statement of the form a=10; should be interpreted as take the numerical value 10 and store it in a memory location associated with the integer variable a. The "=" character should not be seen as an equality otherwise writing statements of the form: a=a+10; This statement should be interpreted as take the current value stored in a memory location associated with the integer variable a; add the numerical value 10 to it and then replace this value in the memory location associated with a.
Decimal Number Variables

As described above, an integer variable has no fractional part. Integer variables tend to be used for counting, whereas real numbers are used in arithmetic. C uses one of two keywords to declare a variable that is to be associated with a decimal number: float and double. They are each offer a different level of precision as outlined below.
float

A float, or floating point, number has about seven digits of precision and a range of about 1.E-36 to 1.E+36. A float takes four bytes to store.
double

A double, or double precision, number has about 13 digits of precision and a range of about 1.E-303 to 1.E+303. A double takes eight bytes to store. For example: float total;

double sum; To assign a numerical value to our floating point and double precision variables we would use the following C statement. total=0.0; sum=12.50; Before you can use a variable you have to declare it. As we have seen above, to do this you state its type and then give its name. For example, int i; declares an integer variable. You can declare any number of variables of the same type with a single statement. For example: int a, b, c; Here is an example program that includes some of the concepts outlined above. It includes a slightly more advanced use of the printf function which will covered in detail in the next part of this course:

main() { int a,b,average; a=10; b=6; average = ( a+b ) / 2 ; printf("Here "); printf("is "); printf("the "); printf("answer... "); printf("\n"); printf("%d.",average); } Here is the answer... 8
Character Variables

C only has a concept of numbers and characters. It very often comes as a surprise to some programmers who learnt a beginner's language such as BASIC that C has no understanding of strings but a string is only an array of characters and C does have a concept of arrays which we shall be meeting later in this course. To declare a variable of type character we use the keyword char. - A single character stored in one byte. For example char c; To assign, or store, a character value in a char data type is easy - a character variable is just a symbol enclosed by single quotes. For example, if c is a char variable you can store the letter A in it using the following C statement.

c='A'

Notice that you can only store a single character in a char variable. Later we will be discussing using character strings, which has a very real potential for confusion because a string constant is written between double quotes. But for the moment remember that a char variable is 'A' and not "A".
Constants

ANSI C allows you to declare constants. When you declare a constant it is a bit like a variable declaration except the value cannot be changed. The const keyword is to declare a constant, as shown below. int const a = 1; const int a =2; The preprocessor #define is another more flexible (see Preprocessor Chapters) method to define constants in a program. You frequently see const declaration in function parameters. This says simply that the function is not going to change the value of the parameter. The following function definition used concepts we have not met (see chapters on functions, strings, pointers, and standard libraries) but for completenes of this section it is is included here: void strcpy(char *buffer, char const *string)
Assignment Statement

The easiest example of an expression is in the assignment statement. An expression is evaluated, and the result is saved in a variable. A simple example might look like
y = (m * x) + c

This assignment will save the value of the expression in variable y.

Arithmetic operators

Here are the most common arithmetic operators + Addition * / Subtraction Multiplication Division

% Modulo Reduction *, / and % will be performed before + or - in any expression. Brackets can be used to force a different order of evaluation to this. Where division is performed between two integers, the result will be an integer, with remainder discarded. Modulo reduction is only meaningful between integers. If a program is ever required to divide a number by zero, this will cause an error, usually causing the program to crash. Here are some arithmetic expressions used within assignment statements.
velocity = distance / time; force = mass * acceleration; count = count + 1;

C has some operators which allow abbreviation of certain types of arithmetic assignment statements Shorthand i++; or ++i; i--; or --i; Equivalent i=i+1; i=i-1;

These operations are usually very efficient. They can be combined with another expression. x= a *b++; is equivalent to x= a * b, b=b+1; Versions where the operator occurs before the variable name change the value of the variable before evaluating the expression, so x=-- i * ( a + b) is equivalent to x= i-1; x= i * (a+ b) These can cause confusion if you try to do too many things on one command line. You

are recommended to restrict your use of ++ and - to ensure that your programs stay readable. Shorthand i +=10 i -=10 i *=10 i /=10 Equivalent i = i+10 i = i-10 i = i*10 i = i/10

Comparison Operator

C has no special type to represent logical or Boolean values. It improvises by using any of the integral types char, int, short, long, unsigned, with a value of 0 representing false and any other value representing true. It is rare for logical values to be stored in variables. They are usually generated as required by comparing two numeric values. This is where the comparison operators are used, they compare two numeric values and produce a logical result. C notation == > < >= <= != Meaning Equal to Grater Than Less Than Grater than or equal to Less than or equal to not equal to

Note that == is used in comparisons and = is used in assignments. Comparison operators are used in expressions like the ones below.
x == y i > 10 a + b != c

In the last example, all arithmetic is done before any comparison is made.
Logical Operators

These are the usual And, Or and Not operators Symbol && Meaning AND

||

OR

! Not They are frequently used to combine relational operators, for example x < 20 && x >= 10 In C these logical connectives employ a technique known as lazy evaluation. They evaluate their left hand operand, and then only evaluate the right hand one if this is required. Clearly false && anything is always false, true || anything is always true. In such cases the second test is not evaluated. Not operates on a single logical value, its effect is to reverse its state. Here is an example of its use.

if ( ! acceptable ) printf("Not Acceptable !!\n"); Type conversion

You can mix the types of values in your arithmetic expressions. char types will be treated as int. Otherwise where types of different size are involved, the result will usually be of the larger size, so a float and a double would produce a double result. Where integer and real types meet, the result will be a double. There is usually no trouble in assigning a value to a variable of different type. The value will be preserved as expected except where.

The variable is too small to hold the value. In this case it will be corrupted (this is bad). The variable is an integer type and is being assigned a real value. The value is rounded down. This is often done deliberately by the programmer.

Values passed as function arguments must be of the correct type. The function has no way of determining the type passed to it, so automatic conversion cannot take place. This can lead to corrupt results. The solution is to use a method called casting which temporarily disguises a value as a different type.

eg. The function sqrt finds the square root of a double. int i = 256; int root root = sqrt( (double) i); The cast is made by putting the bracketed name of the required type just before the value. (double) in this example. The result of sqrt( (double) i); is also a double, but this is automatically converted to an int on assignment to root.

Conditional Operator: ? :

Syntax of Conditional operators is logical-or-expression ? expression : conditional-expression The conditional operator (? :) is a ternary operator (it takes three operands). The conditional operator works as follows

The first operand is implicitly converted to bool. It is evaluated and all side effects are completed before continuing. If the first operand evaluates to true (1), the second operand is evaluated. If the first operand evaluates to false (0), the third operand is evaluated.

The result of the conditional operator is the result of whichever operand is evaluated the second or the third. Only one of the last two operands is evaluated in a conditional expression. #include<stdio.h> void main() { int a,b; printf("Enter value of a); scanf("%d",&a); printf("Enter value of b);

scanf("%d",&b); (a>b)?printf("%d is big",a):printf("%d is big",b); getch(); } BITWISE OPERATORS C has a distinction of supporting special operators known as bitwise operators for manipulation of data at bit level. These operators are used for testing the bits, or shifting them right or left. Bitwise operators may not be applied to float or double. Bitwise operators are Operators & | ^ << >> ~ More about bitwise operators User Defined Type Declaration C support the feature known as type definition that allows user to define an identifier that would represent an exiting data type. The user defined datatype isentifier can later be used to declare variables. It takes the general form. typedef type identifier; Where type refers to an existing data type may belong to any class of type , including the user defined ones. Remember that the new type is 'new' only in name , but not the data type. typedef can not create a new type. Some example of type definition are typedef int unit; typedef float marks; Meaning bitwise AND bitwise OR bitwise exclusive OR Shift left Shift right One's complement

Here , unit symbolizes int and mark symbolizes folat. They can be later used to declare variables as follows. units batch1, batch2; marks name1[50], name2[50]; Bacth1 and batch2 are declare as int variable and name1[50] and name2[50] are declared as 50 element of floating point array variables. The main advantage of typedef is that we can create meaningful data type name for increasing the readability of the program Another user-defined data type is enumerated data type provided by ANSI standard. It is defined as follows. enum identifier { value1,value2,....valuen }; The identifier is user -defined enumerated data type which can be used to declare variable that can have one of the value enclosed with in the braces ( known as enumeration constant). After this we can declare variables to be of this new type as below.

enum identifier v1,v2,...vn. The enumerated variable v1,v2,..vn can only have one of the following types are valid; v1= value3; v3= value1; An example

enum day { Monday, Tuesday,...,Sunday}; enum day week_st, Week_end; Weel_st= Monday; week_end= Friday; if(week_st==Tuesday) week_end=Saturday; The compiler automatically assign integer digit beginning with 0 to all the enumeration

constants that is , the enumeration constant value1 is assign 0, value 1 , and so on. However the automatic assignment can be overridden by assigning values explicitly to the enumeration constant For example enum day { Monday=1, Tuesday,...Sunday }; Here, the constant Monday is assigned the value of 1. The remaining constants are assigned values that increase successively by 1. The definition and deceleration of enumerated variable can be combined in one statement enum day { Monday,....Sunday} Week_st, Week_end;

Input and Output

One of the advantages of C is that essentially it is a small language. This means that you can write a complete description of the language in a few pages. It doesn't have many keywords or data types for that matter. What makes C so powerful is the way that these low-level facilities can be put together to make higher level facilities. C supplies a standard package for performing input and output to Files or the terminal. This contains most of the functions which will be introduced in this section, along with definitions of the datatypes required to use them. To use these facilities, your program must include these definitions by adding the line This is done by adding the line #include<stdio.h> near the start of the program File. If you do not do this, the compiler may complain about undefined functions or datatypes.
Character Input / Output

This is the lowest level of input and output. It provides very precise control, but is usually too fiddly to be useful. Most computers perform buffering of input and output. This

means that they'll not start reading any input until the return key is pressed, and they'll not print characters on the terminal until there is a whole line to be printed.
getchar()

getchar returns the next character of keyboard input as an int. If there is an error then EOF (end of File) is returned instead. It is therefore usual to compare this value against EOF before using it. If the return value is stored in a char, it will never be equal to EOF, so error conditions will not be handled correctly. As an example, here is a program to count the number of characters read until an EOF is encountered. EOF can be generated by typing Control - z. #include <stdio.h> void main() { int ch, i = 0; while((ch = getchar()) != EOF) i ++; printf("%d\n", i); } putchar putchar puts its character argument on the standard output (usually the screen). The following example program converts any typed input into capital letters. To do this it applies the function toupper from the character conversion library ctype.h to each character in turn. #include <ctype.h> #include <stdio.h> void main() { int ch;

while((ch = getchar()) != '\n') putchar(toupper(ch)); } getch(), getche() These input functions are same as getchar(). The difference is getch() used to input a charater, will not echo character on the screen. The difference is getche() used to input a charater, will echo character on the screen.The difference is getchar() used to input a charater, will echo character on the screen and wait for carriage return.

printf() The printf (and scanf) functions do differ from the sort of functions that you will created for yourself in that they can take a variable number of parameters. In the case of printf the first parameter is always a string (c.f. "Hello World") but after that you can include as many parameters of any type that you want to. That is, the printf function is usually of the form: printf(string,variable,variable,variable...) where the ... means you can carry on writing a list of variables separated by commas as long as you want to. The string is all-important because it specifies the type of each variable in the list and how you want it printed. The string is usually called the control string or the format string. The way that this works is that printf scans the string from left to right and prints on the screen, or any suitable output device, any characters it encounters - except when it reaches a % character. The % character is a signal that what follows it is a specification for how the next variable in the list of variables should be printed. printf uses this information to convert and format the value that was passed to the function by the variable and then moves on to process the rest of the control string and anymore variables it might specify. For example: printf("Hello World");

only has a control string and, as this contains no % characters it results in Hello World being displayed and doesn't need to display any variable values. The specifier %d means convert the next value to a signed decimal integer and so: printf("Total = %d",total); will print Total = and then the value passed by >total as a decimal integer. The C view of output is at a lower level than you might expect. The %d isn't just a format specifier, it is a conversion specifier. It indicates the data type of the variable to be printed and how that data type should be converted to the characters that appear on the screen. That is %d says that the next value to be printed is a signed integer value (i.e. a value that would be stored in a standard int variable) and this should be converted into a sequence of characters (i.e. digits) representing the value in decimal. If by some accident the variable that you are trying to display happens to be a float or a double then you will still see a value displayed - but it will not correspond to the actual value of the float or double. The reason for this is twofold. The first difference is that an int uses two bytes to store its value, while a float uses four and a double uses eight. If you try to display a float or a double using %d then only the first two bytes of the value are actually used. The second problem is that even if there wasn't a size difference ints, floats and doubles use a different binary representation and %d expects the bit pattern to be a simple signed binary integer. This is all a bit technical, but that's in the nature of C. You can ignore these details as long as you remember two important facts The specifier following % indicates the type of variable to be displayed as well as the format in which that the value should be displayed; If you use a specifier with the wrong type of variable then you will see some strange things on the screen and the error often propagates to other items in the printf list.

You can also add an 'l' in front of a specifier to mean a long form of the variable type and h to indicate a short form (long and short will be covered later in this course). For example, %ld means a long integer variable (usually four bytes) and %hd means short int. Notice that there is no distinction between a four-byte float and an eight-byte double. The reason is that a float is automatically converted to a double precision value when passed to printf - so the two can be treated in the same way. (In pre-ANSI all floats were converted to double when passed to a function but this is no longer true.) The only real problem that this poses is how to print the value of a pointer? The answer is that you can use %x to see the address in hex or %o to see the address in octal. Notice that the value printed is the segment offset and not the absolute address - to understand what we am going on about you need to know something about the Structure of your processor. The % Format Specifiers:The % specifiers that you can use in ANSI C are: Usual variable type %c char %d (%i) int %e (%E) float or double %g (%G) float or double %o int %s array of char %u int %x (%X) int Display single character signed integer exponential format use %f or %e as required unsigned octal value sequence of characters unsigned decimal unsigned hex value

Formatting Output

The type conversion specifier only does what you ask of it - it convert a given bit pattern into a sequence of characters that a human can read. If you want to format the characters then you need to know a little more about the printf function's control string.Each specifier can be preceded by a modifier which determines how the value will be printed. The most general modifier is of the form flag width.precision The flag can be any of

flag + space 0 #

meaning left justify always display sign display space if there is no sign pad with leading zeros use alternate form of specifier

The width specifies the number of characters used in total to display the value and precision indicates the number of characters used after the decimal point. For example, %10.3f will display the float using ten characters with three digits after the decimal point. Notice that the ten characters includes the decimal point.and a - sign if there is one. If the value needs more space than the width specifies then the additional space is used - width specifies the smallest space that will be used to display the value. The specifier %-1Od will display an int left justified in a ten character space. The specifier %+5d will display an int using the next five character locations and will add a + or - sign to the value. The only complexity is the use of the # modifier. What this does depends on which type of format it is used with. The only complexity is the use of the # modifier. What this does depends on which type of format it is used with %#o %#x %#f %#e %#g adds a leading 0 to the octal value adds a leading 0x to the hex value or ensures decimal point is printed displays trailing zeros

Strings will be discussed later but for now remember: if you print a string using the %s specifier then all of the characters stored in the array up to the first null will be printed. If you use a width specifier then the string will be right justified within the space. If you include a precision specifier then only that number of characters will be printed. printf("%s,Hello") will print Hello

printf("%25s ,Hello") printf("%25.3s,Hello")

will print 25 characters with Hello right justified and will print Hello right justified in a group of 25 spaces.

Also notice that it is fine to pass a constant value to printf as in printf("%s,Hello"). Finally there are the control codes \b \f \n \r \t \' \0 backspace formfeed new line carriage return horizontal tab single quote null

If you include any of these in the control string then the corresponding ASCII control code is sent to the screen, or output device, which should produce the effect listed. In most cases you only need to remember \n for new line.

Scanf() Now that we have mastered the intricacies of printf you should find scanf very easy. The scanf function works in much the same way as the printf. That is it has the general form: scanf(control string,variable,variable,...) In this case the control string specifies how strings of characters, usually typed on the keyboard, should be converted into values and stored in the listed variables. However there are a number of important differences as well as similarities between scanf and printf. The most obvious is that scanf has to change the values stored in the parts of computers memory that is associated with parameters (variables).

To understand this fully you will have to wait until we have covered functions in more detail. But, just for now, bare with us when we say to do this the scanf function has to have the addresses of the variables rather than just their values. This means that simple variables have to be passed with a preceding >&. (Note for future reference: There is no need to do this for strings stored in arrays because the array name is already a pointer.) The second difference is that the control string has some extra items to cope with the problems of reading data in. However, all of the conversion specifiers listed in connection with printf can be used with scanf. The rule is that scanf processes the control string from left to right and each time it reaches a specifier it tries to interpret what has been typed as a value. If you input multiple values then these are assumed to be separated by white space - i.e. spaces, newline or tabs scanf("%d %d",&i,&j); will read in two integer values into i and j. The integer values can be typed on the same line or on different lines as long as there is at least one white space character between them. The only exception to this rule is the %c specifier which always reads in the next character typed no matter what it is. You can also use a width modifier in scanf. In this case its effect is to limit the number of characters accepted to the width. scanf("%lOd",&i) would use at most the first ten digits typed as the new value for i.untile maximum value match data type. There is one main problem with scanf function which can make it unreliable in certain cases. The reason being is that scanf tends to ignore white spaces, i.e. the space character. If you require your input to contain spaces this can cause a problem. Therefore for string data input the function getstr() may well be more reliable as it records spaces in the input

text and treats them as an ordinary characters. A program to demonstrate input,output task. #include <stdio.h> main() { int a,b,c; printf("\nThe first number is "); scanf("%d",&a); printf("The second number is "); scanf("%d",&b); c=a+b; printf("The answer is %d \n",c); } gets(),puts()

Where we are not too interested in the format of our data, or perhaps we cannot predict its format in advance, we can read and write whole lines as character strings. This approach allows us to read in a line of input, and then use various string handling functions to analyse it at our leisure. gets reads a whole line of input into a string until a newline or EOF is encountered. It is critical to ensure that the string is large enough to hold any expected input lines. When all input is finished, NULL as defined in stdio.h is returned. puts writes a string to the output, and follows it with a newline character.Example: Program which uses gets and puts to double space typed input.
#include <stdio.h> main() { char line[80]; /* Define string sufficiently large to store a line of input */

while(gets(line) != NULL) { puts(line); printf("\n"); }

/* Read line */ /* Print line */ /* Print blank line */

Control Statements A program consists of a number of statements which are usually executed in sequence. Programs can be much more powerful if we can control the order in which statements are run. Statements fall into three general types

Assignment, where values, usually the results of calculations, are stored in variables. Input / Output, data is read in or printed out. Control, the program makes a decision about what to do next.

This section will discuss the use of control statements in C. We will show how they can be used to write powerful programs by;

Repeating important sections of the program. Selecting between optional sections of a program. If else Statement

This is used to decide whether to do something at a special point, or to decide between two courses of action. The following test decides whether a student has passed an exam with a pass mark of 45 if (result >= 45) printf("Pass\n"); else printf("Fail\n"); It is possible to use the if part without the else.

if (temperature < 0) print("Frozen\n"); Each version consists of a test, (this is the bracketed statement following the if). If the test is true then the next statement is obeyed. If it is false then the statement following the else is obeyed if present. After this, the rest of the program continues as normal. If we wish to have more than one statement following the if or the else, they should be grouped together between curly brackets. Such a grouping is called a compound statement or a block. if (result >= 45) { printf("Passed\n"); printf("Congratulations\n") } else { printf("Failed\n"); printf("Good luck in the resits\n"); } Sometimes we wish to make a multi-way decision based on several conditions. The most general way of doing this is by using the else if variant on the if statement. This works by cascading several comparisons. As soon as one of these gives a true result, the following statement or block is executed, and no further comparisons are performed. In the following example we are awarding grades depending on the exam result. if (result >= 75) printf("Passed: Grade A\n"); else if (result >= 60) printf("Passed: Grade B\n"); else if (result >= 45) printf("Passed: Grade C\n"); else printf("Failed\n");

In this example, all comparisons test a single variable called result. In other cases, each test may involve a different variable or some combination of tests. The same pattern can be used with more or fewer else if's, and the final lone else may be left out. It is up to the programmer to devise the correct Structure for each programming problem. The switch Statement

This is another form of the multi way decision. It is well Structured, but can only be used in certain cases where;

Only one variable is tested, all branches must depend on the value of that variable. The variable must be an integral type. (int, long, short or char). Only one variable is tested, all branches must depend on the value of that variable. The variable must be an integral type. (int, long, short or char).

Hopefully an example will clarify things. This is a function which converts an integer into a vague description. It is useful where we are only concerned in measuring a quantity when it is quite small. estimate(number) int number; /* Estimate a number as none, one, two, several, many */ { switch(number) { case 0 : printf("None\n"); break; case 1 : printf("One\n"); break; case 2 : printf("Two\n"); break; case 3 :

case 4 : case 5 : printf("Several\n"); break; default : printf("Many\n"); break; } } Each interesting case is listed with a corresponding action. The break statement prevents any further statements from being executed by leaving the switch. Since case 3 and case 4 have no following break, they continue on allowing the same action for several values of number. Both if and switch constructs allow the programmer to make a selection from a number of possible actions. The other main type of control statement is the loop. Loops allow a statement, or block of statements, to be repeated. Computers are very good at repeating simple tasks many times, the loop is C's way of achieving this.

LOOP C gives you a choice of three types of loop, while, do while and for.

The while loop keeps repeating an action until an associated test returns false. This is useful where the programmer does not know in advance how many times the loop will be traversed.

The do while loops is similar, but the test occurs after the loop body is executed. This ensures that the loop body is run at least once.

The for loop is frequently used, usually where the loop will be traversed a fixed number of times. It is very flexible, and novice programmers should take care not to abuse the power it offers. The while Loop

The while loop repeats a statement until the test at the top proves false. As an example, here is a function to return the length of a string. Remember that the string is represented as an array of characters terminated by a null character '\0'. int string_length(char string[]) { int i = 0; while (string[i] != '\0') i++; return(i); } The string is passed to the function as an argument. The size of the array is not specified, the function will work for a string of any size. The while loop is used to look at the characters in the string one at a time until the null character is found. Then the loop is exited and the index of the null is returned. While the character isn't null, the index is incremented and the test is repeated. The do while Loop

This is very similar to the while loop except that the test occurs at the end of the loop body. This guarantees that the loop is executed at least once before continuing. Such a setup is frequently used where data is to be read. The test then verifies the data, and loops back to read again if it was unacceptable. do {

printf("Enter 1 for yes, 0 for no :"); scanf("%d", &input_value); } while (input_value != 1 && input_value != 0);

The for Loop

The for loop works well where the number of iterations of the loop is known before the loop is entered. The head of the loop consists of three parts separated by semicolons.

The first is run before the loop is entered. This is usually the initialisation of the loop variable The second is a test, the loop is exited when this returns false. The third is a statement to be run every time the loop body is completed. This is usually an increment of the loop counter.

The example is a function which calculates the average of the numbers stored in an array. The function takes the array and the number of elements as arguments. float average(float array[], int count) { float total = 0.0; int i; for(i = 0; i < count; i++) total += array[i]; return(total / count); } The for loop ensures that the correct number of array elements are added up before calculating the average. The three statements at the head of a for loop usually do just one thing each, however any of them can be left blank. A blank first or last statement will mean no initialisation or running increment. A blank comparison statement will always be treated as true. This

will cause the loop to run indefinitely unless interrupted by some other means. This might be a return or a break statement. It is also possible to squeeze several statements into the first or third position, separating them with commas. This allows a loop with more than one controlling variable. The example below illustrates the definition of such a loop, with variables hi and lo starting at 100 and 0 respectively and converging. for (hi = 100, lo = 0; hi >= lo; hi--, lo++) The for loop is extremely flexible and allows many types of program behaviour to be specified simply and quickly. The break Statement We have already met break in the discussion of the switch statement. It is used to exit from a loop or a switch, control passing to the first statement beyond the loop or a switch. With loops, break can be used to force an early exit from the loop, or to implement a loop with a test to exit in the middle of the loop body. A break within a loop should always be protected within an if statement which provides the test to control the exit condition. The continue Statement This is similar to break but is encountered less frequently. It only works within loops where its effect is to force an immediate jump to the loop control statement.

In a while loop, jump to the test statement. In a do while loop, jump to the test statement. In a for loop, jump to the test, and perform the iteration.

Like a break, continue should be protected by an if statement. You are unlikely to use it very often. The goto Statement

C has a goto statement which permits un Structured jumps to be made. Its use is not recommended for professional programming. Syntax for goto statment is goto label. Label is a mark where control is transfered. #include<stdio.h> #include<conio.h> #include<math.h> #include<ctytpe.h> void main() { int num; char ch; repite: printf("Enter a Number"); scanf("%d",&num); printf("Squre root of the given number is %f",sqrt(num)); printf(do you want to continue(Y/N)"); fflush(stdin); ch=getchar(); if((toupper(ch))=='Y') goto repite; }

ARRAYS Scientific programs very often deal with multiple data items possessing common characteristics. In such cases, it is often convenient to place the data items in question into an array, so that they all share a common name (e.g., x). The individual data items can be either integers or floating-point numbers. However, they all must be of the same data type. In C, an element of an array (i.e., an individual data item) is referred to by specifying the

array name followed by one or more subscripts, with each subscript enclosed in square brackets. All subscripts must be nonnegative integers. Thus, in an n-element array called
x,

the array elements are


x[0],x[1], ..., x[n-1]

Note that the first element of the array is x[0] and not x[1], as in other programming languages. The number of subscripts determines the dimensionality of an array. For example, x[i] refers to an element of a one-dimensional array, x. Similarly, y[i][j] refers to an element of a two-dimensional array, y, etc. Arrays are declared in much the same manner as ordinary variables, except that each array name must be accompanied by a size specification (which specifies the number of elements). For a one-dimensional array, the size is specified by a positive integer constant, enclosed in square brackets. The generalization for multi-dimensional arrays is fairly obvious. Several valid array declarations are shown below int j[100]; double x[20]; double y[10][20]; Thus, j is a 100-element integer array, x is a 20-element floating point array, and y is a
10x20

floating-point array. Note that variable size array declarations, e.g.,

double a[n]; where n is an integer variable, are illegal in C. It is sometimes convenient to define an array size in terms of a symbolic constant, rather than a fixed integer quantity. This makes it easier to modify a program that utilizes an array, since all references to the maximum array size can be altered by simply changing the value of the symbolic constant.

Like an ordinary variable, an array can be either local or global in extent, depending on whether the associated array declaration lies inside or outside, respectively, the scope of any of the functions which constitute the program. Both local and global arrays can be initialized via their declaration statements. For instance, int j[5] = {1, 3, 5, 7, 9}; Single operations which involve entire arrays are not permitted in C. Thus, if x and y are similar arrays (i.e., the same data type, dimensionality, and size) then assignment operations, comparison operations, etc. involving these two arrays must be carried out on an element by element basis. This is usually accomplished within a loop (or within nested loops, for multi-dimensional arrays). Reading and writing array element by using a loop, usually for loop is using for example #include<stdio.h> #include<conio.h> #include<stdlib.h> void main() { int arr1[1],i,n; printf("Enter number of array elements"); scanf("%d",&n); if(n>10&&n<=0) { printf("Invalid number of n \n"); exit(1); } for(i=0;i<n;i++) scanf("%d",&arr1[i]);

printf("Contant of array is \n"); for(i=0;i<n;i++) printf("%d\n",arr1[i]); } arrays can be initialized at the declaration section also for example int a[5]={10,20,30,40,50} or int a[]={10,20,30,40,50}

Character Array

An array of character variables is in no way different from an array of numeric variables, but programmers often like to think about them in a different way. For example, if you want to read in and reverse five characters you could use main() { char a[5]; int i; for(i=0; i<5; ++i) scanf("%c",&a[i]); for(i=4;i>=0;--i) printf("%c",a[i]); } Notice that the only difference, is the declared type of the array and the %c used to specify that the data is to be interpreted as a character in scanf and printf. The trouble with character arrays is that to use them as if they were text strings you have to remember how many characters they hold. In other words, if you declare a character array 40 elements long and store H E L L O in it you need to remember that after element 4 the array is empty. This is such a nuisance that C uses the simple convention that the end of a string of characters is marked by a null character. A null character is, as you might

expect, the character with ASCII code 0. If you want to store the null character in a character variable you can use the notation \0 - but most of the time you don't have to actually use the null character. The reason is that C will automatically add a null character and store each character in a separate element when you use a string constant. A string constant is indicated by double quotes as opposed to a character constant which is indicated by a single quote. For example "A" is a string constant, but 'A' is a character constant. The difference between these two superficially similar types of text is confusing at first and the source of many errors. All you have to remember is that "A" consists of two characters, the letter A followed by \0 whereas 'A' is just the single character A. If you are familiar with other languages you might think that you could assign string constants to character arrays and work as if a string was a built-in data type. In C however the fundamental data type is the array and strings are very much grafted on. For example, if you try something like char name[40]; name="Hello" it will not work. However, you can print strings using printf and read them into character arrays using scanf. For example, main() { static char name[40] ="hello"; printf("%s",name); scanf("%s",name); printf("%s",name);

} This program reads in the text that you type, terminating it with a null and stores it in the character array name. It then prints the character array treating it as a string, i.e. stopping when it hits the first null string. Notice the use of the "%s" format descriptor in scanf and printf to specify that what is being printed is a string. At this point the way that strings work and how they can be made a bit more useful and natural depends on understanding pointers which is covered in later section.

Functions and Program Structure A function is a ``black box'' that we've locked part of our program into. The idea behind a function is that it compartmentalizes part of the program, and in particular, that the code within the function has some useful properties. 1. It performs some well-defined task, which will be useful to other parts of the program. 2. It might be useful to other programs as well; that is, we might be able to reuse it (and without having to rewrite it). 3. The rest of the program doesn't have to know the details of how the function is implemented. This can make the rest of the program easier to think about. 4. The function performs its task well. It may be written to do a little more than is required by the first program that calls it, with the anticipation that the calling program (or some other program) may later need the extra functionality or improved performance. (It's important that a finished function do its job well, otherwise there might be a reluctance to call it, and it therefore might not achieve the goal of reusability.) 5. By placing the code to perform the useful task into a function, and simply calling the function in the other parts of the program where the task must be performed, the rest of the program becomes clearer: rather than having some large, complicated, difficult-to-understand piece of code repeated wherever the task is being performed, we have a single simple function call, and the name of the function reminds us which task is being performed.

6. Since the rest of the program doesn't have to know the details of how the function is implemented, the rest of the program doesn't care if the function is reimplemented later, in some different way (as long as it continues to perform its same task, of course!). This means that one part of the program can be rewritten, to improve performance or add a new feature (or simply to fix a bug), without having to rewrite the rest of the program. Functions are probably the most important weapon in our battle against software complexity. You'll want to learn when it's appropriate to break processing out into functions (and also when it's not), and how to set up function interfaces to best achieve the qualities mentioned above: reusability, information hiding, clarity, and maintainability. Function Basics So what defines a function? It has a name that you call it by, and a list of zero or more arguments or parameters that you hand to it for it to act on or to direct its work; it has a body containing the actual instructions (statements) for carrying out the task the function is supposed to perform; and it may give you back a return value, of a particular type. ere is a very simple function, which accepts one argument, multiplies it by 2, and hands that value back: int multbytwo(int x) { int retval; retval = x * 2; return retval; }

On the first line we see the return type of the function (int), the name of the function (multbytwo), and a list of the function's arguments, enclosed in parentheses. Each argument has both a name and a type; multbytwo accepts one argument, of type int, named x. The name x is arbitrary, and is used only within the definition of multbytwo. The caller of this function only needs to know that a single argument of type int is

expected; the caller does not need to know what name the function will use internally to refer to that argument. (In particular, the caller does not have to pass the value of a variable named x.) Next we see, surrounded by the familiar braces, the body of the function itself. This function consists of one declaration (of a local variable retval) and two statements. The first statement is a conventional expression statement, which computes and assigns a value to retval, and the second statement is a return statement, which causes the function to return to its caller, and also specifies the value which the function returns to its caller. The return statement can return the value of any expression, so we don't really need the local retval variable; the function could be collapsed to int multbytwo(int x) { return x * 2; } How do we call a function? We've been doing so informally since day one, but now we have a chance to call one that we've written, in full detail. Here is a tiny skeletal program to call multby2 #include <stdio.h> extern int multbytwo(int); int main() { int i, j; i = 3; j = multbytwo(i); printf("%d\n", j); return 0; } This looks much like our other test programs, with the exception of the new line. extern int multbytwo(int);

This is an external function prototype declaration. It is an external declaration, in that it declares something which is defined somewhere else. (We've already seen the defining instance of the function multbytwo, but maybe the compiler hasn't seen it yet.) The function prototype declaration contains the three pieces of information about the function that a caller needs to know: the function's name, return type, and argument type(s). Since we don't care what name the multbytwo function will use to refer to its first argument, we don't need to mention it. (On the other hand, if a function takes several arguments, giving them names in the prototype may make it easier to remember which is which, so names may optionally be used in function prototype declarations.) Finally, to remind us that this is an external declaration and not a defining instance, the prototype is preceded by the keyword extern. The presence of the function prototype declaration lets the compiler know that we intend to call this function, multbytwo. The information in the prototype lets the compiler generate the correct code for calling the function, and also enables the compiler to check up on our code (by making sure, for example, that we pass the correct number of arguments to each function we call). Down in the body of main, the action of the function call should be obvious: the line j = multbytwo(i); calls multbytwo, passing it the value of i as its argument. When multbytwo returns, the return value is assigned to the variable j. (Notice that the value of main's local variable i will become the value of multbytwo's parameter x; this is absolutely not a problem, and is a normal sort of affair.) This example is written out in ``longhand,'' to make each step equivalent. The variable i isn't really needed, since we could just as well call. j = multbytwo(3);

And the variable j isn't really needed, either, since we could just as well call printf("%d\n", multbytwo(3)); Here, the call to multbytwo is a subexpression which serves as the second argument to printf. The value returned by multbytwo is passed immediately to printf. (Here, as in general, we see the flexibility and generality of expressions in C. An argument passed to a function may be an arbitrarily complex subexpression, and a function call is itself an expression which may be embedded as a subexpression within arbitrarily complicated surrounding expressions.) We should say a little more about the mechanism by which an argument is passed down from a caller into a function. Formally, C is call by value, which means that a function receives copies of the values of its arguments. We can illustrate this with an example. Suppose, in our implementation of multbytwo, we had gotten rid of the unnecessary retval variable like this. int multbytwo(int x) { x = x * 2; return x; } We might wonder, if we wrote it this way, what would happen to the value of the variable i when we called j = multbytwo(i); When our implementation of multbytwo changes the value of x, does that change the value of i up in the caller? The answer is no. x receives a copy of i's value, so when we change x we don't change i. However, there is an exception to this rule. When the argument you pass to a function is not a single variable, but is rather an array, the function does not receive a copy of the

array, and it therefore can modify the array in the caller. The reason is that it might be too expensive to copy the entire array, and furthermore, it can be useful for the function to write into the caller's array, as a way of handing back more data than would fit in the function's single return value. We'll see an example of an array argument (which the function deliberately writes into) in the next chapter.

Function Prototypes In modern C programming, it is considered good practice to use prototype declarations for all functions that you call. As we mentioned, these prototypes help to ensure that the compiler can generate correct code for calling the functions, as well as allowing the compiler to catch certain mistakes you might make. Strictly speaking, however, prototypes are optional. If you call a function for which the compiler has not seen a prototype, the compiler will do the best it can, assuming that you're calling the function correctly. If prototypes are a good idea, and if we're going to get in the habit of writing function prototype declarations for functions we call that we've written (such as multbytwo), what happens for library functions such as printf? Where are their prototypes? The answer is in that boilerplate line. #include <stdio.h> we've been including at the top of all of our programs. stdio.h is conceptually a File full of external declarations and other information pertaining to the ``Standard I/O'' library functions, including printf. The #include directive (which we'll meet formally in a later chapter) arranges that all of the declarations within stdio.h are considered by the compiler, rather as if we'd typed them all in ourselves. Somewhere within these declarations is an external function prototype declaration for printf, which satisfies the rule that there should be a prototype for each function we call. (For other standard library functions we call, there will be other ``header Files'' to include.) Finally, one more thing about external function prototype declarations. We've said that the distinction between

external declarations and defining instances of normal variables hinges on the presence or absence of the keyword extern. The situation is a little bit different for functions. The ``defining instance'' of a function is the function, including its body (that is, the braceenclosed list of declarations and statements implementing the function). An external declaration of a function, even without the keyword extern, looks nothing like a function declaration. Therefore, the keyword extern is optional in function prototype declarations. If you wish, you can write

int multbytwo(int); and this is just as good an external function prototype declaration as. extern int multbytwo(int); (In the first form, without the extern, as soon as the compiler sees the semicolon, it knows it's not going to see a function body, so the declaration can't be a definition.) You may want to stay in the habit of using extern in all external declarations, including function declarations, since ``extern = external declaration'' is an easier rule to remember. Recursive Functions A recursive function is one which calls itself. This is another complicated idea which you are unlikely to meet frequently. We shall provide some examples to illustrate recursive functions. Recursive functions are useful in evaluating certain types of mathematical function. You may also encounter certain dynamic data Structures such as linked lists or binary trees. Recursion is a very useful way of creating and accessing these Structures. Here is a recursive version of the factorial function. We saw a non recursive version of this earlier.

#include<conio.h> #include<stdio.h> void main() { int n,fact; int rec(int); clrscr(); printf("Enter a Number"); scanf("%d",&n); fact= rec(n); printf("%d",fact); } int rec(int x) { int f; if (x==1) return (1); else f=x*rec(x-1); return(f); } Don't be frightened by the apparent complexity of recursion. Recursive functions are sometimes the simplest answer to a calculation. However there is always an alternative non-recursive solution available too. This will normally involve the use of a loop, and may lack the elegance of the recursive solution.

Storage Classes

Every C variable has a storage class and a scope. The storage class determines the part of memory where storage is allocated for an object and how long the storage allocation continues to exist. It also determines the scope which specifies the part of the program over which a variable name is visible, i.e. the variable is accessible by name. There are four storage classes in C are automatic, register, external, and static. Automatic Variables

We have already used automatic variables. They are declared at the start of a block. Memory is allocated automatically upon entry to a block and freed automatically upon exit from the block. The scope of automatic variables is local to the block in which they are declared, including any blocks nested within that block. For these reasons, they are also called local variables. No block outside the defining block may have direct access to automatic variables, i.e. by name. Of course, they may be accessed indirectly by other blocks and/or functions using pointers. Automatic variables may be specified upon declaration to be of storage class auto. However, it is not required; by default, storage class within a block is auto. Automatic variables declared with initializes are initialized each time the block in which they are declared is entered. Register Variables Register variables are a special case of automatic variables. Automatic variables are allocated storage in the memory of the computer; however, for most computers, accessing data in memory is considerably slower than processing in the CPU. These computers often have small amounts of storage within the CPU itself where data can be stored and accessed quickly. These storage cells are called registers. Normally, the compiler determines what data is to be stored in the registers of the CPU at what times. However, the C language provides the storage class register so that the programmer can ``suggest'' to the compiler that particular automatic variables should be allocated to CPU registers, if possible. Thus, register variables provide a certain control

over efficiency of program execution. Variables which are used repeatedly or whose access times are critical, may be declared to be of storage class register.

#include<stdio.h> #include<conio.h> void main() { register float a=0; auto int bb=1; autto char cc = 'w'; /* Rest of the program */ } Register variables behave in every other way just like automatic variables. They are allocated storage upon entry to a block; and the storage is freed when the block is exited. The scope of register variables is local to the block in which they are declared. Rules for initializations for register variables are the same as for automatic variables. As stated above, the register class designation is merely a suggestion to the compiler. Not all implementations will allocate storage in registers for these variables, depending on the number of registers available for the particular computer, or the use of these registers by the compiler. They may be treated just like automatic variables and provided storage in memory. Finally, even the availability of register storage does not guarantee faster execution of the program. For example, if too many register variables are declared, or there are not enough registers available to store all of them, values in some registers would have to be moved to temporary storage in memory in order to clear those registers for other variables. Thus, much time may be wasted in moving data back and forth between registers and memory locations. In addition, the use of registers for variable storage may interfere with other uses of registers by the compiler, such as storage of temporary values in expression evaluation. In the end, use of register variables could actually result in slower execution. Register variables should only be used if you have a detailed

knowledge of the architecture and compiler for the computer you are using. It is best to check the appropriate manuals if you should need to use register variables. External Variables All variables we have seen so far have had limited scope (the block in which they are declared) and limited lifetimes (as for automatic variables). However, in some applications it may be useful to have data which is accessible from within any block and/or which remains in existence for the entire execution of the program. Such variables are called global variables, and the C language provides storage classes which can meet these requirements; namely, the external and static classes. External variables may be declared outside any function block in a source code File the same way any other variable is declared; by specifying its type and name. No storage class specifier is used - the position of the declaration within the File indicates external storage class. Memory for such variables is allocated when the program begins execution, and remains allocated until the program terminates. For most C implementations, every byte of memory allocated for an external variable is initialized to zero. The scope of external variables is global, i.e. the entire source code in the File following the declarations. All functions following the declaration may access the external variable by using its name. However, if a local variable having the same name is declared within a function, references to the name access the local variable cell. #include<stdio.h> void next(void); void next1(void); int a1=1; void main() { printf(" Scope of External Variables \n\n"); a1=2; printf("a1=%d\n",a1);

next(); printf("a1=%d\n",a1); next1(); printf(" a1= %d\n",a1); } int b1=0; void next(void) { char a1; a1='a'; b1=77; printf("a1= %c,b1=%d\n",a1,b1); } void next1(void) { float b1; b1=19.2; a1=13; peintf("a1=%d.b1=%f\n",a1,b1); } External variables may be initialized in declarations just as automatic variables; however, the initializes must be constant expressions. The initialization is done only once at compile time, i.e. when memory is allocated for the variables variables. In general, it is a good programming practice to avoid use of external variables as they destroy the concept of a function as a ``black box''. The black box concept is essential to the development of a modular program with modules. With an external variable, any function in the program can access and alter the variable, thus making debugging more difficult as well. This is not to say that external variables should never be used. There

may be occasions when the use of an external variable significantly simplifies the implementation of an algorithm. Suffice it to say that external variables should be used rarely and with caution. Static Variables As we have seen, external variables have global scope across the entire program (provided extern declarations are used is Files other than where the variable is defined), and a lifetime over the the entire program run. The storage class, static, similarly provides a lifetime over the entire program, however; it provides a way to limit the scope of such variables, Static storage class is declared with the keyword static as the class specifier when the variable is defined. These variables are automatically initialized to zero upon memory allocation just as external variables are. Static storage class can be specified for automatic as well as external variables.

Static automatic variables continue to exist even after the block in which they are defined terminates. Thus, the value of a static variable in a function is retained between repeated function calls to the same function. The scope of static automatic variables is identical to that of automatic variables, i.e. it is local to the block in which it is defined; however, the storage allocated becomes permanent for the duration of the program. Static variables may be initialized in their declarations; however, the initializes must be constant expressions, and initialization is done only once at compile time when memory is allocated for the static variable. #include<stdio.h> #include<conio.h> #define MAX 5 void sumit(); void main() { int count; printf("Static Variables\n"); printf("Enter 5 nubers to be summed\n"); for(count=0;count<MAX;count++)

sumit(); printf("Program Completed"); } void sumit(void) { static int sum=0; int num; printf("Enter a number"); scanf("%d",&num); sum+=num; printf("The curent total is %d",sum); } While the static variable, sum, would be automatically initialized to zero, it is better to do so explicitly. In any case, the initialization is performed only once at the time of memory allocation by the compiler. The variable sum retains its value during program execution. Each time the function sumit() is called, sum is incremented by the next integer read. Static storage class designation can also be applied to external variables. The only difference is that static external variables can be accessed as external variables only in the file in which they are defined. No other source file can access static external variables that are defined in another file. /* file: xxx.c */ static int count; static char name[8]; main() { ... /* program body */ } Only the code in the file xxx.c can access the external variables count and name. Other files cannot access them, even with extern declarations. We have seen that external variables should be used with care, and access to them should not be available indiscriminately. Defining external variables to be static provides an additional control on which functions can access them. For example, in the symbol.c

example in the last section, we created a file symio.c which contained an external variable. This external variable should be accessible only to the functions in that file. However, there is no way to guarantee that some other file may not access it by declaring it as extern. We can ensure that this will not happen by declaring the variable as static as #include<stdio.h> #include "symdef.h" static int c =NULL; int getchr() { int ch; if(c) { ch=c; c=NULL; return(ch); } else return(getchar()); } void ungetchr(int cc) { c=cc; } The static variable c would not be accessible to functions defined in any other file, thus preventing an unplanned use of it as an external variable by the code in other files.

Recursion In normal procedural languages, one can go about defining functions and procedures, and 'calling' these from the 'parent' functions. I hope you already know that.Some languages also provide the ability of a function to call itself. This is called Recursion. We already seen an example of factorial program using recursion. The important thing to remember when creating a recursive function is to give an 'end-condition'. We don't want

the function to keep calling itself forever, now, do we? Somehow, it should know when to stop. There are many ways of doing this. One of the simplest is by means of an 'if condition' statement, as above. In the above example, the recursion stops when n reaches 1. In each instance of the function, the value of n keeps decreasing. So it ultimately reaches 1 and ends. Of course, the above function will run infinitely if the initial value of n is less than 1. So the function is not perfect. The n==1 condition should be changed to n<=1. Imagination is a very hard thing. Imagination of Recursion is all the more tricky. Think of clones. Say you have a machine to make clones of yourself, and (for lack of a better pass-time) decide to find the factorial of a number, say 10, using your clones. So, being smart, this is what you do First, there's only You. Let's call you You-1. You have the number 10 in your pocket. Being smart, you know that all you need to find the factorial of 10 (10*9*...*2*1) is to somehow obtain the value of 9 factorial (9*8*..*2*1), and then just multiply it with 10. So that's what you do. You turn on your machine and out pops a clone! You give the clone You-2 strict instructions to find the factorial of 9 and make it quick! Your job is done for a while, so you (You-1) stretch on your sofa sipping on your lemonade. Meanwhile... You-2 is (you guessed it) just as smart as you! He tucks his number (9) into his pocket, turns on the machine, and out pops a clone (You-3). The new clone is given the job of 8factorial, which it proceeds to do while (unbeknownst to you) You-2 is sipping on his own glass of lemonade on his own sofa. And so the story goes on until finally one fine day... Out pops You-10 who is given strict instructions (by You-9) to get the factorial of 1. Now, You-10, being just as smart as any of the other you's, knows very well that the factorial of 1 is... 1. So he says to You-9 (who was just about to doze off on his sofa), "Here's your factorial of 1." You-9 snatches the result from his subordinate You-10, takes

out his plasma gun, and zaps You-10 out of existence. He scribbles on a piece of paper, calculating the product of the value he got from You-10 with the number in his pocket, 2. "Heh, heh, heh" he thinks, and goes to his boss, You-8, saying,"Here's your factorial of 2..." ...blah...blah... and finally You-2 wakes you up from your slumber, and says to you, "Here's your factorial of 9" You zap him off, multiply by the 10 in your pocket, and There You Have It !! Now, wasn't that simple? Here, 'You' were the function. The 'clones' are merely new instances of the same function. They all think and act alike. At one point, there are 10 You's (which occupies a lot of memory space). As soon as an instance returns a value and finishes its job, it is zapped off from memory. Exercises Here are some programs for you to try... but since nobody these days actual works out the problems, all I'm going to ask you to do is give each problem a thought. You should be able to solve them all. 1. Write a function using Recursion to print numbers from n to 0. 2. Write a function using Recursion to print numbers from 0 to n. (You just need to shift one line in the program of problem 1.) 3. Write a function using Recursion to enter and display a string in reverse. Don't use arrays/strings. 4. Write a function using Recursion to enter and display a string in reverse and state whether the string contains any spaces. Don't use arrays/strings. 5. Write a function using Recursion to check if a number n is prime. (You have to check whether n is divisible by any number below n) 6. Write a function using Recursion to enter characters one by one until a space is encountered. The function should return the depth at which the space was encountered.

Magic Squares

In this page, I'm going to show you the permutation-capabilities of Recursion. Permutation means a combination of certain units in all possible orderings. Recursion can be effectively used to find all possible combinations of a given set of elements. This has applications in anagrams, scheduling and, of course, Magic Squares. And if you're interested, Recursion can also be used for cracking passwords. ;-) First, what is a magic square? A magic square is a 'matrix' or a 2-dimensional grid of numbers. Take the simple case of a 3x3 magic square. Here's one:4 9 2 3 5 7 8 1 6

A Magic Square contains a certain bunch of numbers, in this case, 1..9, each of which has to be filled once into the grid. The 'magic' property of a Magic Square is that the sum of the numbers in the rows and columns and diagonals should all be same, in this case, 15. Try making a 3x3 magic square yourself. It's not that easy. If it was easy, try a 4x4 grid with numbers 1..16. And what about 5x5, 6x6...? That's where computers come in! Okay, now, how do we go about programming something we hardly understand. The answer is : brute force. The computer may not be smart, but it can certainly do something you would take months to do, and that is, pure calculations - millions and millions of them. To have an analogy, suppose you are given two identical photos. It would take you just a glance of the eye to agree that they're same. The computer, on the other hand, would compare them dot by dot, pixel by pixel, and then agree that they're same. In the process, both you and the computer accomplish the same task in pretty much the same time, but in very different ways. So, the answer is brute force. Okay, we've got a bunch of numbers. We've got to arrange them in a matrix so that the sum is equal in all directions. Since we don't have a clue about any strategy, we'd just have to........ Try All Possibilities! Yes, and that's what a computer is meant to do - brute

force. Okay, try figuring it out yourself at this stage. You know everything there is to know the concept of magic squares, the need to check all possibilities, and that the answer lies in recursion. To help ease the complexity, you can make a simple function (besides the recursive function) to check if a square is magical. So, basically, you've got to try all possibilities and permutations, and for each one, you have to call the function to test if the square is magical. I seriously suggest you stop at this point, and brainstorm to extremes. Better yet, just finish the program. It isn't that tough. Given up? Fine. Having said all that I said, only the heart of the program is left to explain. The question boils down to, how do we accomplish permuting a set of numbers (or objects) using recursion? For simplicity sake, we work with a 1-dimensional array. In the case of a 3x3 square, let's have a 9-length single-dimensional array. So we have numbers 1 to 9 and 9 locations to put them into. The permutations would be:123456789 123456798 123456879 123456897 123456978 123456987 .... .... 987654321 Conversion from single to 2-D array is fairly simple, and may be done within the magictesting function that we shall call 'TestMagic'... 111,112,113,121,122,123,131,132,133, 211,212,213,221,222,223,231,232,233, 311,312,313,321,322,323,331,332,333. ...using For loops.

It's as simple as:for i = 1 to 3 for j = 1 to 3 for k = 1 to 3 print i,j,k

Now, try it using recursion. Answer: Think of it this way: i loops from 1 to 3. For every value of i, j loops from 1 to 3. For every value of j, k loops from 1 to 3. For every value of k, the values are displayed. So, basically, these three loops perform very similar functions, which can therefore be reduced to a single recursive function with a single loop. void Func(n) { for i = 1 to 3 { A[n] = i if (n<3) Func(n+1) else print A[1],A[2],A[3] } } A[] is simply an array of integers. The function should be invoked with initial n value as 1, i.e., Func(1). Trace the program to figure out the output. For each pass through the loop, the function's child's loop is completely executed, by means of the recursive call. [A child of a given instance is the instance that it creates and calls.] Just in order to confuse you even more, the same function can be written in this way:void Func(n) { if (n<4)

{ for i = 1 to 3 { A[n] = i Func(n+1) } } else print A[1],A[2],A[3] } Anyway, coming back to our magic squares and our 9-length array which is to be permuted.... We can easily adopt the above functions, with one difference: the numbers should not repeat. If the numbers were allowed to repeat, we could easily write: void Permute(n) { for i = 1 to 9 { A[n] = i if (n<9) Permute(n+1) else TestMagic( ) } } A[] is the 9-length array.

The function should be called with n=1 initially. Function TestMagic checks whether the square represented by the array is magical, and displays it if it is so. However, we must not allow repetition, as per the rules and regulations of magic square authorities and environmental agencies worldwide. There could be several ways to perform this check, and it is left open to you. What I did was: I kept another 9-length array, which contained information about which number was used, and which was not. E.g.: Say B[] is the extra array. If B[2]=0, then, number 2 is still free. If B[2]=1, then, number 2 is already used. Whenever we 'go to' a recursive call and 'come back' from a recursive call, we should update this array. One possible algorithm could be:void Permute(n) { for i = 1 to 9 if B[i]=0 // if i is free { B[i]=1 A[n]=i if n<9 Permute(n+1) else TestMagic( ) //at the end B[i]=0 } } Note the way I set and reset the value of B[i]. For all deeper recursive instances of the function, value of B[i] is 1. And when we come back, we undo this change. Strictly speaking, the same concept is used while changing the value of variable n. The value of n sent to the child instance is different from the value of n in the current instance. And upon returning from the child instance, the value of n is reset to its old value. (This is taken care of automatically by the passing of parameters between the calls, so we don't have to //recurse

bother explicitly changing the value of n.) The rest is left to you. Try the program, and taste the results yourself. There are totally 8 solutions for the 3x3 matrix with numbers 1..9. Did you get them all? We have worked out this problem by realizing that we need to find all permutations of the numbers 1..9, and for each permutation, check if it satisfies the condition. There's another way of looking at the same thing, which is a common viewpoint when talking about recursion. It is called 'BackTracking'. In effect, what our program does is, when it finds (at the 9th recursion) that a square is not magical (say), it 'goes back' to the previous instance of the function, and even more back if needed. This is called BackTracking and is used in all recursive-problem-solving programs. Even if you own a 800MHz m/c, you may have noticed that the calculation took at least a few seconds, maybe longer. This is because the algorithm is not very efficient. It is possible to get all the results in under a second on any machine, if we tweak this algorithm here and there. That's what we'll do next. Tweak If you observe (and imagine) a bit... okay, more than just a bit.... you will realize that a LOT of the possibilities we test are actually quite useless. The first state is: 1 4 7 or 1 2 3 4 5 6 7 8 9 10. Now, the begins by permuting 8-9, then 7-8-9, then 6-7-8-9... which all takes time. All these are useless until we start permuting the top row, since 1+2+3=6, but we need 15. Get it? It's going to take a LOT of permutations before we finally backtrack to 3,2 and 1, which remain as sum 6 all this while. So, this 1-2-3 combination really sucks, and we should never allow it. 2 4 8 2 6 9

I wouldn't be describing this problem if I didn't know the answer, so here it is: While filling the numbers, at every row, we check if the sum is 15. So, before we go on to the second row (or the 4th element in our 1-D array) we check the sum of the first row - if it isn't 15, go back and permute... until the sum is 15. So, now the first row has a sum 15 (done very quickly since we permute only 3 locations) and all those useless permutations of the other two rows are not attempted. The same should happen for the second row, which saves some time, but not as much as that for the first row. Finally, after all 9 elements are inserted, check the columns and diagonals. Actually what happens is, if the sum of the first row elms is not 15, it backtracks until the sum is 15. If the sum is now 15, it 'goes forward' and checks the second row for sum 15. If second row sum is not 15, it backtracks to try to get the sum as 15. If all permutations within row 2 are complete, it backtracks to row 1... The following function checks the sum at every row. void Permute(n) { for i = 1 to 9 if B[i]=0 { B[i]=1 A[n]=i if (n % 3 = 0) // if n is div by 3 { if RowSum() = 15 { if n<9 Permute(n+1) else // at the end TestMagic() } // if i is free

} else Permute(n+1) //recurse B[i]=0 } } Tweak 2 Even the above program is a bit wasteful. Consider one of the cases in which the above program successfully fills the entire 9 locations (The row sums are all 15):1 2 3 5 6 4 9 7 8

This is by no means a magical square. Only the row sums are proper. What about the column sums? Look at column 1. Isn't it a little familiar? Right, we're back to the same old philosophies - this time, for the columns. A little thinking (for a guy like Einstein) or a lot of it (for you and me) will convince you that we also need to check and maintain column sums (as 15) along the way. So, we need to check both rows and columns. A little More thinking will convince you (poorly) that we need to fill the rows and columns alternatively to maximize efficiency (and confusion). At this point, keep in mind one of the greater truths that programmers (like you and me) live by: "The more complicated your program, the more you are respected." There are at least 2 good ways to alternate rows and columns. 1 a d g 2 b e h 3 c f i

1 2 3

The first way:

row1, column1, row2, column2, row3,column3. or, a-b-c-d-g-e-f-h-i. At c, check row1 sum. At g, check column1 sum. At f, check row 2 sum. At h, check column2 sum. At i check row3 and column3 sum and diagonals as well. So, with a very few 'fillings' we can extract the solutions. The second way: In a spiral pattern: row1,column3, row3(reverse), column1(rev), row 2, column2 or, a-b-c-f-i-h-g-d-e. At c, check row1. At i, check column3. At g, check row3. At d, check column1. At e, check row2, column2 and diagonals. And, there you have it. The solutions will pop out in a second. Exercises You should be able to solve these problems:1. Write a function using Recursion to display all anagrams of the word 'RECURSION'. 2. Write a function using Recursion to display all anagrams of any string entered by the user. 3. Write a function using Recursion to display all anagrams of a string entered by the user, in such a way that all its vowels are located at the end of every anagram. (E.g.: Recursion => Rcrsneuio, cRsnroieu, etc.) Optimize it. 4. Write a function using Recursion to do the following: You have 20 different cards. You have only 7 envelopes. You can therefore send only 7 cards. Display all possible ways you can fill the 7 envelopes. (Every card is different) 5. Same as above, except: Of the 20 cards, 5 are identical birthday cards, and 7 others are identical anniversary cards. Find all permutations, without repetitions. (Swapping two identical cards doesn't create a new permutation.)

6. Write a function using Recursion to crack a password. The password is of unknown length (maximum 10) and is made up of capital letters and digits. (Store the actual password in your program, just for checking whether the string currently obtained is the right password.) 7. Write a function using Recursion to do the following: You are the manager in a small factory. You have 7 workers and 7 jobs to be done. Each worker is assigned one and only one job. Each worker demands different pay for each job. (E.g.: Worker Sam demands $10 for welding, $15 for carpentry, etc. Worker Joe demands $12 for welding, $5 for carpentry, etc.) Find the job-assignment which works out cheapest for you.

Tic Tac Toe

( also know as: Noughts and crosses, X and Zero) This is one of the favorites when it comes to recursion. All the more pleasurable if you can program it yourself without reading this article. It isn't all that difficult if you give it a few days of thought. So give it a shot before you read the solutions I've provided. The game is itself quite simple, and very very famous. If you are one of the - less fortunate - who never played pencil-paper games in the middle of your 3rd grade Math class, or equivalently, if you're 72 and have forgotten how to play your favorite game of tic tac toe, read the intro to the game. Otherwise, take a sheet from somewhere, start scribbling and work on it - before you go on to read the rest of this article. Good Luck! The Game A 3x3 grid. 2 players. One player plays 'X', the other plays '0'. The players take turns. Each marks a free location with his/her symbol (X or 0). The first player to get 3 of his symbols in a straight line, either vertically, horizontally or diagonally, wins. If all 9 locations are filled without any winning line, the game is drawn. E.g.: 0 0 X X X o X

The player marking 'X' in the above game has won, since he managed to get 3 X's in a diagonal straight line. The Program Before we start off on the program, we should have a general idea of what we want it to do. So, let me make a few suggestions...The program should support the following game modes:

Human vs Human Human vs Computer Computer vs Computer

The first mode is trivial. Let's deal with the second mode. Once we are able to program the second mode, i.e., once we are able to make the Computer play a game, the third mode should become a trivial problem, and can be easily accomplished. In this article, I am not going to discuss anything about the interface and such (I leave this juicy stuff to you), instead, I concentrate only on the logic. First, let's look at it broadly. There could be two approaches the computer could take to play a game1) plan through the entire game at the start of the game itself, or 2) decide upon the best move at every turn. Planning the entire game is not worth from many points of view. Besides, there's nothing wrong with selecting the best move at every turn 'just in case' it messed up somewhere along the way and needs to start over. So, the computer should decide upon the move looking only at the future, and ignoring the past. To come to think of it, this is how we humans think - what has happened has happened, I'll just try my best from now on. Okay, so the Computer is going to select the best move at every one of its turns. If we have to program it to 'select', then obviously, the Computer has to check out each possible move, assigning 'goodness values' to each of them, and finally select the one with the

maximum goodness value. Let's assume that there already exists a function Goodness( ) which returns the goodness value of a particular move [We'll get to this function later]. So, the following function should be able to decide upon the best move: A - the 1 Dimensional 9-length array (as in Magic Squares) which represents the 2-D 3x3 grid. int SelectBestMove(player) // selects a move // for player 'player' { max = -100 for i = 1 to 9 if A[i] is free { mark A[i] value = Goodness( ) unmark A[i] if value > max { max = value best_locn = i } } return best_locn } Note: This is only the skeleton, just to show the logic. You'll have to add some beef to check for special conditions and prevent errors. So, it is enough if we call the above function every time the computer has to play. Now, the question is, how do we go about checking the Goodness( ) value ??? For starters, the function Goodness( ) can check if the player wins by playing that move. So we can have a Goodness( ) which simply searches for three in a line. If the function finds such a winning line, it returns a high goodness value of, say, 128. If it does not, it simply returns 0. This would work, but is definitely not good enough. It is equivalent to a child playing tictac-toe who simply searches for a place to get 3 in a row, without any deeper thinking, or future planning.

Let's try and scrutinize the way we humans play the game. First, we try to win in the current move (The above suggestion for Goodness( ) already does this). If we can't win in the current move, we try to make it as hard as possible for the opponent to win in the next move. Whatever we play, the opponent is then definitely going to select the best move for himself - in a way, he's going to compare the goodness values of all of his possible moves, and select the best one. If you think about it, the better this best-goodness-value that he obtains is, the worse it is for us. Right? So, in a way, we've got to select a move which gives him the worst best-goodness-value. Think about it for a while. You may not realize it, but in the above paragraph, we have effectively given the recursive definition for the solution of this problem. See: For each possible move we can make, we first check if that move would make us win. (If yes, return 128). Then, we check the best-goodness-value that the opponent gets. The better this value is, the worse ours, and vice versa. The value of his best-goodness-value would correspond to a value of our-goodness-value. The function should return whatever this value of our-goodnessvalue is. One simple way of calculating our-goodness-value from the opponent's bestgoodness-value is to take our-goodness-value as the negative of his best-goodness-value. So, the higher his is, the lower ours is. Ultimately, it's just a comparison of all goodness values, so the negative sign won't cause any problems. In fact, this way, if his bestgoodness-value is, say, -128, it means that our-goodness-value is +128, which is equivalent to saying, "I am sure to win in the next move, if I move here." Since we are using the negative-value idea, our recursive definition of Goodness( ) becomes: Goodness( ) 1) Check if opponent wins. If yes, return: -128. 2) For each possible next move, get -Goodness(opponent) 3) Finally, select the best (highest) of these values and return it. As you may see, the above works very well, despite the modifications. Suppose, in step 2, we select a move which is supposed to make us win. We call Goodness(opponent). In the new instance of Goodness, the opponent checks (in step 1) if we win. We do, so the

function returns -128. Since we are taking the negative of this value, we get +128, which is right! You can check similarly for other possibilities. The modification we made above requires a modification in our SelectBestMove( ) function that we defined earlier. The call to Goodness( ) should be changed from "value = Goodness()" to "value =
-Goodness()".

We'll see about the parameters next.

In order to toggle between the two players as we go recursively deeper into a given move, we'll use the 'negative' concept again. Let player = 1 denote Player1, and player = -1 denote Player2. Then, our recursive function call will be: value = -Goodness(-player). I hope that doesn't confuse you. Let's see the algorithm for Goodness( ):int Goodness(player) { if CheckWin(-player) return -128 max = -200 for i = 1 to 9 if A[i] is free { mark A[i] value = -Goodness(-player) unmark A[i] if value > max max = value } return max }

As in the previous code fragment, you'll need to fine-tune several aspects of this one, but it is generally trivial, and depends on your data structures and such. Also note that the function above does not recurse infinitely. Why? Because there will come a time (around the 9th recursion) when none of A[i] is free, which means it never enters the loop, and thus, simply returns. (It will have to return 0 - for draw) Okay, that takes care of most of it. But the program will still act kind of funny. Can you guess why? The answer is not obvious, but you may realize what's happening after you struggle with it for a few days. Let's see what the code above does in the following case: Suppose it is my turn, and there is a move I can make which will get me 3 in a row. Also, there is another move I could make which will definitely make me win in my next move. The above code treats both these as equivalent, since both have a goodness value of +128. So how do we go about telling the program "The sooner the better"? The answer naturally has to do with the goodness value. Somehow, the 'closer' wins have to have greater precedence. This means that the distant values have to be reduced to a smaller fraction by the time it reaches the main function, SelectBestMove( ). One simple way to do this is: replace the statement
value = -Goodness(-player) by value = -Goodness(-player) / 2

So, effectively, the priority of deeper instances keeps on diminishing. The effect is that the computer selects the move such that it wins as soon as possible. One last mention. Better Methods? There are some other possibilities we haven't yet looked into, which arguably, could be better than the logic above. You see, we have used the 'max' method, in which the computer selects the best possible move, which is the one with the maximum goodness value. This is fine and correct. However, the program also assumes that the opponent

selects the best move. As a result, the computer may not appear to play smartly against a normal or below-average opponent. One option available, though not guaranteed to improve all situations, is to take the average of the opponent's goodness value as the return value. This kind of generalizes the unpredictability of the opponent's moves. Maybe. Another option is the minmax method. Here, we don't use the negative of the opponent's best goodness value. Instead, we use his worst goodness value. Makes a lot of difference. I haven't tried it out. If you've tried it out successfully, tell me about it. Exercises First, get your tic-tac-toe program working. There's nothing like playing against your own game. Your own baby. 1. Write a program using Recursion to play the following game: There are 21 stones. Two players take turns picking the stones. Each player should take at least 1 stone, and a maximum of 4 stones at each turn. The player who picks the last stone is the loser.

Connect 4

(also know as: Plot 4, Go 4 it) This is a game very similar to Tic Tac Toe, but probably not as famous. It offers many more possibilities of games than the very restricted Tic-Tac-Toe. This introduces new philosophies into our world of Recursion. Fasten your seat-belts for a mind-blazing session into the intricacies of one of the best games I've known! The Game The actual game is played on a 7x7 grid rack. The rack is placed vertically, with an opening at the top. The players take turns dropping their coins into one of the 7 columns. The dropped coin rests on top of whatever was dropped into the same column earlier. Coins may not be dropped into a full column, ie, a column filled with 7 coins. The

objective of the game is to get 4 of the player's coins in a continuous line, either horizontally, vertically or diagonally. If all 49 cells are filled without a winner, the game is drawn. Eg: yellow wins in the following game.

The Program As you may already have realised, the program for this game should be very similar to that for Tic-Tac-Toe, as discussed in the previous section. Except that we don't have to check each cell at every move - just one in each column, i.e., there are 7 possible moves, not 49, at the start of the game. You could proceed as we did with tic tac toe, checking all possible moves, and recursing till a depth at which there are no further possible moves. You could try that... to find out the hard way about the limitations of Recursion. Let me explain. Let's go back to the Tic Tac Toe program. Assume each call to the CheckWin( ) function takes t seconds (possibly t = 0.0001). Consider the first move. There are 9 possibilities (which means 9 calls to the function). For each of these possibilities, there are 8 possibilities for the next move. For each of the 8, there are 7 further possibilities, and so on. Total time taken for the first move (approxiamately) = (9 x 8 x 7 x 6 x 5 x 4 x 3 x 2 x 1) x t which is, 9! x t. 9! = 362,880 9! x t = 36 seconds, assuming t = 0.0001 sec.s

Okay, forget about that. Now, let's see what happens if we do the same thing over here in Connect 4. Although incorrect technically, it is fair to assume there are 7 possibilities at every move, just for the sake of calculation [It is incorrect since, at some point, the columns start getting filled, and hence possibilities reduce]. Now, suppose the function which checks for a win takes some t seconds (t=0.0001). What happens in the first move? There are 7 possibilities. For each of these, there are 7 more possibilities... and so on 49 times! So, the total time taken = (7 raised to 49) x t, which is... a big number. Too big. Let us not check ALL possibilities at every move. Instead, let us just check the moves up to a depth of say, 5. In other words, we'll calculate (for each of our 7 possible moves) the opponent's 7 possible moves, who'll check for each of his 7 possible moves, our 7 possible moves,.... 5 times. In other words, the number of times the CheckWin( ) function is called is: 7 raised to 5 = 16807 Let's assume this takes just 1 second. Now, let's increase the recursive depth by 1. Number of times the CheckWin( ) function is called is now: 7 raised to 6 Time taken (depth 6) = 7 seconds Let's again increase recursive depth by 1. Time taken (depth 7) = 49 seconds and again... Time taken (depth 8) = 6 min.s and again... Time taken (depth 9) = 42 min.s and so on... A depth of 12 will require a time of more than 9 days. A depth of 16 will require 63 years.... So let's forget about a depth of 49, shall we? Limitations of Recursion

I guess it is obvious what the problem is after the evaluation above. In Mathematics, we would call the algorithms exponential. The time taken for each successive value of depth increases exponentially. This is the limitation of recursion which destroys its usefulness prematurely. It forces the algorithms to recurse to only a small depth. Even the almost exponential increase in computer speed nowadays hardly offsets the exponential increase in the amount of time required for an increased depth. Back to Connect 4. So, we're going to limit the depth of recursion. Or maybe we can provide the user with the choice for various depth levels, corresponding to increasing difficulty levels. It is obvious that the greater the depth the better the move, since the computer can look deeper into a given move, and look further 'ahead'. The basic algorithm would be:int Goodness(player, depth) { if CheckWin(-player) return -128 if depth=0 return 0 max = -200 for i = 1 to 7 if column i is not full { drop coin into column i value = -Goodness(-player,depth-1) / 2 remove coin from column i if value > max max = value } return max }

The depth variable mechanism makes sure the recursive descent does not continue beyond a certain value. Assuming a depth of 5, the function should first be called by :

value = -Goodness(-player,5)

The rest is very similar to Tic-Tac-Toe. Note that the time taken for any move is t x (7 raised to something). Therefore, it is very important that t be as small as possible. t represents the time taken for the CheckWin( ) function. This function is going to be executed some 7-raised-to-something times. So, this particular function should be as efficient (fast) as possible. For instance, the CheckWin( ) function should not check every row and column and diagonal for a possible win. Instead, it should check only the row and column and diagonals in which the last coin played resides. Further improvements are possible.

Alpha-Beta Pruning

This is a technique used for optimizing Recursion Trees. You'll know what Recursion Trees are in a minute. Basically, this alpha-beta pruning method helps speed up your recursive function ten-fold. Formidable though this term may seem, the concept is fairly straightforward. And it has the effect of nullifying much of the Limitations of Recursion we discussed earlier. First, you should understand what a Recursion Tree is. Recursion Tree Take the case of Connect 4. At the beginning of the game, there are 7 possible moves. This can be represented as:Eg: yellow wins in the following game.

For each of the 7 given possible moves, there are 7 possible moves.

This is a Recursion Tree. Level 0 corresponds to the topmost level (which is a call to the move-selecting function). Level 1 is deeper than level 0, level 3 is deeper than level 2, etc. (as you can see). Node 1 would occur first, then node 2, then node 3 and so on. On a given level, the nodes occur from left to right (or so we'll assume). For the sake of making it simpler to explain, assume that the Recursion is allowed only to a depth of 2, i.e., only till level 2. At level 2, the function calculates a goodness value based on the position of the coins, advantage, etc. [Which I haven't discussed.] So, we have something like this:-

Consider the entry into the d-subtree. At this point, we know that the current maximum on level 1 is 5 (node c). For the first node in the d-subtree, we obtain a value of 3. We now know that the maximum value on this level 2 cannot be less than 3. Following me?

And hence, the goodness value of the node d can by no means be greater than -3. Which is less than 5. So, the d-subtree is useless, and we can immediately abandon further pursuits in this sub-tree. We have thus saved checking 6 nodes. Suppose the recursive depth was 4, i.e., recurse till level 4, then we save checking 6x7x7 nodes - quite a bit of time is saved. Did you get the point? Summary. When checking a given node, if the maximum goodness value of the current level is greater than the negative of the goodness value of one of the node's children, then the node can be abandoned. Equivalently, when the goodness value of a given node is greater than the negative of the maximum goodness value in the level above, then the rest of the sibling nodes need not be checked. Using this method, a lot of time is saved and a lot of useless sub-trees are avoided. This method of "cutting off branches" is called Pruning (derived from the gardening term). Don't ask me what 'alpha' & 'beta' are supposed to mean in alpha-beta-pruning. All I know is it works. And it works wonderfully. I noticed that my game of Connect 4 increased in speed by over 12 times. Moreover, increasing the depth does not significantly increase the time taken. It doesn't seem exponential anymore! This method is applicable to all recursive functions which return a goodness value. So you can even use it with Tic Tac Toe. It doesn't need too much of a modification to implement. Go ahead, try it! And that concludes this wonderful tutorial.

Pointers A pointer is a variable that points at, or refers to, another variable. That is, if we have a pointer variable of type ``pointer to int,`` it might point to the int variable , or to the cell of the int array . Given a pointer variable, we can ask questions like, ``What's the value of

the variable that this pointer points to?'' Why would we want to have a variable that refers to another variable? Why not just use that other variable directly? The answer is that a level of indirection can be very useful. (Indirection is just another word for the situation when one variable refers to another.) Imagine a club which elects new officers each year. In its clubroom, it might have a set of mailboxes for each member, along with special mailboxes for the president, secretary, and treasurer. The bank doesn't mail statements to the treasurer under the treasurer's name; it mails them to ``treasurer,'' and the statements go to the mailbox marked ``treasurer.'' This way, the bank doesn't have to change the mailing address it uses every year. The mailboxes labeled ``president,'' ``treasurer,'' and ``secretary'' are a little bit like pointers--they don't refer to people directly. Basic Pointer Operations The first things to do with pointers are to declare a pointer variable, set it to point somewhere, and finally manipulate the value that it points to. A simple pointer declaration looks like this. int *ip; This declaration looks like our earlier declarations, with one obvious difference: that asterisk. The asterisk means that ip, the variable we're declaring, is not of type int, but rather of type pointer-to-int. (Another way of looking at it is that *ip, which as we'll see is the value pointed to by ip, will be an int.) We may think of setting a pointer variable to point to another variable as a two-step process: first we generate a pointer to that other variable, then we assign this new pointer to the pointer variable. We can say (but we have to be careful when we're saying it) that a pointer variable has a value, and that its value is ``pointer to that other variable''. This will make more sense when we see how to generate pointer values. Pointers (that is, pointer values) are generated with the ``address-of'' operator &, which

we can also think of as the ``pointer-to'' operator. We demonstrate this by declaring (and initializing) an int variable i, and then setting ip to point to it. int i = 5; ip = &i; The assignment expression ip = &i; contains both parts of the ``two-step process'' &i generates a pointer to i, and the assignment operator assigns the new pointer to (that is, places it ``in'') the variable ip. Now ip ``points to'' i, which we can illustrate with this picture

i is a variable of type int, so the value in its box is a number, 5. ip is a variable of type pointer-to-int, so the ``value'' in its box is an arrow pointing at another box. Referring once again back to the ``two-step process'' for setting a pointer variable: the & operator draws us the arrowhead pointing at i's box, and the assignment operator =, with the pointer variable ip on its left, anchors the other end of the arrow in ip's box. We discover the value pointed to by a pointer using the ``contents-of'' operator, *. Placed in front of a pointer, the * operator accesses the value pointed to by that pointer. In other words, if ip is a pointer, then the expression *ip gives us whatever it is that's in the variable or location pointed to by ip. For example, we could write something like printf("%d\n", *ip); which would print 5, since ip points to i, and i is (at the moment) 5. (You may wonder how the asterisk * can be the pointer contents-of operator when it is also the multiplication operator. There is no ambiguity here: it is the multiplication operator when it sits between two variables, and it is the contents-of operator when it sits in front of a single variable. The situation is analogous to the minus sign: between two variables or expressions it's the subtraction operator, but in front of a single operator or expression it's the negation operator. Technical terms you may hear for these distinct

roles are unary and binary: a binary operator applies to two operands, usually on either side of it, while a unary operator applies to a single operand.) The contents-of operator * does not merely fetch values through pointers; it can also set values through pointers. We can write something like *ip = 7; which means ``set whatever ip points to 7.'' Again, the * tells us to go to the location pointed to by ip, but this time, the location isn't the one to fetch from--we're on the lefthand sign of an assignment operator, so *ip tells us the location to store to. (The situation is no different from array subscripting expressions such as a[3] which we've already seen appearing on both sides of assignments.) The result of the assignment *ip = 7 is that i's value is changed to 7,

If we called printf("%d\n", *ip) again, it would now print 7. At this point, you may be wondering why we're going through this rigamarole--if we wanted to set i to 7, why didn't we do it directly? We'll begin to explore that next, but first let's notice the difference between changing a pointer (that is, changing what variable it points to) and changing the value at the location it points to. When we wrote *ip = 7, we changed the value pointed to by ip, but if we declare another variable j. int j = 3; ip = &j; we've changed ip itself.The picture now looks like this

We have to be careful when we say that a pointer assignment changes ``what the pointer points to.'' Our earlier assignment *ip = 7; changed the value pointed to by ip, but this more recent assignment ip = &j; has changed what variable ip points to. It's true that ``what ip points to'' has changed, but this time, it has changed for a different reason. Neither i (which is still 7) nor j (which is still 3) has changed. (What has changed is ip's value.) If we again call printf("%d\n", *ip); this time it will print 3. We can also assign pointer values to other pointer variables. If we declare a second pointer variable. int *ip2; ip2 = ip; Now ip2 points where ip does; we've essentially made a ``copy'' of the arrow.

Now, if we set ip to point back to i again.

ip = &i; the two arrows point to different places:

We can now see that the two assignments

ip2 = ip; *ip2 = *ip; do two very different things. The first would make ip2 again point to where ip points (in other words, back to i again). The second would store, at the location pointed to by ip2, a copy of the value pointed to by ip; in other words (if ip and ip2 still point to i and j respectively) it would set j to i's value, or 7. It's important to keep very clear in your mind the distinction between a pointer and what it points to. The two are like apples and oranges (or perhaps oil and water); you can't mix them. You can't ``set ip to 5'' by writing something like ip = 5; /* WRONG */

5 is an integer, but ip is a pointer. You probably wanted to ``set the value pointed to by ip to 5,'' which you express by writing . *ip = 5; Similarly, you can't ``see what ip is'' by writing printf("%d\n", ip); /* WRONG */ Again, ip is a pointer-to-int, but %d expects an int. To print what ip points to, use

printf("%d\n", *ip); Finally, a few more notes about pointer declarations. The * in a pointer declaration is related to, but different from, the contents-of operator *. After we declare a pointer variable int *ip; ip = &i sets what ip points to (that is, which location it points to), while the expression *ip = 5 sets the value of the location pointed to by ip. On the other hand, if we declare a pointer variable and include an initializer int *ip3 = &i; we're setting the initial value for ip3, which is where ip3 will point, so that initial value is a pointer. (In other words, the * in the declaration int *ip3 = &i; is not the contents-of operator, it's the indicator that ip3 is a pointer.) If you have a pointer declaration containing an initialization, and you ever have occasion to break it up into a simple declaration and a conventional assignment, do it like this int *ip3; ip3 = &i; Don't write int *ip3; *ip3 = &i; although the asterisk affects ip's type, it goes with the identifier name ip, not with the type int on the left. To declare two pointers at once, the declaration looks like

int *ip1, *ip2; Some people write pointer declarations like this int* ip; This works for one pointer, because C essentially ignores whitespace. But if you ever write int* ip1, ip2; /* PROBABLY WRONG */ it will declare one pointer-to-int ip1 and one plain int ip2, which is probably not what you meant. What is all of this good for? If it was just for changing variables like i from 5 to 7, it would not be good for much. What it's good for, among other things, is when for various reasons we don't know exactly which variable we want to change, just like the bank didn't know exactly which club member it wanted to send the statement to.

Pointers and Arrays; Pointer Arithmetic Pointers do not have to point to single variables. They can also point at the cells of an array. For example, we can write . int *ip; int a[10]; ip = &a[3]; and we would end up with ip pointing at the fourth cell of the array a (remember, arrays are 0-based, so a[0] is the first cell). We could illustrate the situation like this.

We'd use this ip just like the one in the previous section: *ip gives us what ip points to,

which in this case will be the value in a[3]. Once we have a pointer pointing into an array, we can start doing pointer arithmetic. Given that ip is a pointer to a[3], we can add 1 to ip ip + 1 What does it mean to add one to a pointer? In C, it gives a pointer to the cell one farther on, which in this case is a[4]. To make this clear, let's assign this new pointer to another pointer variable. ip2 = ip + 1; now The picture now looks like this

If we now do *ip2 = 4; we've set a[4] to 4. But it's not necessary to assign a new pointer value to a pointer variable in order to use it; we could also compute a new pointer value and use it immediately. *(ip + 1) = 5; In this last example, we've changed a[4] again, setting it to 5. The parentheses are needed because the unary ``contents of'' operator * has higher precedence (i.e., binds more tightly than) the addition operator. If we wrote *ip + 1, without the parentheses, we'd be fetching the value pointed to by ip, and adding 1 to that value. The expression *(ip + 1), on the other hand, accesses the value one past the one pointed to by ip.

Given that we can add 1 to a pointer, it's not surprising that we can add and subtract other numbers as well. If ip still points to a[3], then *(ip + 3) = 7; sets a[6] to 7, and *(ip - 2) = 4; sets a[1] to 4.Up above, we added 1 to ip and assigned the new pointer to ip2, but there's no reason we can't add one to a pointer, and change the same pointer. ip = ip + 1; Now ip points one past where it used to (to a[4], if we hadn't changed it in the meantime). The shortcuts we learned in a previous chapter all work for pointers, too: we could also increment a pointer using ip += 1; or ip++; Of course, pointers are not limited to ints. It's quite common to use pointers to other types, especially char. Here is the innards of the mystrcmp function written to use pointers. (mystrcmp, you may recall, compares two strings, character by character.) char *p1 = &str1[0], *p2 = &str2[0]; while(1) { if(*p1 != *p2) return *p1 - *p2; if(*p1 == '\0' || *p2 == '\0') return 0; p1++; p2++;

} The autoincrement operator ++ (like its companion, --) makes it easy to do two things at once. We've seen idioms like a[i++] which accesses a[i] and simultaneously increments i, leaving it referencing the next cell of the array a. We can do the same thing with pointers: an expression like *ip++ lets us access what ip points to, while simultaneously incrementing ip so that it points to the next element. The preincrement form works, too: *++ip increments ip, then accesses what it points to. Similarly, we can use notations like *ip-- and *--ip. As another example, here is the strcpy (string copy) loop from a previous chapter, rewritten to use pointers: char *dp = &dest[0], *sp = &src[0]; while(*sp != '\0') *dp++ = *sp++; *dp = '\0'; (One question that comes up is whether the expression *p++ increments p or what it points to. The answer is that it increments p. To increment what p points to, you can use (*p)++.) When you're doing pointer arithmetic, you have to remember how big the array the pointer points into is, so that you don't ever point outside it. If the array a has 10 elements, you can't access a[50] or a[-1] or even a[10] (remember, the valid subscripts for a 10-element array run from 0 to 9). Similarly, if a has 10 elements and ip points to a[3], you can't compute or access ip + 10 or ip - 5. (There is one special case: you can, in this case, compute, but not access, a pointer to the nonexistent element just beyond the end of the array, which in this case is &a[10]. This becomes useful when you're doing pointer comparisons, which we'll look at next.) Pointer Subtraction and Comparison

As we've seen, you can add an integer to a pointer to get a new pointer, pointing somewhere beyond the original (as long as it's in the same array). For example, you might write ip2 = ip1 + 3; Applying a little algebra, you might wonder whether ip2 - ip1 = 3 and the answer is, yes. When you subtract two pointers, as long as they point into the same array, the result is the number of elements separating them. You can also ask (again, as long as they point into the same array) whether one pointer is greater or less than another: one pointer is ``greater than'' another if it points beyond where the other one points. You can also compare pointers for equality and inequality: two pointers are equal if they point to the same variable or to the same cell in an array, and are (obviously) unequal if they don't. (When testing for equality or inequality, the two pointers do not have to point into the same array.) One common use of pointer comparisons is when copying arrays using pointers. Here is a code fragment which copies 10 elements from array1 to array2, using pointers. It uses an end pointer, ep, to keep track of when it should stop copying. int array1[10], array2[10]; int *ip1, *ip2 = &array2[0]; int *ep = &array1[10]; for(ip1 = &array1[0]; ip1 < ep; ip1++) *ip2++ = *ip1; As we mentioned, there is no element array1[10], but it is legal to compute a pointer to this (nonexistent) element, as long as we only use it in pointer comparisons like this (that is, as long as we never try to fetch or store the value that it points to.)

Null Pointers We said that the value of a pointer variable is a pointer to some other variable. There is one other value a pointer may have: it may be set to a null pointer. A null pointer is a special pointer value that is known not to point anywhere. What this means that no other valid pointer, to any other variable or array cell or anything else, will ever compare equal to a null pointer. The most straightforward way to ``get'' a null pointer in your program is by using the predefined constant NULL, which is defined for you by several standard header Files, including <stdio.h>, <stdlib.h>, and <string.h>. To initialize a pointer to a null pointer, you might use code like #include <stdio.h> int *ip = NULL; and to test it for a null pointer before inspecting the value pointed to you might use code like if(ip != NULL) printf("%d\n", *ip); It is also possible to refer to the null pointer by using a constant 0, and you will see some code that sets null pointers by simply doing int *ip = 0; (In fact, NULL is a preprocessor macro which typically has the value, or replacement text, 0.) Furthermore, since the definition of ``true'' in C is a value that is not equal to 0, you will see code that tests for non-null pointers with abbreviated code like if(ip) printf("%d\n", *ip);

This has the same meaning as our previous example; if(ip) is equivalent to if(ip != 0) and to if(ip != NULL). All of these uses are legal, and although I recommend that you use the constant NULL for clarity, you will come across the other forms, so you should be able to recognize them. You can use a null pointer as a placeholder to remind yourself (or, more importantly, to help your program remember) that a pointer variable does not point anywhere at the moment and that you should not use the ``contents of'' operator on it (that is, you should not try to inspect what it points to, since it doesn't point to anything). A function that returns pointer values can return a null pointer when it is unable to perform its task. (A null pointer used in this way is analogous to the EOF value that functions like getchar return.) #include <stddef.h> char *mystrstr(char input[], char pat[]) { char *start, *p1, *p2; for(start = &input[0]; *start != '\0'; start++) { /* for each position in input string... */ p1 = pat; /* prepare to check for pattern string there */ p2 = start; while(*p1 != '\0') { if(*p1 != *p2) /* characters differ */ break; p1++; p2++; } if(*p1 == '\0') /* found match */ return start;

} return NULL; } In general, C does not initialize pointers to null for you, and it never tests pointers to see if they are null before using them. If one of the pointers in your programs points somewhere some of the time but not all of the time, an excellent convention to use is to set it to a null pointer when it doesn't point anywhere valid, and to test to see if it's a null pointer before using it. But you must use explicit code to set it to NULL, and to test it against NULL. (In other words, just setting an unused pointer variable to NULL doesn't guarantee safety; you also have to check for the null value before using the pointer.) On the other hand, if you know that a particular pointer variable is always valid, you don't have to insert a paranoid test against NULL before using it.

``Equivalence'' between Pointers and Arrays There are a number of similarities between arrays and pointers in C. If you have an array int a[10]; you can refer to a[0], a[1], a[2], etc., or to a[i] where i is an int. If you declare a pointer variable ip and set it to point to the beginning of an array. int *ip = &a[0]; you can refer to *ip, *(ip+1), *(ip+2), etc., or to *(ip+i) where i is an int. There are also differences, of course. You cannot assign two arrays; the code int a[10], b[10]; a = b; /* WRONG */ is illegal. As we've seen, though, you can assign two pointer variables: int *ip1, *ip2; ip1 = &a[0];

ip2 = ip1; Pointer assignment is straightforward; the pointer on the left is simply made to point wherever the pointer on the right does. We haven't copied the data pointed to (there's still just one copy, in the same place); we've just made two pointers point to that one place. The similarities between arrays and pointers end up being quite useful, and in fact C builds on the similarities, leading to what is called ``the equivalence of arrays and pointers in C.'' When we speak of this ``equivalence'' we do not mean that arrays and pointers are the same thing (they are in fact quite different), but rather that they can be used in related ways, and that certain operations may be used between them. The first such operation is that it is possible to (apparently) assign an array to a pointer: int a[10]; int *ip; ip = a; What can this mean? In that last assignment ip = a, aren't we mixing apples and oranges again? It turns out that we are not; C defines the result of this assignment to be that ip receives a pointer to the first element of a. In other words, it is as if you had written ip = &a[0]; The second facet of the equivalence is that you can use the ``array subscripting'' notation [i] on pointers, too. If you write ip[3] it is just as if you had written *(ip + 3) So when you have a pointer that points to a block of memory, such as an array or a part of an array, you can treat that pointer ``as if'' it were an array, using the convenient [i] notation. In other words, at the beginning of this section when we talked about *ip,

*(ip+1), *(ip+2), and *(ip+i), we could have written ip[0], ip[1], ip[2], and ip[i]. As we'll see, this can be quite useful (or at least convenient). The third fact of the equivalence (which is actually a more general version of the first one we mentioned) is that whenever you mention the name of an array in a context where the ``value'' of the array would be needed, C automatically generates a pointer to the first element of the array, as if you had written &array[0]. When you write something like int a[10]; int *ip; ip = a + 3; it is as if you had written ip = &a[0] + 3; which (and you might like to convince yourself of this) gives the same result as if you had written ip = &a[3]; For example, if the character array char string[100]; contains some string, here is another way to find its length

int len; char *p; for(p = string; *p != '\0'; p++) len = p - string; After the loop, p points to the '\0' terminating the string. The expression p - string is equivalent to p - &string[0], and gives the length of the string. (Of course, we could also call strlen; in fact here we've essentially written another implementation of strlen.)

Arrays and Pointers as Function Arguments Earlier, we learned that functions in C receive copies of their arguments. (This means that C uses call by value; it means that a function can modify one of its arguments without modifying the value in the caller.) We didn't say so at the time, but when a function is called, the copies of the arguments are made as if by assignment. But since arrays can't be assigned, how can a function receive an array as an argument? The answer will explain why arrays are an apparent exception to the rule that functions cannot modify their arguments. We've been regularly calling a function getline like this char line[100]; getline(line, 100); with the intention that getline read the next line of input into the character array line. But in the previous paragraph, we learned that when we mention the name of an array in an expression, the compiler generates a pointer to its first element. So the call above is as if we had written char line[100]; getline(&line[0], 100); In other words, the getline function does not receive an array of char at all; it actually receives a pointer to char! As we've seen throughout this chapter, it's straightforward to manipulate the elements of an array using pointers, so there's no particular insurmountable difficulty if getline receives a pointer. One question remains, though: we had been defining getline with its line parameter declared as an array int getline(char line[], int max) { ... }

We mentioned that we didn't have to specify a size for the line parameter, with the explanation that getline really used the array in its caller, where the actual size was specified. But that declaration certainly does look like an array--how can it work when getline actually receives a pointer? We mentioned that we didn't have to specify a size for the line parameter, with the explanation that getline really used the array in its caller, where the actual size was specified. But that declaration certainly does look like an array--how can it work when getline actually receives a pointer? The answer is that the C compiler does a little something behind your back. It knows that whenever you mention an array name in an expression, it (the compiler) generates a pointer to the array's first element. Therefore, it knows that a function can never actually receive an array as a parameter. Therefore, whenever it sees you defining a function that seems to accept an array as a parameter, the compiler quietly pretends that you had declared it as accepting a pointer, instead. The definition of getline above is compiled exactly as if it had been written int getline(char *line, int max) { ... } Let's look at how getline might be written if we thought of its first parameter (argument) as a pointer, instead. int getline(char *line, int max) { int nch = 0; int c; max = max - 1; /* leave room for '\0' */ #ifndef FGETLINE while((c = getchar()) != EOF) #else

while((c = getc(fp)) != EOF) #endif { if(c == '\n') break; if(nch < max) { *(line + nch) = c; nch = nch + 1; } } if(c == EOF && nch == 0) return EOF; *(line + nch) = '\0'; return nch; } But, as we've learned, we can also use ``array subscript'' notation with pointers, so we could rewrite the pointer version of getline like this: int getline(char *line, int max) { int nch = 0; int c; max = max - 1; /* leave room for '\0' */ #ifndef FGETLINE while((c = getchar()) != EOF) #else while((c = getc(fp)) != EOF) #endif {

if(c == '\n') break; if(nch < max) { line[nch] = c; nch = nch + 1; } } if(c == EOF && nch == 0) return EOF; line[nch] = '\0'; return nch; } But this is exactly what we'd written before (see chapter 6, Sec. 6.3), except that the declaration of the line parameter is different. In other words, within the body of the function, it hardly matters whether we thought line was an array or a pointer, since we can use array subscripting notation with both arrays and pointers. These games that the compiler is playing with arrays and pointers may seem bewildering at first, and it may seem faintly miraculous that everything comes out in the wash when you declare a function like getline that seems to accept an array. The equivalence in C between arrays and pointers can be confusing, but it does work and is one of the central features of C. If the games which the compiler plays (pretending that you declared a parameter as a pointer when you thought you declared it as an array) bother you, you can do two things: Continue to pretend that functions can receive arrays as parameters; declare and use them that way, but remember that unlike other arguments, a function can modify the copy in its caller of an argument that (seems to be) an array.

Realize that arrays are always passed to functions as pointers, and always declare your functions as accepting pointers.

Strings and pointer

Because of the ``equivalence'' of arrays and pointers, it is extremely common to refer to and manipulate strings as character pointers, or char *'s. It is so common, in fact, that it is easy to forget that strings are arrays, and to imagine that they're represented by pointers. (Actually, in the case of strings, it may not even matter that much if the distinction gets a little blurred; there's certainly nothing wrong with referring to a character pointer, suitably initialized, as a ``string.'') Let's look at a few of the implications Any function that manipulates a string will actually accept it as a char * argument. The caller may pass an array containing a string, but the function will receive a pointer to the array's (string's) first element (character). The %s format in printf expects a character pointer. Although you have to use strcpy to copy a string from one array to another, you can use simple pointer assignment to assign a string to a pointer. The string being assigned might either be in an array or pointed to by another pointer. In other words, given . char string[] = "Hello, world!"; char *p1, *p2; p1 = string p2 = p1 line 3 and line 4 are legal (Remember, though, that when you assign a pointer, you're making a copy of the pointer but not of the data it points to. In the first example, p1 ends up pointing to the string in string. In the second example, p2 ends up pointing to the same string as p1. In any case, after a pointer assignment, if you ever change the string (or other data) pointed to, the change is ``visible'' to both pointers.

Many programs manipulate strings exclusively using character pointers, never explicitly declaring any actual arrays. As long as these programs are careful to allocate appropriate memory for the strings, they're perfectly valid and correct. When you start working heavily with strings, however, you have to be aware of one subtle fact. When you initialize a character array with a string constant char string[] = "Hello, world!"; you end up with an array containing the string, and you can modify the array's contents to your heart's content string[0] = 'J'; However, it's possible to use string constants (the formal term is string literals) at other places in your code. Since they're arrays, the compiler generates pointers to their first elements when they're used in expressions, as usual. That is, if you say char *p1 = "Hello"; int len = strlen("world"); it's almost as if you'd said char internal_string_1[] = "Hello"; char internal_string_2[] = "world"; char *p1 = &internal_string_1[0]; int len = strlen(&internal_string_2[0]); Here, the arrays named internal_string_1 and internal_string_2 are supposed to suggest the fact that the compiler is actually generating little temporary arrays every time you use a string constant in your code. However, the subtle fact is that the arrays which are ``behind'' the string constants are not necessarily modifiable. In particular, the compiler may store them in read-only-memory. Therefore, if you write . char *p3 = "Hello, world!"; p3[0] = 'J';

your program may crash, because it may try to store a value (in this case, the character 'J') into non writable memory. The moral is that whenever you're building or modifying strings, you have to make sure that the memory you're building or modifying them in is writable. That memory should either be an array you've allocated, or some memory which you've dynamically allocated by the techniques which we'll see in the next chapter. Make sure that no part of your program will ever try to modify a string which is actually one of the unnamed, unwritable arrays which the compiler generated for you in response to one of your string constants. (The only exception is array initialization, because if you write to such an array, you're writing to the array, not to the string literal which you used to initialize the array.) Breaking a Line into ``Words'' an earlier assignment, an ``extra credit'' version of a problem asked you to write a little checkbook balancing program that accepted a series of lines of the form deposit 1000 check 10 check 12.34 deposit 50 check 20 It was a surprising nuisance to do this in an ad hoc way, using only the tools we had at the time. It was easy to read each line, but it was cumbersome to break it up into the word (``deposit'' or ``check'') and the amount. I find it very convenient to use a more general approach: first, break lines like these into a series of whitespace-separated words, then deal with each word separately. To do this, we will use an array of pointers to char, which we can also think of as an ``array of strings,'' since a string is an array of char, and a pointer-to-char can easily point at a string. Here is the declaration of such an array: char *words[10];

This is the first complicated C declaration we've seen: it says that words is an array of 10 pointers to char. We're going to write a function, getwords, which we can call like this: int nwords; nwords = getwords(line, words, 10); where line is the line we're breaking into words, words is the array to be filled in with the (pointers to the) words, and nwords (the return value from getwords) is the number of words which the function finds. (As with getline, we tell the function the size of the array so that if the line should happen to contain more words than that, it won't overflow the array). Here is the definition of the getwords function. It finds the beginning of each word, places a pointer to it in the array, finds the end of that word (which is signified by at least one whitespace character) and terminates the word by placing a '\0' character after it. (The '\0' character will overwrite the first whitespace character following the word.) Note that the original input string is therefore modified by getwords: if you were to try to print the input line after calling getwords, it would appear to contain only its first word (because of the first inserted '\0'). #include <stddef.h> #include <ctype.h> getwords(char *line, char *words[], int maxwords) { char *p = line; int nwords = 0; while(1) { while(isspace(*p)) p++; if(*p == '\0')

return nwords; words[nwords++] = p; while(!isspace(*p) && *p != '\0') p++; if(*p == '\0') return nwords; *p++ = '\0'; if(nwords >= maxwords) return nwords; } } Each time through the outer while loop, the function tries to find another word. First it skips over whitespace (which might be leading spaces on the line, or the space(s) separating this word from the previous one). The isspace function is new: it's in the standard library, declared in the header File <ctype.h>, and it returns nonzero (``true'') if the character you hand it is a space character (a space or a tab, or any other whitespace character there might happen to be). When the function finds a non-whitespace character, it has found the beginning of another word, so it places the pointer to that character in the next cell of the words array. Then it steps though the word, looking at non-whitespace characters, until it finds another whitespace character, or the \0 at the end of the line. If it finds the \0, it's done with the entire line; otherwise, it changes the whitespace character to a \0, to terminate the word it's just found, and continues. (If it's found as many words as will fit in the words array, it returns prematurely.) Each time it finds a word, the function increments the number of words (nwords) it has found. Since arrays in C start at [0], the number of words the function has found so far is also the index of the cell in the words array where the next word should be stored. The function actually assigns the next word and increments nwords in one expression

words[nwords++] = p; out should convince yourself that this arrangement works, and that (in this case) the preincrement form words[++nwords] = p; /* WRONG */ would not behave as desired. When the function is done (when it finds the \0 terminating the input line, or when it runs out of cells in the words array) it returns the number of words it has found. Here is a complete example of calling getwords: char line[] = "this is a test"; int i; nwords = getwords(line, words, 10); for(i = 0; i < nwords; i++) printf("%s\n", words[i]);

Preprocessor Conceptually, the ``preprocessor'' is a translation phase that is applied to your source code before the compiler proper gets its hands on it. (Once upon a time, the preprocessor was a separate program, much as the compiler and linker may still be separate programs today.) Generally, the preprocessor performs textual substitutions on your source code, in three sorts of ways.

File inclusion: inserting the contents of another File into your source File, as if you had typed it all in there. Macro substitution: replacing instances of one piece of text with another. Conditional compilation: Arranging that, depending on various circumstances, certain parts of your source code are seen or not seen by the compiler at all.

The next three sections will introduce these three preprocessing functions.

The syntax of the preprocessor is different from the syntax of the rest of C in several respects. First of all, the preprocessor is ``line based.'' Each of the preprocessor directives we're going to learn about (all of which begin with the # character) must begin at the beginning of a line, and each ends at the end of the line. (The rest of C treats line ends as just another white space character, and doesn't care how your program text is arranged into lines.) Secondly, the preprocessor does not know about the Structure of C--about functions, statements, or expressions. It is possible to play strange tricks with the preprocessor to turn something which does not look like C into C (or vice versa). It's also possible to run into problems when a preprocessor substitution does not do what you expected it to, because the preprocessor does not respect the Structure of C statements and expressions (but you expected it to). For the simple uses of the preprocessor we'll be discussing, you shouldn't have any of these problems, but you'll want to be careful before doing anything tricky or outrageous with the preprocessor. (As it happens, playing tricky and outrageous games with the preprocessor is considered sporting in some circles, but it rapidly gets out of hand, and can lead to bewilderingly impenetrable programs.) File Inclusion A line of the form #include <File name.h> or #include "filename.h" causes the contents of the File name.h to be read, parsed, and compiled at that point. (After File name.h is processed, compilation continues on the line following the #include line.) For example, suppose you got tired of retyping external function prototypes such as extern int getline(char [], int); at the top of each source File. You could instead place the prototype in a header File, perhaps getline.h, and then simply place .

#include "getline.h" at the top of each source File where you called getline. (You might not find it worthwhile to create an entire header File for a single function, but if you had a package of several related function, it might be very useful to place all of their declarations in one header File.) As we may have mentioned, that's exactly what the Standard header Files such as stdio.h are--collections of declarations (including external function prototype declarations) having to do with various sets of Standard library functions. When you use #include to read in a header File, you automatically get the prototypes and other declarations it contains, and you should use header files, precisely so that you will get the prototypes and other declarations they contain. The difference between the <> and "" forms is where the preprocessor searches for filename.h. As a general rule, it searches for files enclosed in <> in central, standard directories, and it searches for files enclosed in "" in the ``current directory,'' or the directory containing the source file that's doing the including. Therefore, "" is usually used for header files you've written, and <> is usually used for headers which are provided for you (which someone else has written). The extension ``.h'', by the way, simply stands for ``header,'' and reflects the fact that #include directives usually sit at the top (head) of your source files, and contain global declarations and definitions which you would otherwise put there. (That extension is not mandatory--you can theoretically name your own header files anything you wish--but .h is traditional, and recommended.) As we've already begun to see, the reason for putting something in a header file, and then using #include to pull that header file into several different source files, is when the something (whatever it is) must be declared or defined consistently in all of the source files. If, instead of using a header file, you typed the something in to each of the source files directly, and the something ever changed, you'd have to edit all those source files, and if you missed one, your program could fail in subtle (or serious) ways due to the

mismatched declarations (i.e. due to the incompatibility between the new declaration in one source file and the old one in a source file you forgot to change). Placing common declarations and definitions into header files means that if they ever change, they only have to be changed in one place, which is a much more workable system. What should you put in header files?

External declarations of global variables and functions. We said that a global variable must have exactly one defining instance, but that it can have external declarations in many places. We said that it was a grave error to issue an external declaration in one place saying that a variable or function has one type, when the defining instance in some other place actually defines it with another type. (If the two places are two source files, separately compiled, the compiler will probably not even catch the discrepancy.) If you put the external declarations in a header file, however, and include the header wherever it's needed, the declarations are virtually guaranteed to be consistent. It's a good idea to include the header in the source file where the defining instance appears, too, so that the compiler can check that the declaration and definition match. (That is, if you ever change the type, you do still have to change it in two places: in the source file where the defining instance occurs, and in the header file where the external declaration appears. But at least you don't have to change it in an arbitrary number of places, and, if you've set things up correctly, the compiler can catch any remaining mistakes.)

Preprocessor macro definitions . Structure definitions. Typedef declarations . Defining instances of global variables. If you put these in a header file, and include the header file in more than one source file, the variable will end up multiply defined.

However, there are a few things not to put in header files.

Function bodies (which are also defining instances). You don't want to put these in headers for the same reason--it's likely that you'll end up with multiple copies

of the function and hence ``multiply defined'' errors. People sometimes put commonly-used functions in header files and then use #include to bring them (once) into each program where they use that function, or use #include to bring together the several source files making up a program, but both of these are poor ideas. It's much better to learn how to use your compiler or linker to combine together separately-compiled object files. Since header files typically contain only external declarations, and should not contain function bodies, you have to understand just what does and doesn't happen when you #include a header file. The header file may provide the declarations for some functions, so that the compiler can generate correct code when you call them (and so that it can make sure that you're calling them correctly), but the header file does not give the compiler the functions themselves. The actual functions will be combined into your program at the end of compilation, by the part of the compiler called the linker. The linker may have to get the functions out of libraries, or you may have to tell the compiler/linker where to find them. In particular, if you are trying to use a third-party library containing some useful functions, the library will often come with a header file describing those functions. Using the library is therefore a two-step process: you must #include the header in the files where you call the library functions, and you must tell the linker to read in the functions from the library itself.

Macro Definition and Substitution A preprocessor line of the form #define name text defines a macro with the given name, having as its value the given replacement text. After that (for the rest of the current source File), wherever the preprocessor sees that name, it will replace it with the replacement text. The name follows the same rules as ordinary identifiers (it can contain only letters, digits, and underscores, and may not begin with a digit). Since macros behave quite differently from normal variables (or functions), it is customary to give them names which are all capital letters (or at least which begin

with a capital letter). The replacement text can be absolutely anything--it's not restricted to numbers, or simple strings, or anything. The most common use for macros is to propagate various constants around and to make them more self-documenting. We've been saying things like char line[100]; ... getline(line, 100); but this is neither readable nor reliable; it's not necessarily obvious what all those 100's scattered around the program are, and if we ever decide that 100 is too small for the size of the array to hold lines, we'll have to remember to change the number in two (or more) places. A much better solution is to use a macro. #define MAXLINE 100 char line[MAXLINE]; ... getline(line, MAXLINE); Now, if we ever want to change the size, we only have to do it in one place, and it's more obvious what the words MAXLINE sprinkled through the program mean than the magic numbers 100 did. Since the replacement text of a preprocessor macro can be anything, it can also be an expression, although you have to realize that, as always, the text is substituted (and perhaps evaluated) later. No evaluation is performed when the macro is defined. For example, suppose that you write something like #define A 2 #define B 3 #define C A + B (this is a pretty meaningless example, but the situation does come up in practice). Then, later, suppose that you write

int x = C * 2; If A, B, and C were ordinary variables, you'd expect x to end up with the value 10. But let's see what happens. The preprocessor always substitutes text for macros exactly as you have written it. So it first substitites the replacement text for the macro C, resulting in int x = A + B * 2; Then it substitutes the macros A and B, resulting in int x = 2 + 3 * 2; Only when the preprocessor is done doing all this substituting does the compiler get into the act. But when it evaluates that expression (using the normal precedence of multiplication over addition), it ends up initializing x with the value 8! . To guard against this sort of problem, it is always a good idea to include explicit parentheses in the definitions of macros which contain expressions. If we were to define the macro C as #define C (A + B) then the declaration of x would ultimately expand to int x = (2 + 3) * 2; and x would be initialized to 10, as we probably expected. Notice that there does not have to be (and in fact there usually is not) a semicolon at the end of a #define line. (This is just one of the ways that the syntax of the preprocessor is different from the rest of C.) If you accidentally type .

#define MAXLINE 100; then when you later declare char line[MAXLINE]; the preprocessor will expand it to char line[100;]; /* WRONG */

/* WRONG */

which is a syntax error. This is what we mean when we say that the preprocessor doesn't know much of anything about the syntax of C--in this last example, the value or replacement text for the macro MAXLINE was the 4 characters 1 0 0 ; , and that's exactly what the preprocessor substituted (even though it didn't make any sense). Simple macros like MAXLINE act sort of like little variables, whose values are constant (or constant expressions). It's also possible to have macros which look like little functions (that is, you invoke them with what looks like function call syntax, and they expand to replacement text which is a function of the actual arguments they are invoked with) but we won't be looking at these yet Conditional Compilation The last preprocessor directive we're going to look at is #ifdef. If you have the sequence #ifdef name program text #else more program text #endif

in your program, the code that gets compiled depends on whether a preprocessor macro by that name is defined or not. If it is (that is, if there has been a #define line for a macro called name), then ``program text'' is compiled and ``more program text'' is ignored. If the

macro is not defined, ``more program text'' is compiled and ``program text'' is ignored. This looks a lot like an if statement, but it behaves completely differently: an if statement controls which statements of your program are executed at run time, but #ifdef controls which parts of your program actually get compiled. Just as for the if statement, the #else in an #ifdef is optional. There is a companion directive #ifndef, which compiles code if the macro is not defined (although the ``#else clause'' of an #ifndef directive will then be compiled if the macro is defined). There is also an #if directive which compiles code depending on whether a compile-time expression is true or false. (The expressions which are allowed in an #if directive are somewhat restricted, however, so we won't talk much about #if here.) Conditional compilation is useful in two general classes of situations

You are trying to write a portable program, but the way you do something is different depending on what compiler, operating system, or computer you're using. You place different versions of your code, one for each situation, between suitable #ifdef directives, and when you compile the progam in a particular environment, you arrange to have the macro names defined which select the variants you need in that environment. (For this reason, compilers usually have ways of letting you define macros from the invocation command line or in a configuration File, and many also predefine certain macro names related to the operating system, processor, or compiler in use. That way, you don't have to change the code to change the #define lines each time you compile it in a different environment.) For example, in ANSI C, the function to delete a File is remove. On older Unix systems, however, the function was called unlink. So if File name is a variable containing the name of a File you want to delete, and if you want to be able to compile the program under these older Unix systems, you might write

#ifdef unix unlink(filename); #else remove(filename);

#endif

Then, you could place the line #define unix at the top of the file when compiling under an old Unix system. (Since all you're using the macro unix for is to control the #ifdef, you don't need to give it any replacement text at all. Any definition for a macro, even if the replacement text is empty, causes an #ifdef to succeed.) (In fact, in this example, you wouldn't even need to define the macro unix at all, because C compilers on old Unix systems tend to predefine it for you, precisely so you can make tests like these.)

You want to compile several different versions of your program, with different features present in the different versions. You bracket the code for each feature with #ifdef directives, and (as for the previous case) arrange to have the right macros defined or not to build the version you want to build at any given time. This way, you can build the several different versions from the same source code. (One common example is whether you turn debugging statements on or off. You can bracket each debugging printout with #ifdef DEBUG and #endif, and then turn on debugging only when you need it.) For example, you might use lines like this.

#ifdef DEBUG printf("x is %d\n", x); #endif to print out the value of the variable x at some point in your program to see if it's what you expect. To enable debugging printouts, you insert the line . #define DEBUG at the top of the file, and to turn them off, you delete that line, but the debugging printouts quietly remain in your code, temporarily deactivated, but ready to reactivate if you find yourself needing them again later. (Also, instead of inserting and deleting the

#define

line, you might use a compiler flag such as -DDEBUG to define the macro DEBUG

from the compiler invocatin line.) Conditional compilation can be very handy, but it can also get out of hand. When large chunks of the program are completely different depending on, say, what operating system the program is being compiled for, it's often better to place the different versions in separate source files, and then only use one of the files (corresponding to one of the versions) to build the program on any given system. Also, if you are using an ANSI Standard compiler and you are writing ANSI-compatible code, you usually won't need so much conditional compilation, because the Standard specifies exactly how the compiler must do certain things, and exactly which library functions it much provide, so you don't have to work so hard to accommodate the old variations among compilers and libraries

Structure A Structure is a collection of variables under a single name. These variables can be of different types, and each has a name which is used to select it from the Structure. A Structure is a convenient way of grouping several pieces of related information together. A Structure can be defined as a new named type, thus extending the number of available types. It can use other Structures, arrays or pointers as some of its members, though this can get complicated unless you are careful. Basic Operations of Structure

A Structure type is usually defined near to the start of a File using a statement. Which defines and names a new type, allowing its use throughout the program. Structure usually occur just after the #define and #include statements in a file. struct { char name[30];

char course[50]; int age; int year; } student; This defines a new type student variables of type student can be declared as follows. Struct student st_rec; Notice how similar this is to declaring an int or float. The variable name is st_rec, it has members called name, course, age and year. Each member of a Structure can be used just like a normal variable, but its name will be a bit longer. To return to the examples above, member name of Structure st_rec will behave just like a normal array of char, however we refer to it by the name st_rec.name Here the dot is an operator which selects a member from a Structure. Where we have a pointer to a Structure we could dereference the pointer and then use dot as a member selector. This method is a little clumsy to type. Since selecting a member from a Structure pointer happens frequently, it has its own operator -> which acts as follows. Assume that st_ptr is a pointer to a Structure of type student We would refer to the name member as st_ptr -> name Arrays can also be Structure member. Element of Structure can be used like other ordinary variable. Structure can also used as array of objects for example. #include<stdio.h> #include<conio.h>

struct student { char name[30]; char course[50]; int age; int year; }; void main() { int i; struct student st_rec[5]; clrscr(); for(i=0;i<5;i++) { printf("Enter %d th Structure data",i); printf("\n Enter name"); scanf("%s",st_rec[i].name); printf("Enter Course"); scanf("%s",st_rec[i].course); printf(" Enter age"); scanf("%d",&st_rec[i].age); printf("\n Enter year"); scanf("%d",&st_rec[i].year); } printf("Students Recors"); for(i=0;i<5;i++) { printf("\n name"); printf("%s",st_rec[i].name); printf(" Course");

printf("%s",st_rec[i].course); printf(" age"); printf("%d",st_rec[i].age); printf(" year"); printf("%d",st_rec[i].year); } } Structures as Function Arguments A Structure can be passed as a function argument just like any other variable. This raises a few practical issues. Where we wish to modify the value of members of the Structure, we must pass a pointer to that Structure. This is just like passing a pointer to an int type argument whose value we wish to change. #include<stdio.h> #include<conio.h> struct complex { float real; float imag; }; void main() { struct complex c1,c2,c3; struct complex sum(struct complex,struct complex); clrscr(); printf("Enter First Complex Number"); printf("\n Enter Real Part"); scanf("%f",&c1.real); printf("Enter imaginary part"); scanf("%f",&c1.imag); printf("Enter Second Complex Number"); printf("\n Enter Real Part"); scanf("%f",&c2.real); printf("Enter imaginary part"); scanf("%f",&c2.imag); c3=sum(c1,c2); printf("%f",c3.real);

printf("%f",c3.imag); } struct complex sum( struct complex a,struct complex b) { struct complex c; c.real=a.real+b.real; c.imag=a.imag+b.imag; return c; } If we are only interested in one member of a Structure, it is probably simpler to just pass that member. This will make for a simpler function, which is easier to re-use. Of course if we wish to change the value of that member, we should pass a pointer to it. As we have seen, a Structure is a good way of storing related data together. It is also a good way of representing certain types of information. Complex numbers in mathematics inhabit a two dimensional plane (stretching in real and imaginary directions). These could easily be represented here by Union A union is a variable which may hold (at different times) objects of different sizes and types. That is a union hold only one member at a time. C uses the union statement to create unions, for example. union number { short shortnumber; long longnumber; double floatnumber; } anumber defines a union called number and an instance of it called a number. number is a union tag and acts in the same way as a tag for a Structure. All operation on union like that of Structure. Difference between Structure and union is Structure allocate storage space for all the members where as union allow only one member at a time. Application of union is when

we need only one member of a Structure for a particular application that time we can use union.

Files in C This section describes the use of C's input / output facilities for reading and writing Files How will we specify that we want to access a particular data File? It would theoretically be possible to mention the name of a File each time it was desired to read from or write to it. But such an approach would have a number of drawbacks. Instead, the usual approach (and the one taken in C's stdio library) is that you mention the name of the File once, at the time you open it. Thereafter, you use some little token--in this case, the File pointer-which keeps track (both for your sake and the library's) of which File you're talking about. Whenever you want to read from or write to one of the Files you're working with, you identify that File by using its File pointer (that is, the File pointer you obtained when you opened the File. As we'll see, you store File pointers in variables just as you store any other data you manipulate, so it is possible to have several Files open, as long as you use distinct variables to store the File pointers. You declare a variable to store a File pointer like this:

File *fp; The type File is predefined for you by <stdio.h>. It is a data Structure which holds the information the standard I/O library needs to keep track of the File for you. For historical reasons, you declare a variable which is a pointer to this File type. The name of the variable can (as for any variable) be anything you choose; it is traditional to use the letters fp in the variable name (since we're talking about a File pointer). If you were reading from two Files at once you'd probably use two File pointers:

*fp1, *fp2; If you were reading from one file and writing to another you might declare and input file pointer and an output file pointer. file *ifp, *ofp; Like any pointer variable, a file pointer isn't any good until it's initialized to point to something. (Actually, no variable of any type is much good until you've initialized it.) To actually open a file, and receive the ``token'' which you'll store in your file pointer variable, you call fopen. fopen accepts a file name (as a string) and a mode value indicating among other things whether you intend to read or write this file. (The mode variable is also a string.) To open the file input.dat for reading you might call ifp = fopen("input.dat", "r"); The mode string "r" indicates reading. Mode "w" indicates writing, so we could open output.dat for output like this. ofp = fopen("output.dat", "w"); The other values for the mode string are less frequently used. The third major mode is "a" for append. (If you use "w" to write to a File which already exists, its old contents will be discarded.) You may also add a + character to the mode string to indicate that you want to both read and write, or a b character to indicate that you want to do ``binary'' (as opposed to text) I/O. One thing to beware of when opening Files is that it's an operation which may fail. The requested File might not exist, or it might be protected against reading or writing. (These possibilities ought to be obvious, but it's easy to forget them.) fopen returns a null pointer if it can't open the requested File, and it's important to check for this case before going off and using fopen's return value as a File pointer. Every call to fopen will typically be followed with a test, like this. ifp = fopen("input.dat", "r"); if(ifp == NULL)

{ printf("can't open file\n"); exit or return } If fopen returns a null pointer, and you store it in your file pointer variable and go off and try to do I/O with it, your program will typically crash. It's common to collapse the call to fopen and the assignment in with the test. if((ifp = fopen("input.dat", "r")) == NULL) { printf("can't open File\n"); exit or return } You don't have to write these ``collapsed'' tests if you're not comfortable with them, but you'll see them in other people's code, so you should be able to read them. I/O with file Pointers For each of the I/O library functions we've been using so far, there's a companion function which accepts an additional File pointer argument telling it where to read from or write to. The companion function to printf is fprintf, and the File pointer argument comes first. To print a string to the output.dat File> we opened in the previous section, we might call . fprintf(ofp, "Hello, world!\n"); The companion function to getchar is getc, and the File pointer is its only argument. To read a character from the input.dat File we opened in the previous section, we might call. int c; c = getc(ifp); The companion function to putchar is putc, and the File pointer argument comes last. To write a character to output.dat, we could call .

putc(c, ofp); Our own getline function calls getchar and so always reads the standard input. We could write a companion fgetline function which reads from an arbitrary File pointer. #include <stdio.h> /* Read one line from fp, */ /* copying it to line array (but no more than max chars). */ /* Does not place terminating \n in line array. */ /* Returns line length, or 0 for empty line, or EOF for end-of-file. */ int fgetline(file *fp, char line[], int max) { int nch = 0; int c; max = max - 1; /* leave room for '\0' */ while((c = getc(fp)) != EOF) { if(c == '\n') break; if(nch < max) { line[nch] = c; nch = nch + 1; } } if(c == EOF && nch == 0) return EOF; line[nch] = '\0';

return nch; } Now we could read one line from ifp by calling char line[MAXLINE]; ... fgetline(ifp, line, MAXLINE);

Predefined Streams Besides the File pointers which we explicitly open by calling fopen, there are also three predefined streams. stdin is a constant File pointer corresponding to standard input, and stdout is a constant File pointer corresponding to standard output. Both of these can be used anywhere a File pointer is called for; for example, getchar() is the same as getc(stdin) and putchar(c) is the same as putc(c, stdout). The third predefined stream is stderr. Like stdout, stderr is typically connected to the screen by default. The difference is that stderr is not redirected when the standard output is redirected. For example, under Unix or MS-DOS, when you invoke program > File name anything printed to stdout is redirected to the File name, but anything printed to stderr still goes to the screen. The intent behind stderr is that it is the ``standard error output''; error messages printed to it will not disappear into an output File. For example, a more realistic way to print an error message when a File can't be opened would be if((ifp = fopen(Filename, "r")) == NULL) { fprintf(stderr, "can't open File %s\n", File name); exit or return } where File name is a string variable indicating the File name to be opened. Not only is the

error message printed to stderr, but it is also more informative in that it mentions the name of the File that couldn't be opened. Closing Files Although you can open multiple Files, there's a limit to how many you can have open at once. If your program will open many Files in succession, you'll want to close each one as you're done with it; otherwise the standard I/O library could run out of the resources it uses to keep track of open Files. Closing a File simply involves calling fclose with the File pointer as its argument: fclose(fp); Calling fclose arranges that (if the File was open for output) any last, buffered output is finally written to the File, and that those resources used by the operating system (and the C library) for this File are released. If you forget to close a File, it will be closed automatically when the program exits. Reading a Data File Suppose you wanted to read these numbers into an array. (Actually, the array will be an array of arrays, or a ``multidimensional'' array) We can write code to do this by putting together several pieces: the fgetline function we just showed, and the get words function from chapter 10. Assuming that the data File is named input.dat, the code would look like this. #define MAXLINE 100 #define MAXROWS 10 #define MAXCOLS 10 int array[MAXROWS][MAXCOLS]; char *Filename = "input.dat"; File *ifp; char line[MAXLINE]; char *words[MAXCOLS]; int nrows = 0;

int n; int i; ifp = fopen(Filename, "r"); if(ifp == NULL) { fprintf(stderr, "can't open %s\n", Filename); exit(EXIT_FAILURE); } while(fgetline(ifp, line, MAXLINE) != EOF) { if(nrows >= MAXROWS) { fprintf(stderr, "too many rows\n"); exit(EXIT_FAILURE); } n = getwords(line, words, MAXCOLS); for(i = 0; i < n; i++) array[nrows][i] = atoi(words[i]); nrows++; } Command Line Arguments We've mentioned several times that a program is rarely useful if it does exactly the same thing every time you run it. Another way of giving a program some variable input to work on is by invoking it with command line arguments. (We should probably admit that command line user interfaces are a bit old-fashioned, and currently somewhat out of favor. If you've used Unix or MS-DOS, you know what a command line is, but if your experience is confined to the Macintosh or Microsoft Windows or some other Graphical User Interface, you may never have seen a command line. In fact, if you're learning C on a Mac or under Windows, it can be tricky to give

your program a command line at all. Think C for the Macintosh provides a way; If your compilation environment doesn't provide an easy way of simulating an old-fashioned command line, you may skip this chapter.) C's model of the command line is that it consists of a sequence of words, typically separated by whitespace. Your main program can receive these words as an array of strings, one word per string. In fact, the C run-time startup code is always willing to pass you this array, and all you have to do to receive it is to declare main as accepting two parameters, like this.

int main(int argc, char *argv[]) { ... } When main is called, argc will be a count of the number of command-line arguments, and argv will be an array (``vector'') of the arguments themselves. Since each word is a string which is represented as a pointer-to-char, argv is an array-of-pointers-to-char. Since we are not defining the argv array, but merely declaring a parameter which references an array somewhere else (namely, in main's caller, the run-time startup code), we do not have to supply an array dimension for argv. (Actually, since functions never receive arrays as parameters in C, argv can also be thought of as a pointer-to-pointer-to-char, or char **. But multidimensional arrays and pointers to pointers can be confusing, and we haven't covered them, so we'll talk about argv as if it were an array.) (Also, there's nothing magic about the names argc and argv. You can give main's two parameters any names you like, as long as they have the appropriate types. The names argc and argv are traditional.) The first program to write when playing with argc and argv is one which simply prints its arguments #include <stdio.h>

main(int argc, char *argv[]) { int i; for(i = 0; i < argc; i++) printf("arg %d: %s\n", i, argv[i]); return 0; } If you run this program, you'll discover that the set of ``words'' making up the command line includes the command you typed to invoke your program (that is, the name of your program). In other words, argv[0] typically points to the name of your program, and argv[1] is the first argument. here are no hard-and-fast rules for how a program should interpret its command line. There is one set of conventions for Unix, another for MS-DOS, another for VMS. Typically you'll loop over the arguments, perhaps treating some as option flags and others as actual arguments (input Files, etc.), interpreting or acting on each one. Since each argument is a string, you'll have to use strcmp or the like to match arguments against any patterns you might be looking for. Remember that argc contains the number of words on the command line, and that argv[0] is the command name, so if argc is 1, there are no arguments to inspect. (You'll never want to look at argv[i], for i >= argc, because it will be a null or invalid pointer.) As another example, also illustrating fopen and the File I/O techniques of the previous chapter, here is a program which copies one or more input Files to its standard output. Since ``standard output'' is usually the screen by default, this is therefore a useful program for displaying Files. (It's analogous to the obscurely-named Unix cat command, and to the MS-DOS type command.) You might also want to compare this program to the character-copying program of section 6.2. #include <stdio.h>

main(int argc, char *argv[]) { int i; File *fp; int c; for(i = 1; i < argc; i++) { fp = fopen(argv[i], "r"); if(fp == NULL) { fprintf(stderr, "cat: can't open %s\n", argv[i]); continue; } while((c = getc(fp)) != EOF) putchar(c); fclose(fp); } return 0; } As a historical note, the Unix cat program is so named because it can be used to concatenate two Files together, like this. cat a b > c This illustrates why it's a good idea to print error messages to stderr, so that they don't get redirected. The ``can't open File'' message in this example also includes the name of the program as well as the name of the File. Yet another piece of information which it's usually appropriate to include in error messages is the reason why the operation failed, if known. For operating system

problems, such as inability to open a File, a code indicating the error is often stored in the global variable errno. The standard library function strerror will convert an errno value to a human-readable error message string. Therefore, an even more informative error message printout would be. fp = fopen(argv[i], "r"); if(fp == NULL) fprintf(stderr, "cat: can't open %s: %s\n", argv[i], strerror(errno)); If you use code like this, you can #include <errno.h> to get the declaration for errno, and <string.h> to get the declaration for strerror().

Memory Allocation In this chapter, we'll meet malloc, C's dynamic memory allocation function, and we'll cover dynamic memory allocation in some detail. As we begin doing dynamic memory allocation, we'll begin to see (if we haven't seen it already) what pointers can really be good for. Many of the pointer examples in the previous chapter (those which used pointers to access arrays) didn't do all that much for us that we couldn't have done using arrays. However, when we begin doing dynamic memory allocation, pointers are the only way to go, because what malloc returns is a pointer to the memory it gives us. (Due to the equivalence between pointers and arrays, though, we will still be able to think of dynamically allocated regions of storage as if they were arrays, and even to use array-like subscripting notation on them.) You have to be careful with dynamic memory allocation. malloc operates at a pretty ``low level''; you will often find yourself having to do a certain amount of work to manage the memory it gives you. If you don't keep accurate track of the memory which malloc has given you, and the pointers of yours which point to it, it's all too easy to

accidentally use a pointer which points ``nowhere'', with generally unpleasant results. (The basic problem is that if you assign a value to the location pointed to by a pointer: *p = 0; and if the pointer p points ``nowhere'', well actually it can be construed to point somewhere, just not where you wanted it to, and that ``somewhere'' is where the 0 gets written. If the ``somewhere'' is memory which is in use by some other part of your program, or even worse, if the operating system has not protected itself from you and ``somewhere'' is in fact in use by the operating system, things could get ugly.) Allocating Memory with malloc A problem with many simple programs, including in particular little teaching programs such as we've been writing so far, is that they tend to use fixed-size arrays which may or may not be big enough. We have an array of 100 ints for the numbers which the user enters and wishes to find the average of--what if the user enters 101 numbers? We have an array of 100 chars which we pass to getline to receive the user's input--what if the user types a line of 200 characters? If we're lucky, the relevant parts of the program check how much of an array they've used, and print an error message or otherwise gracefully abort before overflowing the array. If we're not so lucky, a program may sail off the end of an array, overwriting other data and behaving quite badly. In either case, the user doesn't get his job done. How can we avoid the restrictions of fixed-size arrays? The answers all involve the standard library function malloc. Very simply, malloc returns a pointer to n bytes of memory which we can do anything we want to with. If we didn't want to read a line of input into a fixed-size array, we could use malloc, instead. Here's the first step. #include <stdlib.h> char *line; int linelen = 100; line = malloc(linelen);

/* incomplete -- malloc's return value not checked */ getline(line, linelen); malloc is declared in <stdlib.h>, so we #include that header in any program that calls malloc. A ``byte'' in C is, by definition, an amount of storage suitable for storing one character, so the above invocation of malloc gives us exactly as many chars as we ask for. We could illustrate the resulting pointer like this

The 100 bytes of memory (not all of which are shown) pointed to by line are those allocated by malloc. (They are brand-new memory, conceptually a bit different from the memory which the compiler arranges to have allocated automatically for our conventional variables. The 100 boxes in the figure don't have a name next to them, because they're not storage for a variable we've declared.) As a second example, we might have occasion to allocate a piece of memory, and to copy a string into it with strcpy

char *p = malloc(15); /* incomplete -- malloc's return value not checked */ strcpy(p, "Hello, world!"); When copying strings, remember that all strings have a terminating \0 character. If you use strlen to count the characters in a string for you, that count will not include the trailing \0, so you must add one before calling malloc. char *somestring, *copy; ... copy = malloc(strlen(somestring) + 1); /* +1 for \0 */ /* incomplete -- malloc's return value not checked */ strcpy(copy, somestring);

What if we're not allocating characters, but integers? If we want to allocate 100 ints, how many bytes is that? If we know how big ints are on our machine (i.e. depending on whether we're using a 16- or 32-bit machine) we could try to compute it ourselves, but it's much safer and more portable to let C compute it for us. C has a sizeof operator, which computes the size, in bytes, of a variable or type. It's just what we need when calling malloc. To allocate space for 100 ints, we could call int *ip = malloc(100 * sizeof(int)); The use of the sizeof operator tends to look like a function call, but it's really an operator, and it does its work at compile time. Since we can use array indexing syntax on pointers, we can treat a pointer variable after a call to malloc almost exactly as if it were an array. In particular, after the above call to malloc initializes ip to point at storage for 100 ints, we can access ip[0], ip[1], ... up to ip[99]. This way, we can get the effect of an array even if we don't know until run time how big the ``array'' should be. (In a later section we'll see how we might deal with the case where we're not even sure at the point we begin using it how big an ``array'' will eventually have to be.) Our examples so far have all had a significant omission: they have not checked malloc's return value. Obviously, no real computer has an infinite amount of memory available, so there is no guarantee that malloc will be able to give us as much memory as we ask for. If we call malloc(100000000), or if we call malloc(10) 10,000,000 times, we're probably going to run out of memory. When malloc is unable to allocate the requested memory, it returns a null pointer. A null pointer, remember, points definitively nowhere. It's a ``not a pointer'' marker; it's not a pointer you can use. (As we said in section 9.4, a null pointer can be used as a failure return from a function that returns pointers, and malloc is a perfect example.) Therefore, whenever you call malloc, it's vital to check the returned pointer before using it! If you

call malloc, and it returns a null pointer, and you go off and use that null pointer as if it pointed somewhere, your program probably won't last long. Instead, a program should immediately check for a null pointer, and if it receives one, it should at the very least print an error message and exit, or perhaps figure out some way of proceeding without the memory it asked for. But it cannot go on to use the null pointer it got back from malloc in any way, because that null pointer by definition points nowhere. (``It cannot use a null pointer in any way'' means that the program cannot use the * or [] operators on such a pointer value, or pass it to any function that expects a valid pointer.) A call to malloc, with an error check, typically looks something like this int *ip = malloc(100 * sizeof(int)); if(ip == NULL) { printf("out of memory\n"); exit or return } After printing the error message, this code should return to its caller, or exit from the program entirely; it cannot proceed with the code that would have used ip. Of course, in our examples so far, we've still limited ourselves to ``fixed size'' regions of memory, because we've been calling malloc with fixed arguments like 10 or 100. (Our call to getline is still limited to 100-character lines, or whatever number we set the linelen variable to; our ip variable still points at only 100 ints.) However, since the sizes are now values which can in principle be determined at run-time, we've at least moved beyond having to recompile the program (with a bigger array) to accommodate longer lines, and with a little more work, we could arrange that the ``arrays'' automatically grew to be as large as required. (For example, we could write something like getline which could read the longest input line actually seen.) We'll begin to explore this possibility in a later section.

Freeing Memory

Memory allocated with malloc lasts as long as you want it to. It does not automatically disappear when a function returns, as automatic-duration variables do, but it does not have to remain for the entire duration of your program, either. Just as you can use malloc to control exactly when and how much memory you allocate, you can also control exactly when you deallocate it. In fact, many programs use memory on a transient basis. They allocate some memory, use it for a while, but then reach a point where they don't need that particular piece any more. Because memory is not inexhaustible, it's a good idea to deallocate (that is, release or free) memory you're no longer using. Dynamically allocated memory is deallocated with the free function. If p contains a pointer previously returned by malloc, you can call free(p);

which will ``give the memory back'' to the stock of memory (sometimes called the ``arena'' or ``pool'') from which malloc requests are satisfied. Calling free is sort of the ultimate in recycling: it costs you almost nothing, and the memory you give back is immediately usable by other parts of your program. (Theoretically, it may even be usable by other programs.) (Freeing unused memory is a good idea, but it's not mandatory. When your program exits, any memory which it has allocated but not freed should be automatically released. If your computer were to somehow ``lose'' memory just because your program forgot to free it, that would indicate a problem or deficiency in your operating system.) Naturally, once you've freed some memory you must remember not to use it any more. After calling

free(p);

it is probably the case that p still points at the same memory. However, since we've given it back, it's now ``available,'' and a later call to malloc might give that memory to some other part of your program. If the variable p is a global variable or will otherwise stick around for a while, one good way to record the fact that it's not to be used any more would be to set it to a null pointer. free(p); p = NULL; Now we don't even have the pointer to the freed memory any more, and (as long as we check to see that p is non-NULL before using it), we won't misuse any memory via the pointer p. When thinking about malloc, free, and dynamically-allocated memory in general, remember again the distinction between a pointer and what it points to. If you call malloc to allocate some memory, and store the pointer which malloc gives you in a local pointer variable, what happens when the function containing the local pointer variable returns? If the local pointer variable has automatic duration (which is the default, unless the variable is declared static), it will disappear when the function returns. But for the pointer variable to disappear says nothing about the memory pointed to! That memory still exists and, as far as malloc and free are concerned, is still allocated. The only thing that has disappeared is the pointer variable you had which pointed at the allocated memory. (Furthermore, if it contained the only copy of the pointer you had, once it disappears, you'll have no way of freeing the memory, and no way of using it, either. Using memory and freeing memory both require that you have at least one pointer to the memory!) Reallocating Memory Blocks Sometimes you're not sure at first how much memory you'll need. For example, if you need to store a series of items you read from the user, and if the only way to know how many there are is to read them until the user types some ``end'' signal, you'll have no way of knowing, as you begin reading and storing the first few, how many you'll have seen by

the time you do see that ``end'' marker. You might want to allocate room for, say, 100 items, and if the user enters a 101st item before entering the ``end'' marker, you might wish for a way to say ``uh, malloc, remember those 100 items I asked for? Could I change my mind and have 200 instead?'' In fact, you can do exactly this, with the realloc function. You hand realloc an old pointer (such as you received from an initial call to malloc) and a new size, and realloc does what it can to give you a chunk of memory big enough to hold the new size. For example, if we wanted the ip variable from an earlier example to point at 200 ints instead of 100, we could try calling ip = realloc(ip, 200 * sizeof(int));

Since you always want each block of dynamically-allocated memory to be contiguous (so that you can treat it as if it were an array), you and realloc have to worry about the case where realloc can't make the old block of memory bigger ``in place,'' but rather has to relocate it elsewhere in order to find enough contiguous space for the new requested size. realloc does this by returning a new pointer. If realloc was able to make the old block of memory bigger, it returns the same pointer. If realloc has to go elsewhere to get enough contiguous memory, it returns a pointer to the new memory, after copying your old data there. (In this case, after it makes the copy, it frees the old block.) Finally, if realloc can't find enough memory to satisfy the new request at all, it returns a null pointer. Therefore, you usually don't want to overwrite your old pointer with realloc's return value until you've tested it to make sure it's not a null pointer. You might use code like this. int *newp; newp = realloc(ip, 200 * sizeof(int)); if(newp != NULL) ip = newp; else { printf("out of memory\n"); /* exit or return */ /* but ip still points at 100 ints */ }

If realloc returns something other than a null pointer, it succeeded, and we set ip to what it returned. (We've either set ip to what it used to be or to a new pointer, but in either case, it points to where our data is now.) If realloc returns a null pointer, however, we hang on to our old pointer in ip which still points at our original 100 values. Putting this all together, here is a piece of code which reads lines of text from the user, treats each line as an integer by calling atoi, and stores each integer in a dynamicallyallocated ``array'': #define MAXLINE 100 char line[MAXLINE]; int *ip; int nalloc, nitems; nalloc = 100; ip = malloc(nalloc * sizeof(int)); /* initial allocation */ if(ip == NULL) { printf("out of memory\n"); exit(1); } nitems = 0; while(getline(line, MAXLINE) != EOF) { if(nitems >= nalloc) { /* increase allocation */ int *newp; nalloc += 100; newp = realloc(ip, nalloc * sizeof(int)); if(newp == NULL) { printf("out of memory\n"); exit(1); } ip = newp; } ip[nitems++] = atoi(line); }

We use two different variables to keep track of the ``array'' pointed to by ip. nalloc is how many elements we've allocated, and nitems is how many of them are in use. Whenever we're about to store another item in the ``array,'' if nitems >= nalloc, the old ``array'' is full, and it's time to call realloc to make it bigger. Finally, we might ask what the return type of malloc and realloc is, if they are able to return pointers to char or pointers to int or (though we haven't seen it yet) pointers to any other type. The answer is that both of these functions are declared (in <stdlib.h>) as returning a type we haven't seen, void * (that is, pointer to void). We haven't really seen type void, either, but what's going on here is that void * is specially defined as a ``generic'' pointer type, which may be used (strictly speaking, assigned to or from) any pointer type. Pointer Safety At the beginning of the previous chapter, we said that the hard thing about pointers is not so much manipulating them as ensuring that the memory they point to is valid. When a pointer doesn't point where you think it does, if you inadvertently access or modify the memory it points to, you can damage other parts of your program, or (in some cases) other programs or the operating system itself! When we use pointers to simple variables, as in section 10.1, there's not much that can go wrong. When we use pointers into arrays, as in section 10.2, and begin moving the pointers around, we have to be more careful, to ensure that the roving pointers always stay within the bounds of the array(s). When we begin passing pointers to functions, and especially when we begin returning them from functions (as in the strstr function of section 10.4) we have to be more careful still, because the code using the pointer may be far removed from the code which owns or allocated the memory. One particular problem concerns functions that return pointers. Where is the memory to which the returned pointer points? Is it still around by the time the function returns? The

strstr function returns either a null pointer (which points definitively nowhere, and which the caller presumably checks for) or it returns a pointer which points into the input string, which the caller supplied, which is pretty safe. One thing a function must not do, however, is return a pointer to one of its own, local, automatic-duration arrays. Remember that automatic-duration variables (which includes all non-static local variables), including automatic-duration arrays, are deallocated and disappear when the function returns. If a function returns a pointer to a local array, that pointer will be invalid by the time the caller tries to use it. Finally, when we're doing dynamic memory allocation with malloc, realloc, and free, we have to be most careful of all. Dynamic allocation gives us a lot more flexibility in how our programs use memory, although with that flexibility comes the responsibility that we manage dynamically allocated memory carefully. The possibilities for misdirected pointers and associated mayhem are greatest in programs that make heavy use of dynamic memory allocation. You can reduce these possibilities by designing your program in such a way that it's easy to ensure that pointers are used correctly and that memory is always allocated and deallocated correctly. (If, on the other hand, your program is designed in such a way that meeting these guarantees is a tedious nuisance, sooner or later you'll forget or neglect to, and maintenance will be a nightmare.)

Introduction to Data Structures

The logical inter-relation between elementary data items is called as data structure. The basic data items include integers, bits, characters.
Basically it deals with manipulation and organization of data, solving problems with computer involves data manipulation. But the

data available will usually be in amorphous form. When D={d,F,A}

different types of such data are related to each other, then we call it to be a data structure.

Where,

D : Data structure d : Domain variable F : A set of functions or procedures operating on domain variables. A : A set of axioms or rules which governing the operations of these functions on the domain variable.
Advantages

The major advantages of data structures are : It gives different level of organizing data. It tells how data can be stored and accessed in its elementary level
Operation on Data Structures

The operations that can be performed on data structures are : This operation creates a data structure. The declaration statement causes space to be created for data upon entering at execution time.
Creation :

This operation destroys the data structure and aids in the efficient use of memory.
Destroy :

This operation is used to access data within a data structure. The form of selection depends on the type of data structure being accessed.
Selection :

This operation changes or modifies the data in the data structure and it is an important property in selection operation.
Update : Types of Data Structures Linear Data Structure : Stacks, Non-linear Data Structure

Queues, Linked Lists, etc.

: Trees, Graphs, etc.


Back to Basics

Array is an ordered set which consists of a fixed number of objects. No deletion or insertion operations are performed on arrays. List : List on the other hand is an ordered set containing of a variable number of elements to which insertions and deletions can be made. The list is divided into two types :
Array :

File :

Stacks and Queues.

File is typically a large list that is stored in the external memory of a computer. Ex: Magnetic disk.

Notations Types of Notations : Infix notation Prefix notation Postfix notation

Consider the sum of A and B. We think of applying the operator + to the operands A and B to write the sum as A+B. This particular representation is called Infix notation. There are two alternate notations for expressing the sum of A and B using the symbols A, B and +. These are + A B Prefix notation A B + Postfix notation The prefixes pre-, post- and in- refer to the relative position of the operator with respect to the two operands. In Prefix notation the operator precede the two operands, In Postfix notation the operator follows the two operands and In Infix notation the operator is between the two operands. The evaluation of the expression A + B * C, as written in standard infix notation, requires knowledge of which of the two operations, + or *, is to be performed first. In the case of + and *, we know that multiplication is to be done before addition (in the absence of parenthesis to the contrary). Thus A+B*C is interpreted as A + ( B * C ) unless otherwise specified. We say that multiplication takes precedence over addition. Suppose that we want to rewrite A + B * C in postfix. Applying the rules of precedence, we first convert the portion of the expression that is evaluated first, namely the multiplication. By doing

this conversion in stages, we obtain : A + ( B * C ) Paranthesis for emphasis A + ( BC* ) Convert the multiplication A ( BC* ) + Convert the addition ABC*+ Postfix form The only rules to remember during the conversion process are that operations with highest precedence are converted first and that after a portion of the expression has been converted to postfix, it is to be treated as a single operand. Consider the same example with the precedence of operators reversed by the deliberate insertion of parenthesis. ( A + B ) * C Infix form ( AB+ ) * C Convert the addition ( AB+ ) C * Convert the multiplication AB+C* Postfix form In the above example the addition is converted before the multiplication because of the parenthesis. In going from ( A + B ) * C to ( AB+ ) * C, A and B are the operands and + is the operator. In going from ( AB+ ) * C to ( AB+ ) C *, ( AB+ ) and C are the operands and * is the operator. The rules for converting from infix to postfix are simple, providing that you know the order of precedence.
ALGORITHM : Infix to Postfix

STEP 1 : Read the given infix expression into string called infix. STEP 2 : Read one character at a time and perform the following operations : 1. If the read character is an operand, then add the operand to the postfix string. 2. If the read character is not an operand, then check If the stack is not empty and precedence of the top of the stack operator is higher than the read operator, then pop the operator from stack and add this

operator to the postfix string. Else push the operator onto the stack. STEP 3 : Repeat STEP 2 till all characters are processed from the input string. STEP 4 : If stack is not empty, then pop the operator from stack and add this operator to the postfix string. STEP 5 : Repeat STEP 4 till all the operators are popped from the stack. STEP 6 : Display the result of given infix expression or resultant postfix expression stored in a string called postfix from this algorithm. Infix to postfix expression - SOURCE CODE
Infix to Prefix Expression :Algorithm

STEP 1 : Read the given infix expression into string called infix. STEP 2 : Reverse the infix string and read one character at a time and perform the following operations : If the read character is an operand, then add the operand to the prefix string. If the read character is not an operand, then check If the stack is not empty and precedence of the top of the stack operator is higher than the read operator, then pop the operator from stack and add this operator to the prefix string. Else push the operator onto the stack. STEP 3 : Repeat STEP 2 till all characters are processed from the input string. STEP 4 : If stack is not empty, then pop the operator from stack and add this operator to the prefix string. STEP 5 : Repeat STEP 4 till all the operators are popped from the stack.

STEP 6 : Reverse the prefix string and display the result of the given infix expression or the resultant prefix expression stored in a string called prefix from this algorithm. Infix to prefix expression - SOURCE CODE
Postfix Expression :Algorithm

STEP 1 : Read the given postfix expression into a string called postfix. STEP 2 : Read one character at a time & perform the following operations : 1. If the read character is an operand, then convert it to float and push it onto the stack. 2. If the character is not an operand, then pop the operator from stack and assign to OP2. Similarly, pop one more operator from stack and assign to OP1. 3. Evaluate the result based on operator x. 4. Push the result (based on operator x) onto the stack. STEP 3 : Repeat STEP 2 till all characters are processed from the input string. STEP 4 : Return the result from this procedure or algorithm and display the result in main program. Evaluation of a postfix expression

About Stacks

Lists permit the insertion or deletion of an element to occur only at one end. A linear list belonging to this subclass is called a stack. They are also referred to as pushdown lists. The insertion operation is referred to as PUSH and the deletion operation as POP. The most accessible element in a stack is known as the TOP of the stack.

Since insertion and deletion operations are performed at one end of stack, the elements can only be removed in the opposite order from that in which they were added to the stack. Such a linear list is frequently referred to as a LIFO ( Last-In First-Out ) LIST. picture An example of stack is the in tray of a busy executive. The files pile up in the tray and whenever the executive has time to clear the files, he/she takes it off from the top. That is, files are added at the top and removed from the top. Therefore stacks are sometimes referred to as LIFO structure. A pointer TOP A pointer TOP keeps track of the top element in the stack. Initially when the stack is empty, TOP has a value of 1 and when the stack contains a single element, TOP has a value of 0 ( Zero ) and so on. Each time a new element is inserted in the stack, the pointer is incremented by 1. The pointer decrements by 1 each time a deletion is made from the stack.
STACK STRUCTURE D={d,F,A}

Where, d : Array or a node (structure) d = { a , TOP } Here, a : Simple array or structure TOP : Index or Pointer F : PUSH, POP, DISPLAY, MODIFY A : EMPTY, OVERFLOW, UNDERFLOW
ALGORITHM : STACK

Procedure PUSH(S,TOP,X) : This procedure inserts an element X to the top of the stack which is represented by a vector S consisting MAX elements with a pointer TOP denoting the top element in the stack. STEP 1 : [Check for stack underflow] If (TOP>=max-1) then write(stack overflow) Return STEP 2 : [Increment TOP] TOP <-- TOP+1 STEP 3 : [Insert element] S[TOP] <-- X STEP 4 : [Finished] Return The first step of this algorithm checks for an overflow condition. If such a condition exists, then the insertion can't be performed and an appropriate error message results. Procedure POP(S,TOP,X) : This procedure removes top element from the stack. STEP 1 : [Check for the underflow on stack] If (TOP<0) then write(stack underflow) Return STEP 2 : [Hold the former top element of stack into X] X <-- S[TOP] STEP 3 : [Decrement the TOP pointer or index by 1] TOP <-- TOP-1 STEP 4 : [finished-Return the popped item from the stack] Return(X)

As Underflow condition is checked for in the first step of the algorithm. If such a condition exists, then the deletion cannot be performed and an appropriate error message results. Procedure Display(S,TOP) : This procedure displays the contents of the stack i.e., vector S. STEP 1 : [check for empty on stack] if (TOP==-1) then write('stack empty') Return STEP 2 : [Repeat through STEP 3 from i=TOP to 0] Repeat through STEP 3 for i=TOP to 0 STEP-1] STEP 3 : [Display the stack content] write (S[i]) STEP 4 : [Finished] Return The first step of this algorithm checks for an empty condition. If such a condition exists, then the contents of the stack cannot be displayed and an appropriate error message results. Complete Source code of Stack written in C.
About Queues

Lists permit deletions to be performed at one end of a list and insertions at the other end. The information in such a list is processed in the same order as it was received, i.e. on a first-in, first-out (FIFO) or first-come first-serve (FCFS) basis. This type of list is referred to as a Queue.
QUEUE STRUCTURE

D={d,F,A} Where, d : Array or a node (structure) d = { a , FRONT, REAR } Here, a : Simple array or structure FRONT : Pointer to the front element of a queue REAR : Pointer to the rear element of a queue F : QINSERT, QDELETE, Q DISPLAY, QMODIFY A : QFULL, QEMPTY
Types of Queues Linear Queue Circular Queue Priority Queue

The insertion operation is referred to as QINSERT and the deletion operation as QDELETE. We can insert an item at the rear end using QINSERT and remove an item at the front end using QDELETE as shown in the fig(a).

Picture
A pointer FRONT and REAR FRONT and REAR, pointers to the front and rear elements of queue respectively. Each time a new element is inserted in the queue, the REAR pointer is incremented by 1. The FRONT pointer is incremented by 1 each time a deletion is made from the queue. FRONT and REAR pointers should be reset to -1 once they are found equal. ALGORITHM : LINEAR QUEUE

Procedure QINSERT(Q,F,MAX,X) : Given F and R, pointers to the front and rear elements of a queue. A QUEUE Q consisting of MAX elements and an element X. this procedure inserts X at the rear end of the queue prior to the first invocation of the

procedure, F and R have been set to -1.


Non-linear Data Structure

: Trees, Graphs, etc.


ALGORITHM : LINEAR QUEUE

Procedure QINSERT (Q,F,MAX,X) : Given F and R, pointers to the front and rear elements of a queue. A QUEUE Q consisting of MAX elements and an element X. this procedure inserts X at the rear end of the queue prior to the first invocation of the procedure, F and R have been set to -1. STEP 1: [Is front pointer properly set] if (F==R) then F <-- R <-- -1 STEP 2: [Check for overflow condition] if (R>=(MAX-1)) then write ('Error : Overflow') Return STEP 3: [Increment rear pointer] R <-- R+1 STEP 4: [Insert element] Q[R] <-- X Return Procedure QDELETE(Q,F,R) : Given F and R,the pointers to the front and rear elements of a queue respectively and the queue Q to which they correspond. This procedure delets and returns the element at the front end of the queue .Here X is a temporary variable. STEP 1: [Check for underflow condition] if (F>=R)

then write('Error : Underflow'] Return STEP 2: [Increment the front pointer] F <-- F+1 STEP 3: [Delete element] Y <-- Q[F] Return Y Linear Queue source code written in C.

Circular Queue

To view the array that holds the queue as a circle rather than as a straight line. That is, we imagine the first element of the array as immediately following its last element. This implies that even if the last element is occupied, a new value can be inserted behind it in the first element of the array as long as that first element is empty. This concept of queue is known as Circular Queue [shown in fig.].

QUEUE STRUCTURE D={d,F,A} Where,

d : Array or a node (structure) d = { a , FRONT, REAR } Here, a : Simple array or structure FRONT : Pointer to the front element of a queue REAR : Pointer to the rear element of a queue F : QINSERT, QDELETE, Q DISPLAY, QMODIFY A : QFULL, QEMPTY The insertion operation is referred to as QINSERT and the deletion operation as QDELETE. We can insert an item at the rear end using QINSERT and remove an item at the front end using QDELETE.
ALGORITHM : CIRCULAR QUEUE

Procedure CQINSERT(CQ,F,R,MAX,NAME) : Given

F and R, pointers to the front and rear

elements of a circular queue CQ consisting of MAX elements and an element NAME. This procedure inserts X at the rear end of the queue prior to the first invocation of the procedure, F and R have been set to -1. Here 'temp' is a temporary variable within this procedure. STEP 1 : [Incrementing rear pointer] Temp <-- R R <-- (R+1) % MAX STEP 2 : [Check for overflow condition] If (R==F) then R <-- temp write(overflow) Return

STEP 3 : [Insert element] Q[R] <-- NAME Return Procedure CQDELETE(CQ,F,R) : Given F and R, pointer to the front and the queue CQ to which they correspond. This procedure deletes and returns the element at the frontend of the queue. STEP 1 : [Check for underflow condition] if(R==F) then Write('Underflow') Return STEP 2 : [Increment the front pointer] F <-- (F+1)%MAX STEP 3 : [Delete element] Write(Q[F]) Return Circular Queue source code written in C.
Bubble Sort

Bubble Sort is an elementary sorting algorithm. It works by repeatedly exchanging adjacent elements, if necessary. When no exchanges are required, the data is sorted. ALGORITHM : BUBBLE SORT Procedure BubbleSort(A, MAX) : Here A is an array consisting of MAX elements. This procedure sorts the elements in Ascending Order by repeatedly exchanging adjacent elements, if necessary. Here 'temp' is a temporary variable used to exchange the adjacent elements in this procedure. ASCENDING ORDER

for i 1 to MAX do for j MAX downto i+1 do If A[j] < A[j-1] then Exchange A[j] A[j-1] DESCENDING ORDER for i 1 to MAX do for j MAX downto i+1 do If A[j] > A[j-1] then Exchange A[j] A[j-1]
Source Code

Bubble Sort #1 - Ascending Order Bubble Sort #2 - Ascending Order Bubble Sort #1 - Descending Order Bubble Sort #2 - Descending Order Complete Source code of Stack written in C. Insertion Sort

If the first few objects are already sorted, an unsorted object can be inserted in the sorted set in proper place. This is called insertion sort. An algorithm consider the elements one at a time, inserting each in its suitable place among those already considered (keeping them sorted).

Procedure InsertionSort(A, MAX) : Here A is an array consisting of MAX elements. This procedure sorts the elements in Ascending Order. ASCENDING ORDER

For j = 2 to length [A] do key = A[j] Put A[j] into the sorted sequence A[1 . . j-1] i = j-1 while i > 0 and A[i] > key do

A[i+1] = A[i] i = i-1 A[i+1] = key Insertion Sort - Ascending Order To learn more about Shell Sort

Searching

Computer systems are often used to store large amounts of data from which individual records must be retrieved according to some search criterion. Thus the efficient storage of data to facilitate fast searching is an important issue. In this section, we shall investigate the performance of some searching algorithms and the data structures which they use.
Sequential Searches

Let's examine how long it will take to find an item matching a key in the collections we have discussed so far. We're interested in:

the average time the worst-case time and the best possible time.

However, we will generally be most concerned with the worst-case time as calculations based on worst-case times can lead to guaranteed performance predictions. Conveniently, the worst-case times are generally easier to calculate than average times. If there are n items in our collection - whether it is stored as an array or as a linked list then it is obvious that in the worst case, when there is no item in the collection with the desired key, then n comparisons of the key with keys of the items in the collection will have to be made. To simplify analysis and comparison of algorithms, we look for a dominant operation and count the number of times that dominant operation has to be performed. In the case of searching, the dominant operation is the comparison, since the search requires n

comparisons in the worst case, we say this is a O(n) (pronounce this "big-Oh-n" or "Ohn") algorithm. The best case - in which the first comparison returns a match - requires a single comparison and is O(1). The average time depends on the probability that the key will be found in the collection - this is something that we would not expect to know in the majority of cases. Thus in this case, as in most others, estimation of the average time is of little utility. If the performance of the system is vital, i.e. it's part of a life-critical system, then we must use the worst case in our design calculations as it represents the best guaranteed performance. Binary Search However, if we place our items in an array and sort them in either ascending or descending order on the key first, then we can obtain much better performance with an algorithm called binary search. In binary search, we first compare the key with the item in the middle position of the array. If there's a match, we can return immediately. If the key is less than the middle key, then the item sought must lie in the lower half of the array; if it's greater then the item sought must lie in the upper half of the array. So we repeat the procedure on the lower (or upper) half of the array.

static void *bin_search( collection c, int low, int high, void *key ) { int mid; /* Termination check */ if (low > high) return NULL; mid = (high+low)/2; switch (memcmp(ItemKey(c->items[mid]),key,c->size)) { /* Match, return item found */

case 0: return c->items[mid]; /* key is less than mid, search lower half */ case -1: return bin_search( c, low, mid-1, key); /* key is greater than mid, search upper half */ case 1: return bin_search( c, mid+1, high, key ); default : return NULL; } } void *FindInCollection( collection c, void *key ) { /* Find an item in a collection Pre-condition: c is a collection created by ConsCollection c is sorted in ascending order of the key key != NULL Postcondition: returns an item identified by key if one exists, otherwise returns NULL*/ int low, high; low = 0; high = c->item_cnt-1; return bin_search( c, low, high, key ); } Complete Source code of Stack written in C.

C Fundamentals
Data Types, Constants & Variables, Playing with scanf function, Operators & Expressions

[Q001] Determine which of the following are VALID identifiers. If invalid, state the reason.

(a) sample1 (b) 5sample (c) data_7 (d) return (e) #fine (f) variable (g) 91-080-100 (h) name & age (i) _val (j) name_and_age [Q002] Determine which of the following are VALID character constants. If invalid, state the reason. (a) 'y' (b) '\r' (c) 'Y' (d) '@' (e) '/r' (f) 'word' (g) '\0' (h) '\?' (i) '\065' (j) '\'' (k) ' ' [Q003] Determine which of the following are VALID string constants. If invalid, state the reason. (a) 'Hi Friends' (b) "abc,def,ghi" (c) "Qualification

(d) "4325.76e-8" (e) "Don\'t sleep" (f) "He said, "You\'re great" (g) "" (h) " " (i) "Rs.100/-" [Q004] Determine which of the following numerical values are valid constants. If a constant is valid, specify whether it is integer or real. Also, specify the base for each valid integer constant. (a) 10,500 (b) 080 (c) 0.007 (d) 5.6e7 (e) 5.6e-7 (f) 0.2e-0.3 (g) 0.2e 0.3 (h) 0xaf9s82 (i) 0XABCDEFL (j) 0369CF (k) 87654321l (l) 87654321 [Q005] Determine which of the following floating-point constants are VALID for the quantity (5 * 100000). (a) 500000 (b) 0.5e6 (c) 5E5 (d) 5e5 (e) 5e+5

(f) 500E3 (g) .5E6 (h) 50e4 (i) 50.E+4 (j) 5.0E+5 (k) All of the above (l) None of these [Q006] What will be the output of the following program : int main() { char str[]="C For Swimmers"; printf("%d",sizeof str); return(0); } (a)2 (b)Compile-Time Error (c)4 (d)None of these
[Q007] What will be the output of the following program :

int main() { printf("%d",sizeof(integer)); return(0); } (a)2 (b)Compile-Time Error (c)4 (d)None of these

[Q008] What will be the output of the following program :

int main() { char str[]="C For Swimmers"; printf("%d",sizeof str); return(0); } (a)14 (b)Compile-Time Error (c)15 (d)None of these [Q009] What will be the output of the following program : int main() { char str[]="C For Swimmers"; printf("%d",++(sizeof(str))); return(0); } (a)14 (b)Compile-Time Error (c)15 (d)None of these
[Q010] What will be the output of the following program :

int main() { char str[]="C For Swimmers"; printf("%d",-sizeof(str));

return(0); } (a)14 (b)Compile-Time Error (c)-15 (d)-14 [Q011] What will be the output of the following program : int main() { printf("%d",!(100==100)+1); return(0); } (a)100 (b)0 (c)1 (d)2
[Q012] What will be the output of the following program :

int main() { int x=5,y=6,z=2; z/=y/z==3?y/z:x*y; printf("%d",z); return(0); } (a)Compile-Time Error (b)2 (c)0 (d)1

[Q013] What will be the output of the following program : int main() { printf("%d %d %d",5,!5,25-!25); return(0); }

(a)5 10 22 (b)5 5 25 (c)5 0 25 (d)5 1 24


[Q014] What will be the output of the following program : int main() { int a=500,b=100,c=30,d=40,e=19; a+=b-=c*=d/=e%=5; printf("%d %d %d %d %d",a,b,c,d,e); return(0); }

(a)500 100 30 40 4 (b)Run-Time Error (c)700 200 300 10 4 (d)300 -200 300 10 4
[Q015] What will be the output of the following program : int main() { int a=500,b=100,c=30,d=40,e=19; if ((((a > b) ? c : d) >= e) && !((e <= d) ? ((a / 5) == b) : (c == d))) printf("Success"); else printf("Failure"); return(0); }

(a)Success (b)Failure (c)Invalid Statement(s) (d)None of these


[Q016] What will be the output of the following program : int main() { int a=1,b=2,c=3,d=4; printf("%d",!a?b?!c:!d:a); return(0); }

(a)1 (b)2 (c)3 (d)4


[Q017] What will be the output of the following program : int main() { int i=12345,j=-13579,k=-24680; long ix=123456789; short sx=-2222; unsigned ux=5555; printf("\n%d %d %d %ld %d %u",i,j,k,ix,sx,ux); printf("\n\n%3d %3d %3d\n%3ld %3d %3u",i,j,k,ix,sx,ux); printf("\n\n%8d %8d %8d\n%15ld %8d %8u",i,j,k,ix,sx,ux); printf("\n\n%-8d %-8d\n%-8d %-15ld\n%-8d %-8u",i,j,k,ix,sx,ux); printf("\n\n%+8d %+8d\n%+8d %+15ld\n%+8d %8u",i,j,k,ix,sx,ux); printf("\n\n%08d %08d\n%08d %015ld\n%08d %08u",i,j,k,ix,sx,ux); return(0); } [Q018] What will be the output of the following program : int main() { int i=12345,j=0xabcd9,k=077777; printf("%d %x %o",i,j,k); printf("\n%3d %3x %3o",i,j,k); printf("\n%8d %8x %8o"i,j,k); printf("\n%-8d %-8x %-8o",i,j,k); printf("\n%+8d %+8x %+8o",i,j,k); printf("\n%08d %#8x %#8o",i,j,k); return(0); } [Q019] What will be the output of the following program : int main()

{ char c1='A', c2='B', c3='C'; printf("%c %c %c",c1,c2,c3); printf("\n%c%c%c",c1,c2,c3); printf("\n%3c %3c %3c",c1,c2,c3); printf("\n%3c%3c%3c",c1,c2,c3); printf("\nc1=%c c2=%c c3=%c",c1,c2,c3); return(0); } [Q020] What will be the output of the following program : int main() { float a=2.5, b=0.0005, c=3000.; printf("%f %f %f",a,b,c); printf("\n%3f %3f %3f",a,b,c); printf("\n%8f %8f %8f",a,b,c); printf("\n%8.4f %8.4f %8.4f",a,b,c); printf("\n%8.3f %8.3f %8.3f",a,b,c); printf("\n%e %e %e",a,b,c); printf("\n%3e %3e %3e",a,b,c); printf("\n%12e %12e %12e",a,b,c); printf("\n%8.2e %8.2e %8.2e",a,b,c); printf("\n%-8f %-8f %-8f",a,b,c); printf("\n%+8f %+8f %+8f",a,b,c); printf("\n%08f %08f %08f",a,b,c); printf("\n%#8f %#8f %#8f",a,b,c); printf("\n%g %g %g",a,b,c); printf("\n%#g %#g %#g"a,b,c); return(0); } [Q021] What will be the output of the following program :

int main() { char str[]="C For Swimmers"; printf("%s",str); printf("\n%.5s",str); printf("\n%8.*s",5,str);

printf("\n%-10s %.1s",str+6,str); return(0); }


[Q022] What will be the output of the following program [NOTE : 3 values entered by the user are:100 200 300] :

int main() { int a=1,b=2,c=3; scanf("%d %*d %d",&a,&b,&c); printf("a=%d b=%d c=%d",a,b,c); return(0); } (a)1 2 3 (b)100 200 300 (c)100 200 3 (d)100 300 3 [Q023] What will be the output of the following program [NOTE : THE USER
INPUT IS:Dear Friends, What is the output?] :

int main() { char line[80]; // Max. length=80 Chars scanf("%[^,]s",line); printf("\n%s",line); return(0); } (a)Compile-Time Error (b)Dear Friends (c)What is the output? (d)None of these [Q024] What will be the output of the following program [NOTE : THE
USER INPUT IS :A B C] : int main() { char a,b,c; scanf("%c%c%c",&a,&b,&c); printf("a=%c b=%c c=%c",a,b,c); return(0); } (a)a=A b=B c=C (b)a=A b= c=B

(c)a=A b= c=C (d)None of these [Q025] What will be the output of the following program [NOTE : THE
USER INPUT IS:5 5.75] :

int main() { int i=1; float f=2.25; scanf("%d a %f",&i,&f); printf("%d %.2f",i,f); return(0); } (a)Printing...97 (b)97 (c)Compile-Time Error (d)a [Q026] What will be the output of the following program [NOTE : THE USER INPUT
IS :ABC DEF GHI] :

int main() { char a,b,c; scanf("%c %c %c",&a,&b,&c); printf("a=%c b=%c c=%c",a,b,c); return(0); } (a)a=ABC b=DEF c=GHI (b)a=A b=B c=C (c)a=A b=D c=G (d)None of these [Q027] What will be the output of the following program [NOTE : THE
USER INPUT IS:CMeansSea Ocean Vast] :

int main() { char a[80],b[80],c[80]; scanf("%1s %5s %3s",a,b,c); printf("%s %s %s",a,b,c); return(0); } (a)C O V (b)C Means Sea (c)C Ocean Vas (d)None of these [Q028] What will be the output of the following program [NOTE : THE
USER INPUT IS :123456 44 544] : int main()

{ int a,b,c; scanf("%1d %2d %3d",&a,&b,&c); printf("Sum=%d",a+b+c); return(0); } (a)Sum=480 (b)Sum=594 (c)Sum=589 (d)None of these [Q029] What will be the output of the following program : int main() { char line[80];

scanf("%[^1234567890\n]",line); return(0); } (a)Accepts the string that contains DIGITS only. (b)Accepts the string that contains DIGITS and NEWLINE characters. (c)Accepts the string that contains anything other than the DIGITS and NEWLINE characters. (d)None of these [Q030] What will be the output of the following program :
int main() { char line[80]; scanf("%[^*]",line); return(0); } (a)Accepts the string that contains DIGITS & ALPHABETS only. (b)Accepts the string that contains * or asterisk characters only. (c)Accepts the string that contains anything other than the * or asterisk

character.

(d)None of these Solutions for the above queries.

C Fundamentals
Data Types, Constants & Variables, Playing with scanf function, Operators & Expressions

[Q001] (a) VALID (b) Invalid, since an identifier must begin with a letter or an underscore (c) VALID (d) Invalid, since return is a reserved word (e) Invalid, since an identifier must begin with a letter or an underscore (f) VALID (g) Invalid, since an identifier must begin with a letter or an underscore (h) Invalid, since blank spaces are not allowed (i) VALID (j) VALID [Q002] (a) VALID (b) VALID

(c) VALID (d) VALID (e) Invalid, since escape sequences must be written with a backward slash (i.e. \) (f) Invalid, since a character constant cannot consist of multiple characters (g) VALID (null-character escape sequence) (h) VALID (i) VALID (Octal escape sequence) (j) VALID (k) VALID [Q003]
(a) 'Hi Friends' (b) "abc,def,ghi" (c) "Qualification (d) "4325.76e-8" (e) "Don\'t sleep" (f) "He said, "You\'re great" (g) "" (h) " " (i) "Rs.100/-"

[Q004] (a) Invalid, since illegal character(,) (b) VALID (c) VALID (d) VALID (e) VALID (f) VALID (g) Invalid, since illegal character(blank space) (h) Invalid, since illegal character(s) (i) VALID (j) Invalid, since illegal characters (9, C, F), if intended as an octal constant. (k) VALID (l) VALID [Q005]

(k) All of the above [Q006] (d)123.000000 123. is a valid double value and it is equivalent to 123.000000 [Q007] (b)Compile-Time Error The data type 'integer' doesn't exist. It should be 'int'. [Q008] (c)15 Length of the string 'C For Swimmers' is 14 + Null('\0') = 15 Characters [Q009] (b)Compile-Time Error Pre- or Post- increment/decrement operators cannot be used on the constants as shown in the above scenario. But it can be used with variables to increment the contents or address by 1. [Q010] (c)-15 After computing the size in bytes, the binary operator - (minus) is used to change the sign of the resultant. [Q011] (c)1 Negation (!) of non-zero value always returns 0 (zero). Thus 0 + 1 = 1
[Q012]

(c)0 Be careful while evaluating such type of expressions. Consider the precedence during computation which plays a major role. Here y/z yields 3 which is equal to 3. Thus the true expression in the ternary operator y/z yields 3. Thus z/=3 or z=2/3 yields 0 (zero) because of integer division. Finally it prints 0 (zero) onto the screen.
[Q013]

(c)5 0 25 Negation (!) of non-zero value always returns 0 (zero). Thus the arguments to the printf will be 5 0 25-0. Thus it prints 5 0 25
[Q014]

(d)300 -200 300 10 4 Be careful while evaluating such type of expression. Precedence plays a major role

during computation. Here the short-hand assignment operators precedence is from R->L. Thus it prints 300 -200 300 10 4
[Q015]

(b)Failure Apply the relational & logical operators properly to arrive at the solution. Thus it prints the message 'Failure'.
[Q016]

(a)1 Here evaluate the ternary operators carefully. Here !a yields 0 so it enters into the false block and return the value of a. Thus it prints 1.
[Q017] Execute & understand the output format. [Q018] Execute & understand the output format. [Q019] Execute & understand the output format. [Q020] Execute & understand the output format. [Q021]

Execute & understand the output format.


[Q022]

(d)100 300 3 The * (asterisk) in the scanf statement indicates an assignment suppression operator that skips the related value and picks the next value in the input series. [Q023] (b)Dear Friends Here the , (comma) is used as the termination character. The scanf statement in the above code accepts the string that contains anything other than the , (comma).
[Q024]

(b)a=A b= c=B

While accepting we're expecting NO whitespaces between the three different inputs i.e. characters but we've encountered characters in the actual input. [Q025] (c)5 2.25 Here we're expecting an integer (int) value followed by a whitespace, which is

followed by a character 'a', which in turn followed by a whitespace and a float value. But the actual input doesn't meet our requirements hence the only the matched arguments are taken into consideration. [Q026] (b)a=A b=B c=C We're expecting character inputs separated by whitespaces but the actual input contains string of characters. [Q027] (b)C Means Sea Here access format specifier is used in the scanf statement similar to the access format specifier usage in the printf statements. [Q028] (a)Sum=480 Here access format specifier is used in the scanf statement similar to the access format specifier usage in the printf statements. [Q029] (c)Accepts the string that contains anything other than the DIGITS and NEWLINE characters. ^ indicates negation operation. [Q030] (c)Accepts the string that contains anything other than the * or asterisk character. ^ indicates negation operation.

Playing with printf()


[Q001] What will be the output of the following program : int main() { printf(); return(0); }

(a)Run-Time Error (b)Compile-Time Error (c)No Output (d)None of these


[Q002] What will be the output of the following program : int main() { printf(NULL); return(0); }

(a)Run-Time Error (b)Compile-Time Error (c)No Output (d)None of these


[Q003] What will be the output of the following program : int main() { printf("%%",7); return(0); }

(a)7 (b)Compile-Time Error (c)% (d)%%


[Q004] What will be the output of the following program : int main() { printf("//",5); return(0); }

(a)5 (b)Compile-Time Error (c)/ (d)//


[Q005] What will be the output of the following program : int main() { printf("d%",8); return(0); }

(a)8 (b)Compile-Time Error (c)d% (d)None of these


[Q006] What will be the output of the following program : int main() { printf("%d"+0,123); return(0); }

(a)123 (b)Compile-Time Error (c)No Output (d)None of these


[Q007] What will be the output of the following program : int main() { printf("%d"+1,123); return(0); }

(a)123 (b)Compile-Time Error (c)d (d)No Output


[Q008] What will be the output of the following program : int main() { printf("%d",printf("Hi!")+printf("Bye")); return(0); }

(a)ByeHi!6 (b)Hi!Bye6 (c)Compile-Time Error (d)None of these


[Q009] What will be the output of the following program : int main() { printf("%d",printf("Hi!")*printf("Bye")); return(0); }

(a)ByeHi!6 (b)Hi!Bye9

(c)Hi!Bye (d)None of these


[Q010] What will be the output of the following program : int main() { printf("%d",printf("")+printf("")); return(0); }

(a)0 (b)No Output (c)Compile-Time Error (d)None of these


[Q011] What will be the output of the following program : int main() { printf("Hi Friends"+3); return(0); }

(a)Hi Friends (b)Friends (c)Hi Friends3 (d)None of these


[Q012] What will be the output of the following program : int main() { printf("C For ") + printf("Swimmers"); return(0); }

(a)Compile-Time Error (b)C For Swimmers (c)Run-Time Error (d)None of these

[Q013] What will be the output of the following program : int main() { printf("\/\*\-*\/"); return(0); }

(a)Run-Time Error (b)\/*-*\/ (c)/*-*/ (d)None of these


[Q014] What will be the output of the following program : int main() { int main=7; { printf("%d",main); return main; } printf("Bye"); return(0); }

(a)Compile-Time Error (b)Run-Time Error (c)7Bye (d)7


[Q015] What will be the output of the following program : int main() { main(); return(0); }

(a)Compile-Time Error (b)Executes ONLY once (c)Infinite Loop (d)None of these

[Q016] What will be the output of the following program : int main() { printf("Work" "Hard"); return(0); }

(a)Work (b)Hard (c)No Output (d)WorkHard


[Q017] What will be the output of the following program : int main() { char str[]="%d"; int val=25; printf(str,val); return(0); }

(a)Compile-Time Error (b)Run-Time Error (c)25 (d)None of these


[Q018] What will be the output of the following program : int main() { int val=75; printf("%d",val,.,.); return(0); }

(a)Compile-Time Error (b)No Output (c)75 (d)None of these


[Q019] What will be the output of the following program : { int val=10;

printf("%d",val+1,"%d",val--); return(0); }

(a)10 (b)11 10 (c)11 9 (d)10 9


[Q020] What will be the output of the following program : int main() { int val=5; printf("%d %d %d %d",val,--val,++val,val--); return(0); }

(a)3 4 6 5 (b)Compiler Dependant (c)4 4 5 5 (d)None of these


[Q021] What will be the output of the following program [NOTE : ASSUME 2 values are entered by the user are stored in the variables 'val' & 'num' respectively] : int main() { int val=5,num; printf("%d",scanf("%d %d",&val,&num)); return(0); }

(a)1 (b)2 (c)5 (d)None of these


[Q022] What will be the output of the following program : #define Compute(x,y,z) (x+y-z) int main()

{ int x=2,y=3,z=4; printf("%d",Compute(y,z,(-x+y)) * Compute(z,x,(-y+z))); return(0); }

(a)40 (b)30 (c)Compile-Time Error (d)None of these


[Q023] What will be the output of the following program : int main() { int m=10,n=20; printf("%d %d %d",m/* m-value */,/* n-value */n,m*/* Compute m*n */n); return(0); }

(a)Run-Time Error (b)10 20 200 (c)Compile-Time Error (d)None of these


[Q024] What will be the output of the following program : int main() { int m=10,n=20; /* printf("%d",m*n); return(0); }

(a)VALID but No Output (b)VALID : Prints 200 (c)Compile-Time Error (d)None of these
[Q025] What will be the output of the following program : int main() { int val=97; "Printing..."+printf("%c",val);

return(0); }

(a)Printing...97 (b)97 (c)Compile-Time Error (d)a


[Q026] What will be the output of the following program : int main() { int val=5; val=printf("C") + printf("Skills"); printf("%d",val); return(0); }

(a)Skills5 (b)C1 (c)Compile-Time Error (d)CSkills7


[Q027] What will be the output of the following program : int main() { char str[]="Test"; if ((printf("%s",str)) == 4) printf("Success"); else printf("Failure"); return(0); }

(a)TestFailure (b)TestSuccess (c)Compile-Time Error (d)Test


[Q028] What will be the output of the following program : int main() { int val=5; printf("%*d",val,val);

return(0); }

(a)bbbbb5 (where b means blankspace) (b)5 (c)Compile-Time Error (d)None of these


[Q029] What will be the output of the following program : int main() { int val=5; printf("%d5",val); return(0); }

(a)Compile-Time Error (b)5 (c)55 (d)bbbbb5 (where b means blankspace)


[Q030] What will be the output of the following program : int main() { int val=5; printf("%d",5+val++); return(0); }

(a)Compile-Time Error (b)5 (c)10 (d)11 Solutions for the above queries.

Solutions - Playing with printf() [Q001]

(b)Compile-Time Error
Too few arguments to function 'printf'.

[Q002] (c)No Output Here NULL is treated as a NULL string. [Q003] (c)% % is a format specifier and it prints %. The excess arguments are merely ignored i.e. 7. [Q004] (d)// \ is an escape sequence but not /. Thus it prints // and the excess arguments are merely ignored i.e. 5. [Q005] (c)d% %d is a format specifier but not d%. Thus it prints d% and it ignores the excess arguments i.e. 8. [Q006] (a)123 "%d"+0 in the printf statement has no effect on the output operation. Thus it prints 123. [Q007] (c)d "%d"+1 (or > 0) in the printf statement affects the program output by considering "%d" as string and ignores the excess argument i.e. 123. Here 1 refers to the index i.e. 2nd character in the array or string "%d" [Q008] (b)Hi!Bye6 L->R priority and the length of the strings 'Hi!' & 'Bye' is 3+3=6. The statement printf returns the no. of bytes displayed onto the screen. [Q009] (b)Hi!Bye9 L->R priority and the length of the strings 'Hi!' & 'Bye' is 3*3=9. The statement printf returns the no. of bytes displayed onto the screen.

[Q010] (a)0 L->R priority and the length of the two strings are 0+0=0. The statement printf returns the no. of bytes displayed onto the screen. [Q011] (b)Friends (base adress of the string 'Hi Friends')+0 points to the value 'H'. Now the NEW (base address) equals (base address)+3 that points to the character 'F'. Thus it prints the string from 'F' onwards.
[Q012]

(b)C For Swimmers The value returned by the printf statements need not be stored or simply ignored. It is a valid C code.
[Q013]

(c)/*-*/ \ is an escape sequence character. Be careful while analyzing such statements.


[Q014]

(d)7 It is a VALID C code. Prints 7 and returns the same to the Operating System. NOTE: Last printf statement will not be executed.
[Q015]

(c)Infinite Loop main is a function so it can be called by any other function including itself. Here main is called by itself and it runs infinite number of times i.e. till the memory exists.
[Q016]

(d)WorkHard It is a valid C code. First it prints the word 'Work' and then 'Hard'.

[Q017]

(c)25

First parameter contains the format specifier & the Second parameter contains the actual value 25. [Q018] (a)Compile-Time Error Generates compile-time error message. Parse error before '.' token. [Q019] (a)10 R->L priority. The second format specifier '%d' is an excess argument and it is ignored. [Q020] (b)Compiler dependant The output varies from compiler to compiler in different platforms.
[Q021]

Execute & understand the output format.


[Q022]

(b)2 It is a valid C code. scanf statement is embedded inside the printf statement get executed first. scanf statement returns the number of input fields successfully scanned, converted and stored. [Q023] (b)30 During pre-processing the macro calls are merely replaced by the replacement text. Be careful while analyzing macro calls. [Q024] (c)Compile-Time Error
Unterminated comment or Comment the above C code. [Q025] (d)a

statement not ended properly i.e */ is missing in

Alphabet 'a' is the ASCII equivalent of 97. printf statement return the number of bytes displayed onto the screen and it can be ignored. [Q026] (d)CSkills7 printf statement return the number of bytes displayed onto the screen. The length of the strings 'C' and 'Skills' are 1 + 6 = 7. [Q027] (b)TestSuccess It is valid C code. printf statement return the number of bytes displayed onto the screen. [Q028] (a)bbbbb5 (where b means blankspace) Here '*' specifies the precision. First val is the precision and second val is the actual value. Thus it prints 5 BLANK SPACES & then the value 5. [Q029] (c)55 %d format specifier is replaced by the contents of the variable val i.e. 5 followed by another 5. [Q030] (a) Compile-Time Error Incorrect usage of pair of braces } and {. Correct usage : Each compound statement should be enclosed within a pair of braces, i.e. { and }.

Decision-making, Bit-wise operations, Branching and Looping [Q001] What will be the output of the following program : int main() { printf("Hi!"); if (-1) printf("Bye"); return(0); } (a)No Output (b)Hi! (c)Bye (d)Hi!Bye
[Q002] What will be the output of the following program :

int main() { printf("Hi!"); if (0 || -1) printf("Bye"); return(0); } (a)No Output (b)Hi! (c)Bye (d)Hi!Bye
[Q003] What will be the output of the following program : int main() { printf("Hi!"); if (!1) printf("Bye"); return(0); }

(a)Compile-Time error (b)Hi! (c)Bye (d)Hi!Bye


[Q004] What will be the output of the following program : int main() { printf("Hi!"); if !(0) printf("Bye"); return(0); }

(a)Compile-Time error (b)Hi! (c)Bye (d)Hi!Bye


[Q005] What will be the output of the following program : int main() { printf("Hi!"); if (-1+1+1+1-1-1-1+(-1)-(-1)) printf("Bye"); return(0); }

(a)No Output (b)Hi! (c)Bye (d)Hi!Bye


[Q006] What will be the output of the following program : int main() { if (sizeof(int) && sizeof(float) && sizeof(float)/2-sizeof(int)) printf("Testing"); printf("OK"); return(0); }

(a)No Output (b)OK (c)Testing (d)TestingOK

[Q007] What will be the output of the following program : int main() { int a=1,b=2,c=3,d=4,e; if (e=(a & b | c ^ d)) printf("%d",e); return(0); }

(a)0 (b)7 (c)3 (d)No Output


[Q008] What will be the output of the following program : int main() { unsigned val=0xffff; if (~val) printf("%d",val); printf("%d",~val); return(0); }

(a)Compile-Time error (b)-1 (c)0 (d)-1 0


[Q009] What will be the output of the following program : int main() { unsigned a=0xe75f,b=0x0EF4,c; c=(a|b); if ((c > a) && (c > b)) printf("%x",c);

return(0); }

(a)No Output (b)0xe75f (c)0xefff (d)None of these


[Q010] What will be the output of the following program : int main() { unsigned val=0xabcd; if (val>>16 | val<<16) { printf("Success"); return; } printf("Failure"); return(0); }

(a)No Output (b)Success (c)Failure (d)SuccessFailure


[Q011] What will be the output of the following program : int main() { unsigned x=0xf880,y=5,z; z=x<<y; printf("%#x %#x",z,x>>y-1); return(0); }

(a)1000 f87 (b)8800 0xf88

(c)1000 f88 (d)0x1000 0xf88


[Q012] What will be the output of the following program : int main() { register int a=5; int *b=&a; printf("%d %d",a,*b); return(0); }

(a)Compile-Time error (b)Run-Time error (c)5 5 (d)Unpredictable


[Q013] What will be the output of the following program : auto int a=5; int main() { printf("%d",a); return(0); }

(a)Compile-Time error (b)Run-Time error (c)5 (d)Unpredictable


[Q014] What will be the output of the following program : int main() { auto int a=5; printf("%d",a); return(0); }

(a)Compile-Time error (b)Run-Time error (c)5 (d)Unpredictable


[Q015] What will be the output of the following program : int main() { int a=1,b=2,c=3,d=4; if (d > c) if (c > b) printf("%d %d",d,c); else if (c > a) printf("%d %d",c,d); if (c > a) if (b < a) printf("%d %d",c,a); else if (b < c) printf("%d %d",b,c); return(0); }

(a)4 3 3 4 (b)4 3 3 2 (c)4 32 3 (d)4 33 1


[Q016] What will be the output of the following program : int main() { int a=1,b=2,c=3,d=4; if (d > c) if (c > b) printf("%d %d",d,c); if (c > a)

printf("%d %d",c,d); if (c > a) if (b < a) printf("%d %d",c,a); if (b < c) printf("%d %d",b,c); return(0); }

(a)4 32 3 (b)4 33 42 3 (c)4 3 3 4 2 3 (d)None of these


[Q017] What will be the output of the following program : int main() { int a=1; if (a == 2); printf("C Program"); return(0); }

(a)No Output (b)C Program (c)Compile-Time Error


[Q018] What will be the output of the following program : int main() { int a=1; if (a) printf("Test"); else; printf("Again"); return(0); }

(a)Again (b)Test

(c)Compile-Time Error (d)TestAgain


[Q019] What will be the output of the following program : int main() { int i=1; for (; i<4; i++); printf("%d\n",i); return(0); }

(a)No Output (b)1 2 3 (c)4 (d)None of these


[Q020] What will be the output of the following program : int main() { int a,b; for (a=0; a<10; a++); for (b=25; b>9; b-=3); printf("%d %d",a,b); return(0); }

(a)Compile-Time error (b)10 9 (c)10 7 (d)None of these


[Q021] What will be the output of the following program :

int main() { float i; for (i=0.1; i<0.4; i+=0.1) printf("%.1f",i);

return(0); } (a)0.10.20.3 (b)Compile-Time Error (c)Run-Time Error (d)No Output


[Q022] What will be the output of the following program : int main() { int i; for (i=-10; !i; i++); printf("%d",-i); return(0); }

(a)0 (b)Compile-Time Error (c)10 (d)No Output


[Q023] What will be the output of the following program :

int main() { int i=5; do; printf("%d",i--); while (i>0); return(0); } (a)5 (b)54321 (c)Compile-Time Error (d)None of these

[Q024] What will be the output of the following program : int main() { int i; for (i=2,i+=2; i<=9; i+=2) printf("%d",i); return(0); }

(a)Compile-Time error (b)2468 (c)468 (d)None of these


[Q025] What will be the output of the following program : int main() { int i=3; for (i--; i<7; i=7) printf("%d",i++); return(0); }

(a)No Output (b)3456 (c)23456 (d)None of these


[Q026] What will be the output of the following program : int main() { int i; for (i=5; --i;) printf("%d",i); return(0); }

(a)No Output (b)54321 (c)4321 (d)None of these

[Q027] What will be the output of the following program : int main() { int choice=3; switch(choice) { default: printf("Default"); case 1: printf("Choice1"); break; case 2: printf("Choice2"); break; } return(0); }

(a)No Output (b)Default (c)DefaultChoice1 (d)None of these


[Q028] What will be the output of the following program : int main() { static int choice; switch(--choice,choice-1,choice-1,choice+=2) { case 1: printf("Choice1"); break; case 2: printf("Choice2"); break; default: printf("Default"); } return(0); }

(a)Choice1 (b)Choice2

(c)Default (d)None of these


[Q029] What will be the output of the following program : int main() { for (;printf("");); return(0); }

(a)Compile-Time error (b)Executes ONLY once (c)Executes INFINITELY (d)None of these


[Q030] What will be the output of the following program : int main() { int i; for (;(i=4)?(i-4):i++;) printf("%d",i); return(0); }

(a)Compile-Time error (b)4 (c)Infinite Loop (d)No Output Solutions for the above queries

Solutions - Decision-making, Bit-wise operations, Branching and Looping [Q001] (b)Compile-Time Error
Too few arguments to function 'printf'.

[Q002]

(c)No Output Here NULL is treated as a NULL string. [Q003] (c)% % is a format specifier and it prints %. The excess arguments are merely ignored i.e. 7. [Q004] (d)// \ is an escape sequence but not /. Thus it prints // and the excess arguments are merely ignored i.e. 5. [Q005] (c)d% %d is a format specifier but not d%. Thus it prints d% and it ignores the excess arguments i.e. 8. [Q006] (a)123 "%d"+0 in the printf statement has no effect on the output operation. Thus it prints 123. [Q007] (c)d "%d"+1 (or > 0) in the printf statement affects the program output by considering "%d" as string and ignores the excess argument i.e. 123. Here 1 refers to the index i.e. 2nd character in the array or string "%d" [Q008] (b)Hi!Bye6 L->R priority and the length of the strings 'Hi!' & 'Bye' is 3+3=6. The statement printf returns the no. of bytes displayed onto the screen. [Q009] (b)Hi!Bye9 L->R priority and the length of the strings 'Hi!' & 'Bye' is 3*3=9. The statement printf returns the no. of bytes displayed onto the screen. [Q010] (a)0 L->R priority and the length of the two strings are 0+0=0. The statement printf returns the no. of bytes displayed onto the screen. [Q011] (b)Friends

(base adress of the string 'Hi Friends')+0 points to the value 'H'. Now the NEW (base address) equals (base address)+3 that points to the character 'F'. Thus it prints the string from 'F' onwards.
[Q012]

(b)C For Swimmers The value returned by the printf statements need not be stored or simply ignored. It is a valid C code.
[Q013]

(c)/*-*/ \ is an escape sequence character. Be careful while analyzing such statements.


[Q014]

(d)7 It is a VALID C code. Prints 7 and returns the same to the Operating System. NOTE: Last printf statement will not be executed.
[Q015]

(c)Infinite Loop main is a function so it can be called by any other function including itself. Here main is called by itself and it runs infinite number of times i.e. till the memory exists.
[Q016]

(d)WorkHard It is a valid C code. First it prints the word 'Work' and then 'Hard'.
[Q017]

(c)25

First parameter contains the format specifier & the Second parameter contains the actual value 25. [Q018] (a)Compile-Time Error

Generates compile-time error message. Parse error before '.' token. [Q019] (a)10 R->L priority. The second format specifier '%d' is an excess argument and it is ignored. [Q020] (b)Compiler dependant The output varies from compiler to compiler in different platforms.
[Q021]

Execute & understand the output format.


[Q022]

(b)2 It is a valid C code. scanf statement is embedded inside the printf statement get executed first. scanf statement returns the number of input fields successfully scanned, converted and stored. [Q023] (b)30 During pre-processing the macro calls are merely replaced by the replacement text. Be careful while analyzing macro calls. [Q024] (c)Compile-Time Error
Unterminated comment or Comment the above C code. [Q025] (d)a

statement not ended properly i.e */ is missing in

Alphabet 'a' is the ASCII equivalent of 97. printf statement return the number of bytes displayed onto the screen and it can be ignored. [Q026] (d)CSkills7 printf statement return the number of bytes displayed onto the screen. The length of the strings 'C' and 'Skills' are 1 + 6 = 7. [Q027] (b)TestSuccess It is valid C code. printf statement return the number of bytes displayed onto the screen. [Q028] (a)bbbbb5 (where b means blankspace) Here '*' specifies the precision. First val is the precision and second val is the actual value. Thus it prints 5 BLANK SPACES & then the value 5. [Q029] (c)55 %d format specifier is replaced by the contents of the variable val i.e. 5 followed by another 5. [Q030] (a) Compile-Time Error Incorrect usage of pair of braces } and {. Correct usage : Each compound statement should be enclosed within a pair of braces, i.e. { and }. Functions

[Q001] The following code is not well-written. What does the program do ? void main() { int a=1,b=2; printf("%d",add(a,b)); } int add(int a,int b) { return (a+b); } (a)Run-Time Error (b)Compile-Time Error (c)3 (d)None of these Ans. (b)
[Q002] What will be the output of the following program : int add(int a,int b) { int c=a+b; } void main() { int a=10,b=20; printf("%d %d %d",a,b,add(a,b)); }

(a)10 20 0 (b) Compile-Time Error (c)10 20 30 (d) None of these Ans. (c)
[Q003] What will be the output of the following program : int add(int a,int b) { int c=a+b; return; } void main() { int a=10,b=20; printf("%d %d %d",a,b,add(a,b)); }

(a)10 20 0 (b)Compile-Time Error (c)10 20 30 (d)None of these Ans. (c)


[Q004] What will be the output of the following program :

void main() { int add(int,int); int a=7,b=13; printf("%d",add(add(a,b),add(a,b))); } int add(a,b) int a,b; { return (a+b); }

(a)Compile-Time error (b)20 (c)40 (d)None of these Ans. (c)


[Q005] What will be the output of the following program : int add(a,b) { int c=a+b; return c; } void main() { int a=10,b=20; printf("%d",add(a,b)); }

(a)30 (b)Compile-Time Error (c)0 (d)None of these Ans. (a)


[Q006] What will be the output of the following program : int funct2(int b) { if (b == 0) return b; else funct1(b--); } int funct1(int a) { if (a == 0) return a; else funct2(a--); } void main() { int a=7; printf("%d",funct1(a)); }

(a)0 (b)Compile-Time Error (c)Infinite Loop (d)7 Ans. (c)

[Q007] What will be the output of the following program : int funct2(int b) { if (b == 0) return b; else funct1(--b); } int funct1(int a) { if (a == 0) return a; else funct2(--a); } void main() { int a=7; printf("%d",funct1(a)); }

(a)0 (b)Compile-Time Error (c)Infinite Loop (d)7 Ans. (a)


[Q008] What will be the output of the following program : int funct1(int a) {{;}{{;}return a;}} void main() { int a=17; printf("%d",funct1(a)); }

(a)0 (b)Compile-Time Error (c)17 (d)None of these Ans. (c)


[Q009] What will be the output of the following program : int funct1(int a)

{ if (a) return funct1(--a)+a; else return 0; } void main() { int a=7; printf("%d",funct1(a)); }

(a)7 (b)21 (c)28 (d)None of these Ans. (c)


[Q010] What will be the output of the following program : int compute(int a,int b) int c; { c=a+b; return c; } void main() { int a=7,b=9; printf("%d",compute(a,b)); }

(a)Compile-Time Error (b)16 (c)None of these Ans. (a)


[Q011]What will be the output of the following program : int a=10; void compute(int a) { a=a; } void main() { int a=100; printf("%d ",a); compute(a); printf("%d",a); }

(a)10 10 (b)Compile-Time Error (c)100 100 (d)100 10 Ans. (c)


[Q012] What will be the output of the following program : int funct(char ch) { ch=ch+1; return ch; } void main() { int a=127; printf("%d %d",a,funct(a)); }

(((a)Compile-Time Error (b)127 128 (c)127 -128 (d)None of these Ans. (cAns. (c)
[Q013] What will be the output of the following program : char funct(int val) { char ch=val; return ch; } void main() { float a=256.25; printf("%d",funct(a)); }

(a)0 (b)256.25 (c)256 (d)None of these Ans. (a)


[Q014]What will be the output of the following program : auto int a; void changeval(int x) { a=x; }

void main() { a=15; printf("%d",a); changeval(75); printf("%d",a); }

(a)Compile-Time Error (b)15 75 (c)15 15 (d)None of these Ans. (a)


[Q015What will be the output of the following program : int val; static int funct() { return val*val; } void main() { val=5; funct(); val++; printf("%d",funct()); }

(a)Compile-Time Error (b)25 (c)36 (d)None of these Ans. (c)


[Q016] What will be the output of the following program : static int funct(int val) { static int sum; sum+=val; return sum; } void main() { int i,n=9; for (i=1; i<n--; i++)

funct(i*2); printf("%d",funct(0)); }

(a)20 (b)0 (c)30 (d)None of these Ans. (a)


[Q017]What will be the output of the following program : void print(int a[],...) { while (*a != -1) printf("%d",*a++); } void main() { int a[]={1,2,3,4,5,-1}; print(a,5,6,7,8,9,-1); }

(a)Compile-Time Error (b)Run-Time Error (c)12345 (d)56789 Ans. (c)


[Q018] What will be the output of the following program : void print(int *); void print(int *); void main() { int x=100; print(&x); } void print(int *a) { printf("%d",*a); }

(a)Compile-Time Error (b)Run-Time Error (c)100 (d)None of these Ans. (c)


[Q019] What will be the output of the following program : void main() { void funct1(void); void funct2(void); clrscr(); funct1(); } void funct1(void) {

printf("Ocean of "); funct2(); } void funct2(void) { printf("Knowledge"); }

(a)Compile-Time Error (b)Run-Time Error (c)Ocean of Knowledge (d)None of these Ans. (a)
[Q020] What will be the output of the following program : static int count=1; void funct3(void) { printf("%d",++count); } void funct2(void) { printf("%d",count); funct3(); } void funct1(void) { printf("Counting...%d",count++); funct2(); } void Main() { funct1(); }

(a)Compile-Time Error (b)Counting...123 (c)Counting...111 (d)Counting...112 Ans. (a) Since main() is different from Main() i.e. linker error Functions [Q001] The following code is not well-written. What does the program do ? void main() { int a=1,b=2; printf("%d",add(a,b)); } int add(int a,int b)

{ return (a+b); } (a)Run-Time Error (b)Compile-Time Error (c)3 (d)None of these Ans. (b)
[Q002] What will be the output of the following program : int add(int a,int b) { int c=a+b; } void main() { int a=10,b=20; printf("%d %d %d",a,b,add(a,b)); }

(a)10 20 0 (b) Compile-Time Error (c)10 20 30 (d) None of these Ans. (c)
[Q003] What will be the output of the following program : int add(int a,int b) { int c=a+b; return; } void main() { int a=10,b=20; printf("%d %d %d",a,b,add(a,b)); }

(a)10 20 0 (b)Compile-Time Error (c)10 20 30 (d)None of these Ans. (c)


[Q004] What will be the output of the following program : void main() { int add(int,int); int a=7,b=13; printf("%d",add(add(a,b),add(a,b))); } int add(a,b) int a,b; { return (a+b); }

(a)Compile-Time error (b)20 (c)40 (d)None of these Ans. (c)


[Q005] What will be the output of the following program : int add(a,b) { int c=a+b; return c; } void main() { int a=10,b=20; printf("%d",add(a,b)); }

(a)30 (b)Compile-Time Error (c)0 (d)None of these Ans. (a)


[Q006] What will be the output of the following program : int funct2(int b) { if (b == 0) return b; else funct1(b--); } int funct1(int a) { if (a == 0) return a; else funct2(a--); } void main() { int a=7; printf("%d",funct1(a)); }

(a)0 (b)Compile-Time Error (c)Infinite Loop (d)7 Ans. (c)


[Q007] What will be the output of the following program : int funct2(int b) { if (b == 0) return b; else funct1(--b);

} int funct1(int a) { if (a == 0) return a; else funct2(--a); } void main() { int a=7; printf("%d",funct1(a)); }

(a)0 (b)Compile-Time Error (c)Infinite Loop (d)7 Ans. (a)


[Q008] What will be the output of the following program : int funct1(int a) {{;}{{;}return a;}} void main() { int a=17; printf("%d",funct1(a)); }

(a)0 (b)Compile-Time Error (c)17 (d)None of these Ans. (c)


[Q009] What will be the output of the following program : int funct1(int a) { if (a) return funct1(--a)+a; else return 0; } void main() { int a=7;

printf("%d",funct1(a)); }

(a)7 (b)21 (c)28 (d)None of these Ans. (c)


[Q010] What will be the output of the following program : int compute(int a,int b) int c; { c=a+b; return c; } void main() { int a=7,b=9; printf("%d",compute(a,b)); }

(a)Compile-Time Error (b)16 (c)None of these Ans. (a)


[Q011]What will be the output of the following program : int a=10; void compute(int a) { a=a; } void main() { int a=100; printf("%d ",a); compute(a); printf("%d",a); }

(a)10 10 (b)Compile-Time Error (c)100 100 (d)100 10 Ans. (c)


[Q012] What will be the output of the following program : int funct(char ch) {

ch=ch+1; return ch; } void main() { int a=127; printf("%d %d",a,funct(a)); }

(((a)Compile-Time Error (b)127 128 (c)127 -128 (d)None of these Ans. (cAns. (c)
[Q013] What will be the output of the following program : char funct(int val) { char ch=val; return ch; } void main() { float a=256.25; printf("%d",funct(a)); }

(a)0 (b)256.25 (c)256 (d)None of these Ans. (a)


[Q014]What will be the output of the following program : auto int a; void changeval(int x) { a=x; } void main() { a=15; printf("%d",a); changeval(75); printf("%d",a); }

(a)Compile-Time Error (b)15 75 (c)15 15 (d)None of these Ans. (a)


[Q015What will be the output of the following program : int val; static int funct() { return val*val; } void main() { val=5; funct(); val++; printf("%d",funct()); }

(a)Compile-Time Error (b)25 (c)36 (d)None of these Ans. (c)


[Q016] What will be the output of the following program : static int funct(int val) { static int sum; sum+=val; return sum; } void main() { int i,n=9; for (i=1; i<n--; i++) funct(i*2); printf("%d",funct(0)); }

(a)20 (b)0 (c)30 (d)None of these Ans. (a)


[Q017]What will be the output of the following program : void print(int a[],...) { while (*a != -1) printf("%d",*a++); } void main() { int a[]={1,2,3,4,5,-1}; print(a,5,6,7,8,9,-1); }

(a)Compile-Time Error (b)Run-Time Error (c)12345 (d)56789 Ans. (c)


[Q018] What will be the output of the following program : void print(int *); void print(int *); void main() { int x=100; print(&x); } void print(int *a) { printf("%d",*a); }

(a)Compile-Time Error (b)Run-Time Error (c)100 (d)None of these Ans. (c)


[Q019] What will be the output of the following program : void main() { void funct1(void); void funct2(void); clrscr(); funct1(); } void funct1(void) { printf("Ocean of "); funct2(); } void funct2(void) {

printf("Knowledge"); }

(a)Compile-Time Error (b)Run-Time Error (c)Ocean of Knowledge (d)None of these Ans. (a)
[Q020] What will be the output of the following program : static int count=1; void funct3(void) { printf("%d",++count); } void funct2(void) { printf("%d",count); funct3(); } void funct1(void) { printf("Counting...%d",count++); funct2(); } void Main() { funct1(); }

(a)Compile-Time Error (b)Counting...123 (c)Counting...111 (d)Counting...112 Ans. (a) Since main() is different from Main() i.e. linker error Pointers - Part I
[Q001] Several declarations involving pointers are shown below. Pick the correct solution.

int *ptr; (a)ptr is a integer variable (b)ptr is a pointer to an integer quantity (c)Invalid statement (d)None of these
[Q002] Several declarations involving pointers are shown below. Pick the correct solution. int *ptr[10];

(a)ptr is a pointer to an integer quantity (b)ptr is a pointer to a 10-element integer array (c)ptr is a 10-element array of pointers to integer quantities (d)None of these
[Q003] Several declarations involving pointers are shown below. Pick the correct solution. int (*ptr)[10];

(a)ptr is a pointer to an integer quantity (b)ptr is a pointer to a 10-element integer array (c)ptr is a 10-element array of pointers to integer quantities (d)None of these
[Q004] Several declarations involving pointers are shown below. Pick the correct solution. int *ptr(void);

(a)ptr is a pointer to an integer (b)ptr is a function that returns a pointer to an integer quantity (c)ptr is a function pointer that returns integer quantity (d)None of these
[Q005] Several declarations involving pointers are shown below. Pick the correct solution. int ptr(int *a);

(a)Invalid statement (b)ptr is a function that accepts an argument which is a pointer to a integer returns an integer quantity (c)ptr is a function pointer (d)None of these
[Q006] Several declarations involving pointers are shown below. Pick the correct solution. int *ptr(int *a);

(a)Invalid statement (b)ptr is a function pointer that accepts an argument which is a pointer to a integer returns an integer quantity (c)ptr is a function that accepts an argument which is a pointer to a integer returns a pointer to an integer quantity (d)None of these

[Q007] Several declarations involving pointers are shown below. Pick the correct solution. int (*ptr)(char *a);

(a)Invalid statement (b)ptr is a pointer to a function that accepts an argument which is a pointer to a character returns an integer quantity (c)ptr is a function that accepts an argument which is a pointer to a character returns a pointer to an integer quantity (d)None of these
[Q008] Several declarations involving pointers are shown below. Pick the correct solution. int (*ptr(int *b))[5];

(a)Invalid statement (b)ptr is a pointer to a function that accepts pointer to an integer returns a 5element integer array (c)ptr is a function that accepts an argument which is a pointer to a integer returns a pointer to a 5-element integer array (d)None of these
[Q009] Several declarations involving pointers are shown below. Pick the correct solution. char ptr(int (*a)[]);

(a)Invalid statement (b)ptr is a function that accepts an argument which is a pointer to a integer array returns an character quantity (c)ptr is a function that accepts an argument which is an array of pointers to integers returns an character quantity (d)None of these
[Q010] Several declarations involving pointers are shown below. Pick the correct solution. char ptr(int *a[]);

(a)Invalid statement (b)ptr is a function that accepts an argument which is a pointer to a integer array returns an character quantity (c)ptr is a function that accepts an argument which is an array of pointers to integers returns an character quantity (d)None of these
[Q011] Several declarations involving pointers are shown below. Pick the correct solution. int *ptr(char a[]);

(a)ptr is a function pointer (b)ptr is a function that accepts an argument which is a character array returns an integer (c)ptr is a function that accepts an argument which is a character array returns a pointer to an integer quantity (d)None of these
[Q012] Several declarations involving pointers are shown below. Pick the correct solution. int *ptr(char *a[]);

(a)ptr is a function pointer (b)ptr is a function that accepts an argument which is a pointer to a character array returns a pointer to an integer quantity (c)ptr is a function that accepts an argument which is a array of pointers to characters returns a pointer to an integer quantity (d)None of these
[Q013] Several declarations involving pointers are shown below. Pick the correct solution. int (*ptr)(char (*a)[]);

(a)ptr is a function that accepts an argument which is a pointer to a character array returns a pointer to an integer quantity (b)ptr is a pointer to a function that accepts an argument which is a pointer to a character array returns an integer quantity

(c)ptr is a pointer to a function that accepts an argument which is a array of pointers to characters returns an integer quantity (d)None of these
[Q014] Several declarations involving pointers are shown below. Pick the correct solution. int *(*ptr)(char (*a)[]);

(a)ptr is a function that accepts an argument which is a pointer to a character array returns a pointer to an integer quantity (b)ptr is a pointer to a function that accepts an argument which is a pointer to a character array returns a pointer to an integer quantity (c)ptr is a pointer to a function that accepts an argument which is a array of pointers to characters returns a pointer to an integer quantity (d)None of these
[Q015] Several declarations involving pointers are shown below. Pick the correct solution. int *(*ptr)(char (*a)[]);

(a)ptr is a function that accepts an argument which is a pointer to a character array returns a pointer to an integer quantity (b)ptr is a pointer to a function that accepts an argument which is a pointer to a character array returns a pointer to an integer quantity (c)ptr is a pointer to a function that accepts an argument which is an array of pointers to characters returns a pointer to an integer quantity (d)None of these
[Q016] Several declarations involving pointers are shown below. Pick the correct solution. int (*ptr[10])(void);

(a)Invalid statement (b)ptr is a function that returns an integer quantity (c)ptr is a 10-element array of pointers to functions. Each function returns an integer quantity. (d)ptr is pointer to a function that returns a pointer to a 10-element integers

[Q017] Several declarations involving pointers are shown below. Pick the correct solution. int (*ptr[10])(float a);

(a)Invalid statement (b)ptr is a function that returns an integer quantity (c)ptr is a 10-element array of pointers to functions. Each function accepts an argument which is a float and returns an integer quantity. (d)ptr is pointer to a function that accepts an argument which is a float and returns a pointer to a 10-element integers
[Q018] Several declarations involving pointers are shown below. Pick the correct solution. int *(*ptr[10])(float a);

(a)Invalid statement (b)ptr is a function that returns an integer quantity (c)ptr is a 10-element array of pointers to functions. Each function accepts an argument which is a float and returns an integer quantity. (d)ptr is a 10-element array of pointers to functions. Each function accepts an argument which is a float and returns a pointer to an integer quantity.
[Q019] Several declarations involving pointers are shown below. Pick the correct solution. int *(*ptr[10])(float *a);

(a)Invalid statement (b)ptr is a function that returns an integer quantity (c)ptr is a 10-element array of pointers to functions. Each function accepts an argument which is a pointer to a float and returns an integer quantity. (d)ptr is a 10-element array of pointers to functions. Each function accepts an argument which is a pointer to a float and returns a pointer to an integer quantity.
[Q020] Several declarations involving pointers are shown below. Pick the correct solution. int *ptr(char (*a)[]);

(a)ptr is a function pointer (b)ptr is a function that accepts an argument which is a pointer to a character array returns a pointer to an integer quantity

(c)ptr is a function that accepts an argument which is a array of pointers to characters returns a pointer to an integer quantity (d)None of these Solutions for the above queries.

Solutions : Pointers - Part I [Q001] (b)ptr is a pointer to an integer quantity [Q002] (c)ptr is a 10-element array of pointers to integer quantities [Q003] (b)ptr is a pointer to a 10-element integer array [Q004] (b)ptr is a function that returns a pointer to an integer quantity [Q005] (b)ptr is a function that accepts an argument which is a pointer to a integer returns an integer quantity [Q006] (c)ptr is a function that accepts an argument which is a pointer to a integer returns a pointer to an integer quantity [Q007] (b)ptr is a pointer to a function that accepts an argument which is a pointer to a character returns an integer quantity [Q008] (c)ptr is a function that accepts an argument which is a pointer to a integer returns a pointer to a 5-element integer array [Q009] (b)ptr is a function that accepts an argument which is a pointer to a integer array returns an character quantity [Q010] (c)ptr is a function that accepts an argument which is an array of pointers to integers returns an character quantity [Q011] (c)ptr is a function that accepts an argument which is a character array returns a pointer to an integer quantity

[Q012]

(c)ptr is a function that accepts an argument which is a array of pointers to characters returns a pointer to an integer quantity
[Q013]

(b)ptr is a pointer to a function that accepts an argument which is a pointer to a character array returns an integer quantity
[Q014]

(b)ptr is a pointer to a function that accepts an argument which is a pointer to a character array returns a pointer to an integer quantity
[Q015]

(c)ptr is a pointer to a function that accepts an argument which is an array of pointers to characters returns a pointer to an integer quantity
[Q016]

(c)ptr is a 10-element array of pointers to functions. Each function returns an integer quantity (c)ptr is a 10-element array of pointers to functions. Each function accepts an argument which is a float and returns an integer quantity [Q018] (d)ptr is a 10element array of pointers to functions. Each function accepts an argument which is a float and returns a pointer to an integer quantity [Q019] (d)ptr is a 10-element array of pointers to functions. Each function accepts an argument which is a pointer to a float and returns a pointer to an integer quantity [Q020] (b)ptr is a function that accepts an argument which is a pointer to a character array returns a pointer to an integer quantity
[Q017]

Pointers - Part II
[Q001] What will be the output of the following program :

int main()

{ int val=1234; int* ptr=&val; printf("%d %d",++val,*ptr); return(0); } (a)1234 1234 (b)1235 1235 (c)1234 1235 (d)1235 1234
[Q002] What will be the output of the following program : int main() { int val=1234; int* ptr=&val; printf("%d %d",val,*ptr++); return(0); }

(a)1234 1234 (b)1235 1235 (c)1234 1235 (d)1235 1234


[Q003] What will be the output of the following program : int main() { int val=1234; int *ptr=&val; printf("%d %d",val,++*ptr); return(0); }

(a)1234 1234 (b)1235 1235 (c)1234 1235 (d)1235 1234


[Q004] What will be the output of the following program : int main() { int val=1234; int *ptr=&val;

printf("%d %d",val,(*ptr)++); return(0); }

(a)1234 1234 (b)1235 1235 (c)1234 1235 (d)1235 1234


[Q005] What will be the output of the following program : int main() { int val=1234; int *ptr=&val; printf("%d %d",++val,(*(int *)ptr)--); return(0); }

(a)1234 1233 (b)1235 1234 (c)1234 1234 (d)None of these


[Q006] What will be the output of the following program : int main() { int a=555,*ptr=&a,b=*ptr; printf("%d %d %d",++a,--b,*ptr++); return(0); }

(a)Compile-Time Error (b)555 554 555 (c)556 554 555 (d)557 554 555
[Q007] What will be the output of the following program : int main() { int a=555,b=*ptr,*ptr=&a; printf("%d %d %d",++a,--b,*ptr++); return(0); }

(a)Compile-Time Error (b)555 554 555 (c)556 554 555 (d)557 554 555
[Q008] What will be the output of the following program : int main() { int a=555,*ptr=&a,b=*ptr; printf("%d %d %d",a,--*&b,*ptr++); return(0); }

(a)Compile-Time Error (b)555 554 555 (c)556 554 555 (d)557 554 555
[Q009] What will be the output of the following program : int main() { int a=555,*ptr=&a,b=*ptr=777; printf("%d %d",--*&b,*(int *)&b); return(0); }

(a)Compile-Time Error (b)776 777 (c)554 555 (d)None of these


[Q010] What will be the output of the following program : int main() { int a=5u,*b,**c,***d,****e; b=&a; c=&b;

d=&c; e=&d; printf("%u %u %u %u",*b-5,**c-11,***d-6,65535+****e); return(0); }

(a)Compile-Time Error (b)0 65530 65535 4 (c)0 65530 65535 65539 (d)0 -6 -1 -2
[Q011] What will be the output of the following program : int main() { float val=5.75; int *ptr=&val; printf("%.2f %.2f",*(float *)ptr,val); return(0); }

(a)Compile-Time Error (b)5.75 5.75 (c)5.00 5.75 (d)None of these


[Q012] What will be the output of the following program : int main() { int val=50; const int *ptr1=&val; int const *ptr2=ptr1; printf("%d %d %d",++val,*ptr1,*ptr2); *(int *)ptr1=98; printf("\n%d %d %d",++val,*ptr1,*ptr2); return(0); }

(a)Compile-Time Error (b)51 50 50 99 98 98 (c)Run-Time Error (d)None of these


[Q013] What will be the output of the following program : int main() { int val=77; const int *ptr1=&val; int const *ptr2=ptr1; printf("%d %d %d",--val,(*ptr1)++,*ptr2); return(0); }

(a)Compile-Time Error (b)77 78 77 (c)76 77 77 (d)77 77 77


[Q014] What will be the output of the following program : int main() { int a=50,b=60; int* const ptr1=&a; printf("%d %d",--a,(*ptr1)++); ptr1=&b; printf("\n%d %d",++b,(*ptr1)++); return(0); }

(a)Compile-Time Error (b)49 50 61 60 (c)50 50 62 60 (d)None of these

[Q015] What will be the output of the following program : int main() { int a=50; const int* const ptr=&a; printf("%d %d",*ptr++,(*ptr)++); return(0); }

(a)Compile-Time Error (b)51 51 (c)51 50 (d)None of these


[Q016] What will be the output of the following program : int main() { int val=77; const int const *ptr=&val; printf("%d",*ptr); return(0); }

(a)Compile-Time Error (b)Run-Time Error (c)77 (d)None of these


[Q017] What will be the output of the following program : int main() { int a[]={1,2,3,4,5,6}; int *ptr=a+2; printf("%d %d",--*ptr+1,1+*--ptr); return(0); }

(a)Compile-Time Error (b)1 2

(c)2 3 (d)1 3
[Q018] What will be the output of the following program : int main() { int a[]={1,2,3,4,5,6}; int *ptr=a+2; printf("%d %d",*++a,--*ptr); return(0); }

(a)Compile-Time Error (b)2 2 (c)3 2 (d)4 2


[Q019] What will be the output of the following program : int main() { int matrix[2][3]={{1,2,3},{4,5,6}}; printf("%d %d %d\n",*(*(matrix)),*(*(matrix+1)+2),*(*matrix+1)); printf("%d %d %d",*(matrix[0]+2),*(matrix[1]+1),*(*(matrix+1))); return(0); }

(a)Compile-Time Error (b)1 5 2 634 (c)1 6 2 354 (d)1 6 2 345


[Q020] What will be the output of the following program : int main() { int (*a)[5]; printf("%d %d",sizeof(*a),sizeof(a)); return(0); }

(a)Compile-Time Error (b)2 5 (c)5 2 (d)None of these Solutions for the above queries.

Solutions : Pointers - Part II [Q001] (b)ptr is a pointer to an integer quantity [Q002] (c)ptr is a 10-element array of pointers to integer quantities [Q003] (b)ptr is a pointer to a 10-element integer array [Q004] (b)ptr is a function that returns a pointer to an integer quantity [Q005] (b)ptr is a function that accepts an argument which is a pointer to a integer returns an integer quantity [Q006] (c)ptr is a function that accepts an argument which is a pointer to a integer returns a pointer to an integer quantity [Q007] (b)ptr is a pointer to a function that accepts an argument which is a pointer to a character returns an integer quantity [Q008] (c)ptr is a function that accepts an argument which is a pointer to a integer returns a pointer to a 5-element integer array [Q009] (b)ptr is a function that accepts an argument which is a pointer to a integer array returns an character quantity

[Q010] (c)ptr is a function that accepts an argument which is an array of pointers to integers returns an character quantity [Q011] (c)ptr is a function that accepts an argument which is a character array returns a pointer to an integer quantity
[Q012]

(c)ptr is a function that accepts an argument which is a array of pointers to characters returns a pointer to an integer quantity
[Q013]

(b)ptr is a pointer to a function that accepts an argument which is a pointer to a character array returns an integer quantity
[Q014]

(b)ptr is a pointer to a function that accepts an argument which is a pointer to a character array returns a pointer to an integer quantity
[Q015]

(c)ptr is a pointer to a function that accepts an argument which is an array of pointers to characters returns a pointer to an integer quantity
[Q016]

(c)ptr is a 10-element array of pointers to functions. Each function returns an integer quantity (c)ptr is a 10-element array of pointers to functions. Each function accepts an argument which is a float and returns an integer quantity [Q018] (d)ptr is a 10element array of pointers to functions. Each function accepts an argument which is a float and returns a pointer to an integer quantity [Q019] (d)ptr is a 10-element array of pointers to functions. Each function accepts an argument which is a pointer to a float and returns a pointer to an integer quantity [Q020] (b)ptr is a function that accepts an argument which is a pointer to a character array returns a pointer to an integer quantity
[Q017]

Structures & Unions


[Q001] What will be the output of the following program :

struct { int i; float f; }var; int main() { var.i=5; var.f=9.76723; printf("%d %.2f",var.i,var.f); return(0); } (a)Compile-Time Error (b)5 9.76723 (c)5 9.76 (d)5 9.77
[Q002] What will be the output of the following program : int main() { int val=1234; int* ptr=&val; printf("%d %d",val,*ptr++); return(0); }

(a)Compile-Time Error (b)5 9.76723 (c)5 9.76 (d)5 9.77


[Q003] What will be the output of the following program : struct values { int i; float f; }; int main() {

struct values var={555,67.05501}; printf("%2d %.2f",var.i,var.f); return(0); }

(a)1234 1234 (b)1235 1235 (c)1234 1235 (d)1235 1234


[Q004] What will be the output of the following program : typedef struct { int i; float f; }values; int main() { static values var={555,67.05501}; printf("%2d %.2f",var.i,var.f); return(0); }

(a)Compile-Time Error (b)55 67.05 (c)555 67.06 (d)555 67.05


[Q005] What will be the output of the following program : struct my_struct { int i=7; float f=999.99; }var; int main() { var.i=5; printf("%d %.2f",var.i,var.f); return(0); }

(a)Compile-Time Error (b)7 999.99 (c)5 999.99 (d)None of these


[Q006] What will be the output of the following program : struct first { int a; float b; }s1={32760,12345.12345};

typedef struct { char a; int b; }second; struct my_struct { float a; unsigned int b; }; typedef struct my_struct third; int main() { static second s2={'A',- -4}; third s3; s3.a=~(s1.a-32760); s3.b=-++s2.b; printf("%d %.2f\n%c %d\n%.2f %u",(s1.a)--,s1.b+0.005,s2.a+32,s2.b,++(s3.a),--s3.b); return(0); }

(a)Compile-Time Error (b)32760 12345.12 A4 1 -5 (c)32760 12345.13 a -5 0.00 65531 (d)32760 12345.13 a5 0.00 65530
[Q007] What will be the output of the following program : struct { int i,val[25]; }var={1,2,3,4,5,6,7,8,9},*vptr=&var; int main() { printf("%d %d %d\n",var.i,vptr->i,(*vptr).i); printf("%d %d %d %d %d (*vptr).val[4],*((*vptr).val+4)); return(0); } %d",var.val[4],*(var.val+4),vptr->val[4],*(vptr->val+4),

(a)Compile-Time Error (b)1 1 1 666666 (c)1 1 1 555555 (d)None of these


[Q008] What will be the output of the following program : typedef struct { int i; float f; }temp; void alter(temp *ptr,int x,float y) { ptr->i=x; ptr->f=y; } int main() { temp a={111,777.007}; printf("%d %.2f\n",a.i,a.f); alter(&a,222,666.006); printf("%d %.2f",a.i,a.f); return(0); }

(a)Compile-Time error (b)111 777.007 222 666.006 (c)111 777.01 222 666.01 (d)None of these
[Q009] What will be the output of the following program : typedef struct { int i; float f;

}temp; temp alter(temp tmp,int x,float y) { tmp.i=x; tmp.f=y; return tmp; } int main() { temp a={111,777.007}; printf("%d %.3f\n",a.i,a.f); a=alter(a,222,666.006); printf("%d %.3f",a.i,a.f); return(0); }

(a)Compile-Time error (b)111 777.007 222 666.006 (c)111 777.01 222 666.01 (d)None of these
[Q010] What will be the output of the following program : typedef struct { int i; float f; }temp; temp alter(temp *ptr,int x,float y) { temp tmp=*ptr; printf("%d %.2f\n",tmp.i,tmp.f); tmp.i=x; tmp.f=y; return tmp; } int main() { temp a={65535,777.777}; a=alter(&a,-1,666.666); printf("%d %.2f",a.i,a.f);

return(0); }

(a)Compile-Time error (b)65535 777.777 -1 666.666 (c)65535 777.78 -1 666.67 (d)-1 777.78 -1 666.67
[Q011] What will be the output of the following program : struct my_struct1 { int arr[2][2]; }; typedef struct my_struct1 record; struct my_struct2 { record temp; }list[2]={1,2,3,4,5,6,7,8}; int main() { int i,j,k; for (i=1; i>=0; i--) for (j=0; j<2; j++) for (k=1; k>=0; k--) printf("%d",list[i].temp.arr[j][k]); return(0); }

(a)Compile-Time Error (b)Run-Time Error (c)65872143 (d)56781243


[Q012] What will be the output of the following program : struct my_struct { int i; unsigned int j; }; int main() {

struct my_struct temp1={-32769,-1},temp2; temp2=temp1; printf("%d %u",temp2.i,temp2.j); return(0); }

(a)32767 -1 (b)-32769 -1 (c)-32769 65535 (d)32767 65535


[Q013] What will be the output of the following program : struct names { char str[25]; struct names *next; }; typedef struct names slist; int main() { slist *list,*temp; list=(slist *)malloc(sizeof(slist)); // Dynamic Memory Allocation strcpy(list->str,"Hai"); list->next=NULL; temp=(slist *)malloc(sizeof(slist)); // Dynamic Memory Allocation strcpy(temp->str,"Friends"); temp->next=list; list=temp; while (temp != NULL) { printf("%s",temp->str); temp=temp->next; } return(0); }

(a)Compile-Time Error (b)HaiFriends

(c)FriendsHai (d)None of these


[Q014] What will be the output of the following program : (i) struct A { int a; struct B { int b; struct B *next; }tempB; struct A *next; }tempA; (ii) struct B { int b; struct B *next; }; struct A { int a; struct B tempB; struct A *next; }; (iii) struct B { int b; }tempB; struct { int a; struct B *nextB; }; (iv) struct B { int b; struct B { int b; struct B *nextB; }tempB; struct B *nextB; }tempB;

(a) (iv) Only (b) (iii) Only (c)All of the these (d)None of these
[Q015] What will be the output of the following program : union A { char ch; int i;

float f; }tempA; int main() { tempA.ch='A'; tempA.i=777; tempA.f=12345.12345; printf("%d",tempA.i); return(0); }

(a)Compile-Time Error (b)12345 (c)Erroneous output (d)777


[Q016] What will be the output of the following program : struct A { int i; float f; union B { char ch; int j; }temp; }temp1; int main() { struct A temp2[5]; printf("%d %d",sizeof temp1,sizeof(temp2)); return(0); }

(a)6 30 (b)8 40 (c)9 45 (d)None of these

[Q017] What will be the output of the following program : int main() { static struct my_struct { unsigned a:1; unsigned b:2; unsigned c:3; unsigned d:4; unsigned :6; // Fill out first word }v={1,2,7,12}; printf("%d %d %d %d",v.a,v.b,v.c,v.d); printf("\nSize=%d bytes",sizeof v); return(0); }

(a)Compile-Time Error (b)1 2 7 12 Size=2 bytes (c)1 2 7 12 Size=4 bytes (d)None of these
[Q018] What are the largest values that can be assigned to each of the bit fields defined in [Q017] above. (a)a=0 b=2 c=3 d=4 (b)a=1 b=2 c=7 d=15 (c)a=1 b=3 c=7 d=15 (d)None of these [Q019] What will be the output of the following program : int main() { struct sample { unsigned a:1; unsigned b:4; }v={0,15}; unsigned *vptr=&v.b; printf("%d %d",v.b,*vptr); return(0); }

(a)Compile-Time Error (b)0 0 (c)15 15 (d)None of these


[Q020] What will be the output of the following program : int main()

{ static struct my_struct { unsigned a:1; int i; unsigned b:4; unsigned c:10; }v={1,10000,15,555}; printf("%d %d %d %d",v.i,v.a,v.b,v.c); printf("\nSize=%d bytes",sizeof v); return(0); }

(a)Compile-Time Error (b)1 10000 15 555 Size=4 bytes (c)10000 1 15 555 Size=4 bytes (d)10000 1 15 555 Size=5 bytes Solutions for the above queries. Solutions : Structures & Unions [Q001] Ans. (d) Though both <struct type name> and <structure variables> are optional, one of the two must appear. In the above program, <structure variable> i.e. var is used. (2 decimal places or) 2-digit precision of 9.76723 is 9.77 [Q002] Ans. (d) Both <struct type name> and <structure variables> are optional. Thus the structure defined in the above program has no use and program executes in the normal way. [Q003] Ans. (c) The members of a structure variable can be assigned initial values in much the same manner as the elements of an array. The initial values must appear in order in which they will be assigned to their corresponding strucutre members, enclosed in braces and separated by commas.

[Q004] Ans. (c) In the above program, values is the user-defined structure type or the new user-defined data type. Structure variables can then be defined in terms of the n ew data type. [Q005] Ans. (a) C language does not permit the initialization of individual structure members within the template. The initialization must be done only in the declaration of the actual variables. The correct way to initialize the values is shown in [Q003] or [Q004]. [Q006] Ans. (d) Illustrating 3 different ways of declaring the structres : first, second and third are the user-defined structure type. s1, s2 and s3 are structure variables. Also an expression of the form ++variable.member is equivalent to ++(variable.member), i.e. ++ operator will apply to the structure member, not the entire structure variable. [Q007] Ans. (b) Since value of the member 'i' can be accessed using var.i, vptr->i and (*vptr).i Similarly 5th value of the member 'val' can be accessed using var.val[4], *(var.val+4), vptr->val[4], *(vptr->val+4), (*vptr).val[4] and *((*vptr).val+4) [Q008] Ans. (c) This program illustrates the transfer of a structure to a function by passing the structure's address (a pointer) to the function. [Q009] Ans. (b) This program illustrates the transfer of a structure to a function by value. Also the altered structure is now returned directly to the calling portion of the program. [Q010]

Ans. (d) This program illustrates the transfer of a structure to a function by passing the structure's address (a pointer) to the function. Also the altered structure is now returned directly to the calling portion of the program. [Q011] Ans. (c) This program illustrates the implementation of a nested structure i.e. structure inside another structure.
[Q012]

Ans. (d) An entire structure variable can be assigned to another structure variable, provided both variables have the same composition.
[Q013]

Ans. (c) It is sometimes desirable to include within a structure one member i.e. a pointer to the parent structure type. Such structures are known as Self-Referencial structures. These structures are very useful in applications that involve linked data structures, such as lists and trees. [A linked data structure is not confined to some maximum number of components. Rather, the data structure can expand or contract in size as required.]
[Q014]

Ans. (d) Since all the above structure declarations are valid in C.
[Q015]

Ans. (c) The above program produces erroneous output (which is machine dependent). In effect, a union creates a storage location that can be used by any one of its members at a time. When a different member is assigned a new value, the new value supercedes the previous member's value. [NOTE : The compiler allocates a piece of storage that is large enough to hold the largest variable type in the union i.e. all members share the same address.]
[Q016]

Ans. (b) Since int (2 bytes) + float (4 bytes) = (6 bytes) + Largest among union is int (2 bytes) is equal to (8 bytes). Also the total number of bytes the array 'temp2' requires : (8 bytes) * (5 bytes) = (40 bytes).
[Q017]

Ans. (b) The four fields within 'v' require a total of 10 bits and these bits can be accomodated within the first word(16 bits). Unnamed fields can be used to control the alignment of bit fields within a word of memory. Such fields provide padding within the word. [NOTE : Some compilers order bit-fields from righ-to-left (i.e. from lower-order bits to high- order bits) within a word, whereas other compilers order the fields from left-to-right (high- order to low-order bits). Ans. (c)a=1 (1 bit: 0 or 1) b=3 (2 bits: 00 or 01 or 10 or 11), c=7 (3 bits: 000 or 001 or 010 or 011 or 100 or 101 or 110 or 111) d=15 (4 bits: 0000 or 0001 or 0010 or 0011 or 0100 or 0101 or 0110 or 0111 or 1000 or 1001 or 1010 or 1011 or 1100 or 1101 or 1110 or 1111) [Q019] Ans. (a) Since we cannot take the address of a bit field variable i.e. Use of pointer to access the bit fields is prohibited. Also we cannot use 'scanf' function to read values into a bit field as it requires the address of a bit field variable. Also array of bit-fields are not permitted and a function cannot return a bit field. [Q020]
[Q018]

Ans. (d) Here the bit field variable 'a' will be in first byte of one word, the variable 'i' will be in the second word and the bit fields 'b' and 'c' will be in the third word. The variables 'a', 'b' and 'c' would not get packed into the same word. [NOTE: one word=2 bytes] Challenging Programming Problems - Part I

[Q001] Write

a program (W.A.P.) in C to SWAP the contents of 3 variables without

using the temporary (or extra) variables.

[Q002] W.A.P. in C to find the Fifth root of the sum of the squares of the first 100 ODD numbers only.

[ Q003] W.A.P. in C to multiply any two numbers without using * (asterisk) [Hint : Use BITWISE OPERATORS]

[Q004] W.A.P. in C to check whether given number x is equal to the value 2 POWER i or something, where i>=0 using BITWISE operators ONLY. [Hint : Check whether the given number x is equal to the value 2 POWER i or something using BITWISE operators ONLY]

[Q005] W.A.P. in C to maintain 2 STACKS within a SINGLE ARRAY and the values of one stack should not overwrite the values of another stack.

[Q006] W.A.P. in C that act as a guessing game in which the user has eight tries to guess a randomly generated number. The program will tell the user each time whether he guessed high or low. The user WINS the game when the number guessed is same as randomly generated number.

[Q007]W.A.P. to determine how much money is in a piggy bank that contains several 50 paise coins, 25 paise coins, 20 paise coins, 10 paise coins and 5 paise coins. Use the following values to test your program : Five 50 paise coins, Three 25 paise coins, Two 20 paise coins, One 10 paise coin and Fifteen 5 paise coins. (Answer : Rs. 4.50)

[Q008] Modify the program given in [Q007] to accept total amount (in rupees) and convert them into paise.(Vice-versa of [Q007]) [Q009] W.A.P. in C to determine how many of the characters are vowels and how many are consonants in a given line of text. Also terminate the string when the input character encountered is other than the alphabets(a-z or A-Z) and Blank spaces. [Hint:(a) When the input string is 'C FOR SWIMMERS, TEST YOUR C PROGRAMMING STRENGTHS'. Consider the string 'C FOR SWIMMERS' only Because ',' is encountered. (b) When the input string is 'Y2K PROBLEM'. Consider the character 'Y' only Because the '2' is encountered.]

Solutions for the above queries. Solutions : Pointers - Part II [Q001] Ans. (d) When using macros with argument lists, you can merge (or paste) two tokens by separating them with ## (plus optional whitespace on either side), i.e. Token pasting with ##. [Q002] Ans. (c) Preprocessor directives can be defined anywhere in the program but just before its use. [Q003] Ans. (d) Preprocessor directives can be defined anywhere in the program but just before its use. [Q004] Ans. (a) Consider any function definitions (here it is 'main') in which DECLARATION OF VARIABLES between the () and {} are LEGAL for specifying data types for FORMAL PARAMETERS ONLY. Otherwise it is ILLEGAL or INVALID. Ex:- int c; in the above program is an ILLEGAL statement in C. [Q005] Ans. (b) A macro cannot call itself recursively. [Q006] Ans. (c) A const variable can be indirectly modified by a pointer as shown in the above program. [Q007] Ans. (c) The "stringizing" operator # allows a formal argument within a macro definition to be converted to a string. Any special characters such as '," and \, will be replaced by their corresponding escape sequences, Ex: \',\" and \\. In addition, the resulting string will automatically be concatenated (combined) with any adjacent strings. [Q008] Ans. (b) The "stringizing" operator # allows a formal argument within a macro definition to be converted to a string. The "token-pasting" operator ## causes individual items within a macro definition to be concatenated, thus forming a single item. [Q009]

Ans. (b) The "stringizing" operator # allows a formal argument within a macro definition to be converted to a string. Consecutive whitespace characters inside the actual argument will be replaced by a single blank space character. [Q010] Ans. (b) It is legal but ill-advised to use Turbo C++ keywords as macro identifiers. In the above program : #define int float is legal, but possibly catastrophic. [Q011] Ans. (c) To skip over a data item without assigning it to the designated variable or array, the % sign within the appropriate control group should be followed by an asterisk (*). This feature is referred to as ASSIGNMENT SUPPRESSION.
[Q012]

Ans. (d) The variable 'val' is declared as static, hence memory for 'val' will be allocated for only once, as it encounters the statement. The function main() will be called recursively unless 'val' becomes equal to 0, and since main() is recursively called, so the value of static 'val' ie., 0 will be printed every time the control is returned.
[Q013]

Ans. (a) The variable j is a block level variable and the visibility is inside that block only.
[Q014]

Ans. (c) The preprocessor directives can be redefined anywhere in the program. So the most recently assigned value will be taken.
[Q015]

Ans. (a) #define statement defines symbolic constants in a C program. So the assigned value cannot be altered using any operators instead it can be redefined anywhere in the program.
[Q016]

Ans. (b) *a and -*a cancels out. The result is as simple as 9 - 3 = 6

Ans. (c) Since i is static it is initialized to 0. Inside the while loop the conditional operator evaluates to false, executing i--. Thus the integer value rotates to positive value (32767). Then while condition becomes false and hence, comes out of the while loop, printing the i value. [Q018] Ans. (d) The boolean expression needs to be evaluated only till the truth value of the expression is not known. Here <expr1>'s truth value is 1 or true. Because true || <expr2> where (expr2) will not be evaluated. So the value of a remains the same. Thus a=5, b=7 & c=1 [Q019] Ans. (c) The pointer ptr will point to the integer value in the memory location 0x1fa. Ex: The value 5000 stored at 0x1fa and 0x1fb since size of integer value is 2 bytes. Similarly,the value 6000 stored at 0x1fc and 0x1fd. [Q020] Ans. (c) str[i] is same as i[str], str[i] is same as *(str+i), str[i+1] is same as *++(str+i) Careful observation is necessary.
[Q017] [Q001] Write

Challenging Programming Problems -Part II a program (W.A.P.) in C to clear the screen and print

"Freshersworld" on each line, forming a diagonal pattern running from upper-left to lower right.[Use suitable delay]
[Q002] W.A.P.

in C to SORT the array of strings based on first 3-LETTERS ONLY.

[Q003] Some C Functions take variable argument list in addition to taking a number of fixed (known) parameters. Implement using USER-DEFINED C FUNCTION that take VARIABLE ARGUMENT LIST and COMPUTE THE SUM OF VALUES specified in the list. Ex: int Sum(int a,...) // Here ... means VARIABLE ARGUMENT LIST { // Your Code Goes Here to access the values in the variable argument list } void main(void) { printf("%d",Sum(5,6,7,8,9,10)); // Prints the RESULT (Sum of these values=45) }

[Q004] W.A.P.

in C to compute the sum of two values using function that takes two

arguments (INTEGERS) and IT SHOULD RETURN the sum WITHOUT USING the RETURN statement but the return type of function is INTEGER ('int' data type). [NOTE : DO NOT MAKE USE OF ANY GLOBAL VARIABLES OR POINTER CONCEPT]

[Q005] W.A.P. in C to SWAP the contents of TWO VARIABLES WITHOUT using ASSIGNMENT OPERATOR. [HINT : USE 'asm' statement]

[Q006] W.A.P.

in C to FIND THE LARGEST of two numbers (integer) WITHOUT

using ?: operator, if, if...else and switch statements. [HINT : USE 'asm' statement]

[Q007] W.A.P. in C to print the following output WITHOUT USING GOTO STATEMENT, CONDITIONAL STATEMENTS (if, if...else & switch statements) and ANY LOOP STATEMENTS (for, while & do..while) : (a)

***** **** *** ** *


(b)

* ** *** **** *****


[Q008] W.A.P.

in C to REVERSE THE WORDS IN A GIVEN LINE OF TEXT.

[HINT : USE Built-in function 'strtok' in 'string.h' header file]

[Q009] W.A.P. in C to CONVERT THE TEXT within /* ... */ to UPPER-CASE (all occurrences)

from the SPECIFIED C Source Code File and save the file without altering the remaining text. [Q010] W.A.P.

in C to READ a line of text and WRITE it out BACKWARDS using RECURSIVE Function. Solutions for the above queries.

Solutions : Pointers - Part II [Q001] /* Print Freshersworld on each line, forming a diagonal pattern */ #include<stdio.h> #include<conio.h> #include<dos.h> void main() { char str[]="Freshersworld"; int x=1,y; for (y=1; y<=25; y++) { clrscr(); gotoxy(x,y); printf("%s",str); delay(250); if (y < 8) x+=2; else x+=3; } } /* End of main */

[Q002]

[Q003] /* Compute the sum of values in the variable argument list */ #include<stdio.h> #include<stdarg.h> int Sum(int a,...) { int total=a; va_list ap; int arg; va_start(ap,a); while ((arg = va_arg(ap,int)) != 0) { total+=arg; } va_end(ap); return total; } void main() { clrscr(); printf("%d",Sum(5,6,7,8,9,10)); getch(); } /* End of main */ [Q004] // Compute the sum of two values using function and return the result w/o using RETURN statement #include<stdio.h> #include<conio.h> int Sum(int a,int b)

{ _AX = a + b; // equivalent to : return (a + b); } void main(void) { clrscr(); printf("Result is = %d",Sum(4,6)); getch(); } /* End of main */ [Q005] /* To swap the contents of two variables using 'asm' statement */ #include<stdio.h> #include<conio.h> void main() { int val=85,num=77; clrscr(); printf("Before swapping : %d and %d",val,num); asm mov ax,val asm mov cx,num asm mov num,ax asm mov val,cx printf("\n\nAfter swapping : %d and %d",val,num); } /* End of main */ [Q006] /* To find largest of two numbers using 'asm' statement */ #include<stdio.h> #include<conio.h> void main() {

int val=85,num=77; clrscr(); asm mov ax,val asm cmp ax,num asm jg FirstNum asm mov ax,num FirstNum:printf("Largest of two numbers is %d",_AX); } /* End of main */ [Q007] (a)

/* To print the above pattern or output using asm statement */ #include<stdio.h> #include<conio.h> void main(void) { int i=5,j; clrscr(); // asm statement doesn't end with semicolon (starts with 'asm' keyword) asm mov ax,i // Move the value of 'i' to accumulator (ax) Loopi: j=i; Loopj: printf("*"); // Print asterisk (*) j=j-1; asm mov cx,j // Decrement the counter : Inner Loop asm cmp cx,0 asm jnz Loopj // Terminate the Inner Loop if counter is 0, otherwise goto Loopj i=i-1; printf("\n"); asm mov ax,i // Decrement the counter : Outer Loop asm cmp ax,0

asm jnz Loopi // Terminate the Outer Loop if counter is 0, otherwise goto Loopi getch(); } /* End of main */ ***** **** *** ** * (b)

/* To print the above pattern or output using asm statement */ #include<stdio.h> #include<conio.h> void main(void) { int i=1,j; clrscr(); // asm statement doesn't end with semicolon (starts with 'asm' keyword) asm mov ax,i // Move the value of 'i' to accumulator (ax) Loopi:j=0; Loopj:printf("*"); // Print asterisk (*) j=j+1; asm mov cx,j // Increment the counter : Inner Loop asm cmp cx,i asm jnz Loopj // Terminate the Inner Loop if Inner Loop counter = Outer Loop counter i=i+1; printf("\n");

asm mov ax,i // Increment the counter : Outer Loop asm cmp ax,6 asm jnz Loopi // Terminate the Outer Loop if counter = 6 getch(); } /* End of main */ [HINT : USE 'asm' statement] * ** *** **** ***** [Q008] /* To reverse the words in a given line of text */ #include<stdio.h> #include<string.h> void main() { char ch,str[80],*res="",*temp,*temp1; clrscr(); printf("Enter a sentence :\n"); scanf("%[^\n]",str); temp=strtok(str," "); do { strcpy(temp1,temp); strcat(temp1," "); strcat(temp1,res); strcpy(res,temp1);

temp=strtok(NULL," "); }while (temp != NULL); printf("\n Result : %s",res); getch(); } /* End of main */ [Q009]

[Q010] /* To reverse a given line of test using recursive function */ #include<stdio.h> #include<conio.h> void reverse(void) { char c; if ((c = getchar()) != '\n') reverse(); putchar(c); return; } void main() { clrscr(); printf("Please enter a line of text below\n"); reverse(); } /* End of main */

You might also like