Skip to main content

C - Ritchie & Kernighan Part 2

Chapter 3-Control Flow

  1. the else part of an if-else is optional,there is an ambiguity when an else if omitted from a nested if sequence. This is resolved by associating the else with the closest previous else-less if
  2. The case labeled default is executed if none of the other cases are satisfied. A default is optional; if it isn't there and if none of the cases match, no action at all takes place. Cases and the default clause can occur in any order.
  3. Because cases serve just as labels, after the code for one case is done, execution falls through to the next unless you take explicit action to escape.
  4. The standard library provides a more elaborate function strtol for conversion of strings to long integers
  5. A pair of expressions separated by a comma is evaluated left to right, and the type and value of the result are the type and value of the right operand.
  6. A%B = A when A<B
  7. The continue statement applies only to loops, not to switch. A continue inside a switch inside a loop causes the next loop iteration.
  8. A few situations where gotos may find a place. The most common is to abandon processing in some deeply nested structure, such as breaking out of two or more loops at once. The break statement cannot be used directly since it only exits from the innermost loop
  9. When assignment is made as var=value1,value2,..,valuen; value1 is assigned
  10. Any processing statement other than the case statements, written inside a switch case is ignored.
  11. Any variable declaration(int b) inside switch case statement is allowed and does not produce a compile error. But variable intialization(int b=4) , processing statements (b++)involving that variable produce compile error

Chapter 4-Functions


  1. If the function return type is omitted, int is assumed.
  2. return expression;
The expression will be converted to the return type of the function if necessary. Parentheses are often used around the expression, but they are optional. The calling function is free to ignore the returned value
  1. It is not illegal, but probably a sign of trouble, if a function returns a value from one place and no value from another. In any case, if a function fails to return a value, its ``value'' is certain to be garbage.
  2. Suppose that three functions are stored in three files called a.c, b.c, and c.c. Then the command 'cc a.c b.c c.c'
compiles the three files, placing the resulting object code in files a.o, b.o, and c.o, then loads them all into an executable file called a.out. If there is an error, say in b.c, the file can be recompiled by itself and the result loaded with the previous object files, with the command
cc b.c a.o c.o
  1. A function returning a data type can be declared along with any variable or function returning the sma e data type eg:double sum, atof(char []);
  2. a function is implicitly declared by its first appearance in an expression.If a name that has not been previously declared occurs in an expression and is followed by a left parentheses, it is declared by context to be a function name, the function is assumed to return an int, and nothing is assumed about its arguments.
  3. if a function declaration does not include arguments(func()),nothing is to be assumed about the arguments of the functions; all parameter checking is turned off.
  4. But,If the function takes arguments,you can declare them or if it takes no arguments, use void.
  5. The value of the expression in 'return expression'; is converted to the return type of the function before its returned.If this operation does potentionally discard information, however, so some compilers warn of it.
  6. C does not allow functions to be defined inside other functions
  7. By default, external variables and functions have the property that all references to them by the same name, even from functions compiled separately, are references to the same thing. (The standard calls this property external linkage.)
  8. The scope of an external variable or a function lasts from the point at which it is declared to the end of the file being compiled.
  9. if an external variable is to be referred to before it is defined, or if it is defined in a different source file from the one where it is being used, then an extern declaration is mandatory.
  10. It is important to distinguish between the declaration of an external variable and its definition. A declaration announces the properties of a variable (primarily its type, has an extern keyword if [70] holds); a definition also causes storage to be set aside.
  11. There must be only one definition of an external variable among all the files that make up the source program; other files may contain extern declarations to access it.
  12. The static declaration, applied to an external variable or function, limits the scope of that object to the rest of the source file being compiled. So, the external variables can be shared as well as shielded from outside functions that may try to access them
  13. In case of [73], those static variable names will not conflict with the same names in other files of the same program.
  14. If a function is declared static, however, its name is invisible outside of the file in which it is declared.
  15. Internal static variables are local to a particular function just as automatic variables are, but unlike automatics, they remain in existence rather than coming and going each time the function is activated. i..e retain values
  16. A register declaration advises the compiler that the variable in question will be heavily used
  17. Register variables are to be placed in machine registers, which may result in smaller and faster programs. But compilers are free to ignore the advice.
  18. It is not possible to take the address of a register variable regardless of whether the variable is actually placed in a register.
  1. Variables can be defined in a block-structured fashion within a function. Declarations of variables (including initializations) may follow the left brace that introduces any compound statement, not just the one that begins a function. Variables declared in this way hide any identically named variables in outer blocks, and remain in existence until the matching right brace. eg:if(...){int i=5; ....}
  1. Automatic variables, including formal parameters, also hide external variables and functions of the same name.
