Thinking in C: Chapt 8b – Pointers 102

July 24, 2006

This was a nice advanced chapter. I remembered as well as learned many things.

Some basic stuff:

When a signed number is bit shifted right, the sign bit is propogated.

typedef declares synonyms. For eg:

typedef struct Student Student;

says that Student is a synonym for struct Student.

We can have nested pointers, such as pointers to pointers and pointers to pointers to pointers… uptil 12 levels. However 2 levels is what is practically used.

When sizeof is applied to a pointer to an array, the value it returns is the size of the array. An interesting idiom to find out the number of elements in an array is:

int a[10];

int num_ele = sizeof a/sizeof a[0];

Generic Pointers:

Void pointers are generic pointers. They are used when we do not know what type of pointer to accept or send. In C any pointer type can be assigned to void and the other way round.

Constant Pointers:

Pointers can be constant, which means that the pointer cannot point to another location, and the pointer’s referent can also be constant, which means that the value held in the location pointed by the pointer cannot be changed. Here is how we use them.

int* const i; Here i is a constant pointer. The value of the referent can be changed, but i cannot be changed.

const int* i; Here the referent is constant. The value of the pointer can be changed but the value of what it is pointing to cannot be changed.

Pointer Arithmatic:

When doing pointer arithmatic, when we add to or subtract from a pointer, the pointer is incremented or decremented by the number of elements and not the number of bytes. For eg:

int a[10];

a is a pointer to the begining of the array of integers. a++, a will not point to the next address, but to the next int in the array. So if an int is 4 bytes on your machine, a will be incremented by 4 bytes.

Similarly subtracting 2 pointers yeilds the number of elements between them. It follows that we cannot do arithmatic with pointers of different types.

Function pointers:

We can also have pointers to functions. Here is how we can get a pointer to printf.

int (*fp) (const char*,…) = printf;

This means that fp is a pointer to a function called printf which takes a const char* and an unknown number of parameters after that.

Incomplete types:

Incomplete types are used when we do not have the information in advance or we want to hide it from clients.

They are used with arrays and structures. For eg:

extern int a[]; Struct Employee;

Further Research

  • What happens when a signed number is bit shifted left? Is the sign bit maintained, or is it shifted out?
  • What happens when we have pointers of two different types and we cast them into void pointers to do arithmatic with them?
  • When a variable is declared extern, does the compiler try to verify it?
Advertisements

Thinking in C: Chapt 7 – Pointers 101

July 21, 2006

This was a very interesting chapter. I had forgotten some basic concepts related to pointers and it was nice to refresh them.

Pointers are used to support reference semantics in C. When we pass an array to a function in C, we are in reality passing a pointer to it. Arrays CANNOT be passed by value in C.

Pointers allow us to create dynamic objects whose size we do not know at compile time. Dynamic objects are created with malloc or calloc, and live on the heap. When an object is no longer needed, it’s memory must be returned to the heap by using ‘free’. Another function that C gives us is realloc() which updates the size of memory alloctaed using malloc. We might want to use the sizeof operator when allocating memory. To use these functions be sure to include <stdlib.h>

C has a NULL pointer which does not point to any valid memory location. Since it does not point to a valid memory location, it cannot be dereferenced. A NULL pointer is usually used for comparisons, with pointers returned from a method (where a NULL pointer denotes an error).

C supports two operators for working with pointers to structs. The . operator and the -> operator. When we use the -> operator, we do not need to dereference the pointer to struct.

An interesting note: Most operating systems will free memory used by a program when it exits, however it is usually a good idea to explicitly free memory because if our program takes huge amounts of memory then it might exhaust all the memory available on the system.

Did the assignment. Learned something interesting. If I have a structure Employee

struct Employee {

char name[16] ;

}

struct Employee emp = malloc(sizeof(struct Employee));

emp->name = someCharPointer; //does not compile

strcpy(emp->name, someCharPointer); //works just fine

Why does the first line not work? I think it is because name is initialized as an array of 16 chars, while someCharPointer is also a char pointer, but we do not know it’s size. I think the compiler senses that things could go wrong and disallows the assignment.

Research:

  • Does realloc work if the memory was allocated using calloc()?

Chapt 6 – Thinking in C: Programming with functions

July 21, 2006

A function must be either declared or defined before it’s use. To declare a function we need to specify the function prototype like this:

float avg(int, int);

A void is used to signify no parameters. If a function sayHello() takes no parameters, it can be defined like this:
void sayHello(void) {}
or like this
void sayHello() {}
In this case we may pass parameters to the function, but they will be ignored by the compiler as well as the runtime.

This section goes beyond functions and also mentions different variable types:

  • local variables are those that are declared in methods. They exist on the stack.
  • constant variables declared at the file level, reside in the data segment, and cannot be accessed from other files
  • variables declared at the file level also reside on the data segment, but can be accessed from other files

Research:

  • What is the data segment?