In the absence of explicit initialization, external and static variables are guaranteed to be initialized to zero; automatic and register variables have undefined (i.e., garbage) initial values.
  1. For external and static variables, the initializer must be a constant expression; the initialization is done once, conceptionally before the program begins execution. For automatic and register variables, the initializer is not restricted to being a constant: it may be any expression involving previously defined values, even function
  1. When the size of the array is omitted, the compiler will compute the length by counting the initializers
  1. If there are fewer initializers for an array than the specified size, the others will be zero for external, static and automatic variables. It is an error to have too many initializers
  1. There is no way to specify repetition of an initializer, nor to initialize an element in the middle of an array without supplying all the preceding values as well(possible in explicit assignment).
  1. Assigning the value of the element to the value of a previously intialised element in the array,gives no error.But assigns only junk a[]={8,a[0]}
  1. A long definition may be continued onto several lines by placing a \ at the end of each line to be continued.
  1. Formal parameters are not replaced within quoted strings. If, however, a parameter name is preceded by a # in the replacement text, the combination will be expanded into a quoted string with the parameter replaced by the actual argument
  1. Within the actual argument, each " is replaced by \" and each \ by \\, so the result is a legal string constant.
  1. The preprocessor operator ## provides a way to concatenate actual arguments during macro expansion. If a parameter in the replacement text is adjacent to a ##, the parameter is replaced by the actual argument, the ## and surrounding white space are removed, and the result is re-scanned
  1. Names may be undefined with #undef, usually to ensure that a routine is really a function, not a macro
  1. The expression defined(name) in a #if is 1 if the name has been defined, and 0 otherwise.(Macros and #define can be given anywhere in the source file in unix)

    Chapter 5-Pointers

  2. a 'pointer to void' is used to hold any type of pointer but cannot be dereferenced itself.
  3. (*ip)++ The parentheses are necessary here; without them, the expression would increment ip instead of what it points to, because unary operators like * and ++ associate right to left.
  4. Associativity determines the direction in which the expression is processed. Here in [95] , processing starts from the right and proceeds according to precedence in that direction
  5. The reason why scanf uses '&' for reading inputs is that : it returns the end of file status as its function value, while using a pointer argument to store the input in the memory object
(This is a general method used when a function has to return more than one value)
  1. Array name stores the pointer to the first element in the array i.e. Constant Pointer to the start of the array. Can be used only as a Rvalue;
  2. When an array name is passed to a function, it becomes a mere pointer. Hence incrementing it is legal and can be used as Lvalue. This is same as passing a copy of the address of the first element of the array.
  3. C guarantees that zero is never a valid address for data
  4. Pointers and integers are not interchangeable. Zero is the sole exception: the constant zero may be assigned to a pointer, and a pointer may be compared with the constant zero. The symbolic constant NULL is often used in place of zero.
  5. Operators like ==, !=, <, >=, etc,work properly on pointers of same type. With pointers of different types,warning is produced;but it works.
  6. The header <stddef.h> defines a type ptrdiff_t that is large enough to hold the signed difference of two pointer values.
  7. size_t is the unsigned integer type returned by the sizeof operator.
  8. Only legal pointer operations are comparing pointers of same type, adding or subtracting integer and a pointer.Subtaction of pointers is legal.
  9. It is not legal to add two pointers, or to multiply or divide or shift or mask them, or to add float or double to them, or even, except for void *, to assign a pointer of one type to a pointer of another type without a cast.
  1. Individual characters within the array may be changed but
array name will always refer to the same storage. On the other hand,char ptr is a pointer, initialized to point to a string constant; the pointer may subsequently be modified to point elsewhere, but the result is undefined if you try to modify the string contents.
  1. If a two-dimensional array is to be passed to a function, the parameter declaration in the function must include the number of columns; the number of rows is irrelevant, since what is passed is, as before, a pointer to an array of rows (a row is treated as one data unit just like int,float)
  2. int *a[n] – is an array of 'n' pointerS to int.a is a pointer to such an array's first element
int (*a)[n]- is A pointer to an array of 'n' integers.([] have higher precedence than *)
  1. int *a[n] is a pointer array; Here, pointers are only allocated,not intialised. int a[n][m] is a 2D array. In 2d array, space for storing n*m object are set aside. The important advantage of the pointer array is that the rows of the array may be of different lengths. That is, each element of pointer array need not point to a equal sized vector. (Imagine an array of strings. Strings may have variable lengths)
  2. Memory allocation for individual pointers in a pointer array must be done explicitly through calls to malloc(). Eg: each pointer in an array of char ptrs must be intialised to point to a character array of required size.Whereas in a 2d array, the length is commonly fixed for all strings and no string can exceed that length.
  3. Argc(for argument count) is the number of command-line arguments the program was invoked with;argv (for argument vector) is a pointer to an array of character strings that contain the arguments, one per string.
  4. By convention, argv[0] is the name by which the program was invoked, so argc is at least 1. If argc is 1, there are no command-line arguments after the program name.
  5. The first optional argument is argv[1] and the last is argv[argc-1]; additionally, the standard requires that argv[argc] be a null pointer.
  6. The standard library function strstr(s,t) returns a pointer to the first occurrence of the string t in the string s, or NULL if there is none
  7. <type> (*func_ptr)(<arg_list>) says func_ptr is a pointer to a function with return type 'type' and the specified argument list. The function can be invoked by - (*func_ptr)(param_list).
  8. dcl is based on the grammar that specifies a declarator, this is a simplified form:

dcl: optional *'s direct-dcl
direct-dcl: name
direct-dcl[optional size]
In words, a dcl is a direct-dcl, perhaps preceded by *'s. A direct-dcl is a name, or a parenthesized dcl, or a direct-dcl followed by parentheses, or a direct-dcl followed by brackets with an optional size.
This grammar can be used to parse functions. For instance, consider this declarator:
pfa will be identified as a name and thus as a direct-dcl. Then pfa[] is also a direct-dcl. Then *pfa[] is recognized as a dcl, so (*pfa[]) is a direct-dcl. Then (*pfa[])() is a direct-dcl and thus a dcl.

Chapter 6-Structures


  1. An optional name called a structure tag may follow the word struct
  2. Structures can be nested.Structures may not be compared
  3. The only legal operations on a structure are copying it or assigning to it as a unit, taking its address with &, and accessing its members
  4. Precedence of -> > * > ++
  5. Structure array can be initalised as follows. struct_var[]={val11,val12,..,val1n,val21,val22,...valmn} and also as struct_var[]={{val11,val12,..,val1n},{val21,val22,..},.valmn}}. The set of {} for each array element is optional
  6. sizeof object <=> sizeof(object) .sizeof produces an unsigned integer value whose type, size_t, is defined in the header <stddef.h>.
  7. A sizeof can not be used in a #if line, because the preprocessor does not parse type names. But the expression in the #define is not evaluated by the preprocessor, so the code here is legal.
  8. The language definition does guarantee, however, that pointer arithmetic that involves the first element beyond the end of an array (eg, &tab[n]) will work correctly.However, &tab[-1] is illegal.
  9. Don't assume, however, that the size of a structure is the sum of the sizes of its members. Because of alignment requirements for different objects, there may be unnamed ``holes'' in a structure.Only the sizeof operator gives the proper size of the structure.
  10. It is illegal for a structure to contain an instance of itself.But, it can contain a pointer to a structure of the same type
  11. The alloc of does not guarantee any particular alignment, so we will use the standard library function malloc, which does.
  12. typedef int (*PFI)(char *, char *);