Thinking in C – Chapt 5: Compound data types

July 10, 2006

This chapter was a good refresher on structures in C. Anyways a little introduction to compound data types in C.There are three types of compund data types in C: array,strings, and structures. Strings are just a special type of character array where the last element is a null character.

We can read as well as write data incore instead of the regular console by using sscanf and sprintf.

eg: sscanf(str, “%d %f”, &num, &flo); In this example the data will be read from the buffer reffered to by “str” and not standard input.

eg: sprintf(str, “%d %f”, num, flo); In this example the data will be written to a buffer reffered to by “str” instead of standard output.

A structure is a data type that consists of primitive as well as other compund (including structures) data types. For eg: this is how we will represent an Employee record using structures.

Exercise: Make an Employee structure which will contain last_name, first_name, title, and salary. Accept details from the user and populate an array of Employees till the user submits “enter” for the last_name. The program then prints the list of employees.

Did the exercise.

When the program accepts a decimal, the newline that the user presses to submit the number lingers in the input stream and must be flushed or eaten. Otherwise it will be accepted in the next scanf.

Further Research:

  • What happens if the number of characters we enter are more than what the character array accepts.
  • What is the difference between gets() and scanf().

Thinking in C – Chapt 4: Controlling Program Flow

July 10, 2006

An interesting thing I learned here, is that way back in the sixties some scientists had proved that an alogorithm can be expressed using a :

  • Sequence of statements
  • Decision making constructs
  • Looping constructs
  • An arbitrary number of boolean flags

That was interesting…

A case statement can be used only with integers.

A scan with leading spaces before %c will ignore any number of whitespaces. If we do not include the space, then a space entered by mistake by the user will be read by scanf, ignoring the actual character value the user might have entered.

eg: scanf(” %c”, &c); //note the whitespace before %c

Chuck says that we should not declare variables within a switch clause. He did not explain the reason. Perhaps it is complicated and beyond the scope of this tutorial.

Excercise: Did the exercise. It was similar to the one in chapt 3, except that this time the user could enter an arbitrary number of integers (0 for quit).

Further Research:

  • Why should we not declare variables inside a swicth clause?

Thinking in C: Chapt 3: Operators

July 10, 2006

I am glad I remembered most of the things explained in this chapter. Operators in Java are very similar to operators in C. Infact that is one thing Java has taken right of from C++. C even supports short circuit for the logical operators.

The only difference in C is that it does not have boolean types. 0 is taken as false, while any non zero value is taken as true.

Operator precedance when using bitwise operators with other operators can get tricky, so it is always better to use parenthesis. Check the precedance table for more info.

Did the exercise. It involved reading three integers and printing the sum of odd and even integers that were entered. The purpose of the exercise was to explain the usage of operators.

Further Research:

  • Check formatting with Hexadecimal operators with the exersice.
  • Need a greater understanding of scanf. Why does scanf(“%d %d %d”) with values of 1 2 . yeild 2293674 for the . ?
  • What is the difference between puts() and printf()?

Thinking in C – Chapt 2: Fundamental Data Types

July 9, 2006

This chapter dealt with Fundamental Data Types in C: I was able to refresh many things that I had forgotten.

Characters are also numbers, but they are treated differently in C

There are 3 types of Integers (short, int, long), and the number of bits they may use is platform dependant. The size of an int is the word size on that platform (which in most modern platforms would be 32 bits), the size of short is 16 bits and the size of long is again platform dependant, but is at least 32 bits. This means that on some platforms short and int may be the same size and sometimes int and long may be the same size. However the limits for numeric type are always specified in certain header files. <limit.h> for integer limits and <float.h> for floating point limits.

There are 3 types of floating point numbers as well: float (single precision), double (double precision), and long double (extended double precision). The size of ‘double’ and ‘long double’ is platform dependant. Floating point numbers have a non standard distribution, which means that a number we want may not be representable. In such cases the system will round it to the nearest representable number. The direction of rounding is system dependant.

Characters are 8 bits wide which is why Unicode characters cannot be supported in C, however some implementations have a special type called ‘wchar_t’ (stands for wide char), which supports 16 bit characters.

Some examples of literals:
int i = 9, j = 017, k = 0x7F; (Base 10, Base 8, Base 16)
char c = ‘a’, c2 = 97 (97 may not mean the same character on different platforms)
long n = 1234567L;
float f = 1.23F;
double n = 1.34; (default)

constants can be initialized with other constants, literals, as well as variables. However in C a constant cannot be used to specify an array dimension. C++ on the other hand does allow this. In C we have to use # define to define a constant value that can be used to specify an array dimension.

Did the assignment. It ivolved reading in a floating point number, printing it out and then printing out the integer representation of the number. The purpose of the exercise was to show that when a floating point number is typecast into an integer, we lose the fractional part of the number.

Further Research:

  • Need to refresh concepts of mantissa, and power.