creates the type PFI, for ``pointer to function (of two char * arguments) returning int
  1. a union is a structure in which all members have offset zero from the base, the structure is big enough to hold the ``widest'' member, and the alignment is appropriate for all of the types in the union. The same operations are permitted on unions as on structures: assignment to or copying as a unit, taking the address, and accessing a member.
  2. Bit fields can be declared this way ; <type><bit-field-name> :<field-width> eg:i=unsigned int fl:1;
  3. Bit Fields behave like small integers, and may participate in arithmetic expressions just like other integers
  4. Bit fields can be set to 1 or 0 and can be tested using if(bitfield==0 || bitfield==1)
  5. Fields need not be names; unnamed fields (a colon and width only) are used for padding. The special width 0 may be used to force alignment at the next word boundary
  6. Fields may be declared only as ints; for portability, specify signed or unsigned explicitly. They are not arrays and they do not have addresses, so the & operator cannot be applied on them.
  7. The value of the bit field is set to the LSB(least significant bit) of the number assigned.

Value set to bit field
Odd number(LSB is 1)
Even numbe(LSB is 0)


Popular posts from this blog

Learning Spark Streaming #1

I have been doing a lot of Spark in the past few months, and of late, have taken a keen interest in Spark Streaming . In a series of posts, I intend to cover a lot of details about Spark streaming and even other stream processing systems in general, either presenting technical arguments/critiques, with any micro benchmarks as needed. Some high level description of Spark Streaming (as of 1.4),  most of which you can find in the programming guide .  At a high level, Spark streaming is simply a spark job run on very small increments of input data (i.e micro batch), every 't' seconds, where t can be as low as 1 second. As with any stream processing system, there are three big aspects to the framework itself. Ingesting the data streams : This is accomplished via DStreams, which you can think of effectively as a thin wrapper around an input source such as Kafka/HDFS which knows how to read the next N entries from the input. The receiver based approach is a little compl

Setting up Hadoop/YARN/Spark/Hive on Mac OSX El Capitan

If you are like me, who loves to have everything you are developing against working locally in a mini-integration environment, read on Here, we attempt to get some pretty heavy-weight stuff working locally on your mac, namely Hadoop (Hadoop2/HDFS) YARN (So you can submit MR jobs) Spark (We will illustrate with Spark Shell, but should work on YARN mode as well) Hive (So we can create some tables and play with it)  We will use the latest stable Cloudera distribution, and work off the jars. Most of the methodology is borrowed from here , we just link the four pieces together nicely in this blog.  Download Stuff First off all, make sure you have Java 7/8 installed, with JAVA_HOME variable setup to point to the correct location. You have to download the CDH tarballs for Hadoop, Zookeeper, Hive from the tarball page (CDH 5.4.x page ) and untar them under a folder (refered to as CDH_HOME going forward) as hadoop, zookeeper $ ls $HOME /bin/cdh/5.4.7 hadoop

HDFS Client Configs for talking to HA Hadoop NameNodes

One more simple thing, that had relatively scarce documentation out on the Internet. As you might know, Hadoop NameNodes finally became HA in 2.0 . The HDFS client configuration, which is already a little bit tedious, became more complicated. Traditionally, there were two ways to configure a HDFS client (lets stick to Java) Copy over the entire Hadoop config directory with all the xml files, place it somewhere in the classpath of your app or construct a Hadoop Configuration object by manually adding in those files. Simply provide the HDFS NameNode URI and let the client do the rest.          Configuration conf = new Configuration(false);         conf.set("", "hdfs://localhost:8020"); // this is deprecated now         conf.set("fs.defaultFS", "hdfs://localhost:8020");         FileSystem fs = FileSystem.get(conf); Most people prefer 2, unless you need way more configs from the actual xml config files, at which po