Standard prototypes for main() function

a. int main (void)
b. int main (int argc, char **argv)
c. int main (int argc, char *argv[])

C++ Features Not in C

Listed below are some features that are found in C++, not found in C, but still have nothing to do with Object Oriented Programming.

Casts:
In C, if you want to cast an int to a long int, for example, you'd use 
int i=0; 
long l = (long) i; 

In C++, you can use a function-like call to make the cast. 
long l = long(i);

It's easier to read. Since it's possible to create functions to perform casts involving user-defined types, this makes all the casts look consistent. For example, you may have a user-defined type -- complex numbers. 

You have a function that accepts an integer and casts it to a complex number: 1 --> 1 + 0i (real part is 1 and imaginary part is 0) 

Suppose your function call is named 'complex', then it may look like: 

Complex x;
int i=1; 
 x = complex(i);

Flexible Declarations:
In C, all var declarations within a scope occur at the beginning of that scope. Thus, all global declartions must appear before any functions, and any local declarations must be made before any executable statements.

C++, on the other hand, allows you to mix data declarations with functions and executable statements. 

E.g. In C,
void makeit(void) 
{
      float i; 
      char *cp;
      /* imagine 2000 lines of code here */ 
      /* allocate 100 bytes for cp */ 
      cp = malloc(100); /* 1st use of cp */ 
      for (i=0; i<100; ++i) /* 1st use of i */ 
      { 
              /* do something */ 
      } /* more code */ 
 } 

In C++, 
void makeit(void) 
      // 2000 lines of code 
      char *cp = new char[100]; 
      for (int i=1; i<10; i++) { } 
}

'struct' and 'union' Tags:

In C, we would have this segment: 
struct foo 
{
      int a; 
      float b;
struct foo f; 

This declares a struct with the tag name 'foo' and then creates an instance of foo named f. Notice when you declare var of that struct, you have to say 'struct foo'. 
In C++, struct and union tags are considered to be type name, just as if they had been declared by the 'typedef' statement. 

struct foo {int a; float b;}
foo f; 

which is equivalent to the following in C: 
typedef struct 
      int a; 
      float b; 
} foo;

foo f;


'const':

In ANSI C, it also supports 'const', but C++'s 'const' is more flexible than C's. In both C and C++, a value declared as 'const' is inviolate; it may not be modified by any part of the program in any way. 
The most common use of 'const' values in C is to replace '#define' literal constants. 

#define MAX_CUSTOMERS 10 
 const int MAX_CUSTOMERS = 10; 

Thus, 
MAX_CUSTOMERS = 10; 
MAX_CUSTOMERS ++; 

are both not acceptable. Note: since you cannot make changes to a 'const', each constant must be initialized when declared. The following is wrong: 
const int invalid; 

In C++, you can do something like 
const int ArraySize = 100;
int Array[ArraySize];
while in ANSI C, this would be flagged as an error.

'new' and 'delete':

In C, all dynamic mem allocation is handled via library calls, such as 'malloc' and 'free'. Here's how a traditional C programs might allocate memory: 

void func(void) 
{
     int *i; 
     i = (int *)malloc(sizeof(int)); 
    *i = 10; 
     printf("%d", *i); 
     free(i); 

In C++, there are new ways of dynamically allocating mem using operators called 'new' and 'delete', where 'new' replaces 'malloc' and 'delete' replaces 'free' in C. We could rewrite the above function as the following: 

void func() 
     int *i = new int; 
     *i = 10; 
     cout << *i; 
     delete i; 
}
You'd probably agree this is a much clearer syntax and it's much easier to use as well. 

A couple more examples: 
     int *i = new int[10]; // an array of 10 integers 
     int *i = new int(*)[10]; // an array of 10 pointers to integers 

You can also intialize all the variables allocated by 'new': 

float *f = new float[50] (0.0); 

Error Code: if 'new' fails to allocate any memory requested, it will return NULL;
Tip: Usually, right after a call to allocate memory, 'new' or 'malloc' check to see if any memory has been allocated. This can prevent your program from accessing a NULL pointer which is a disaster and which will cause a bus error.

Note: Don't mix the use of 'new' and 'delete' with that of 'malloc' and 'free'. i.e, always use either all the C lib calls 'malloc' and 'free' in your program to manage dynamic mem. OR use all 'new' and 'delete'. All the mem allocated by 'malloc' should be returned to the available mem pool by 'free' and the same holds for 'new' and 'delete'. I'd just use 'new' and 'delete'.

References:

C can by clumsy sometimes. When you write a function to swap two integers, you have to pass the two integers into the function by reference: 

void swapint(int *a, int *b) 
      int temp;
      temp = *a; 
      *a = *b; 
      *b = temp; 
}
Here's the function call: 
    swapint(&i1, &i2); 

C++ supports a special type of identifier known as 'reference' &. It makes changing the parameter values in a function reletively painless. The above function can be rewritten in C++ as follows: 

void swapint(int &a, int &b) 
     int temp = a; 
     a = b; 
     b = temp; 
Function call: 
     swapint(i1, i2); 

When i1 and i2 are passed into the function, a POINTS to i1 and b POINTS to i2 instead of making local copies of i1 and i2. Now, whenever you refer to a or b in the function, you actually refer to i1 and i2. So, whatever changes you make to a or b, they will be reflected on i1 and i2.


Function Overloading:

In C, as in most other programming languages, every function must have a unique name. At times, it can be annoying. Imagine you want to have a function that returns the abs value of an integer. 
int abs(int i); 

If you need to figure out the abs value of every possible available data type, you then have to write a function for each of the possible types: 

long labs(long l);
double dabs(double d); 

All those functions do the same thing -- return the abs value of the argument. Thus it seems silly to have a different name for each of those functions. 

C++ solves this by allowing you to create those functions with the same name. This is called overloading. 

For example, you can do the above in C++: 
int abs(int i); 
long abs(long l); 
double abs(double d); 

And depending on the type of parameter you pass into the 'abs' func. C++ will select the right one. 

Note: What if the type of the parameter passed in is not identical to any of the available parameter types in the existing functions? 

abs('a'); 
abs(3.1415F); 

C++ will try to make the easiest conversion to match those parameter types in the funcion prototypes. 

abs('a'); // call int abs(int i) 
abs(3.1415F); // call double abs(double d);
If no such conversion exists, then an error will occur.

C,C++ Quiz

1. Base class has some virtual method and derived class has a method with the same name. If we initialize the base class pointer with derived object,. calling of that virtual method will result in which method being called?
a. Base method 
b. Derived method..

Ans: b


2. For the following C program 
#define AREA(x)(3.14*x*x)
main()
{

        float r1=6.25,r2=2.5,a;
        a=AREA(r1);
        printf("\n Area of the circle is %f", a);
        a=AREA(r2);
        printf("\n Area of the circle is %f", a);
}

What is the output? 

Ans:
Area of the circle is 122.656250
Area of the circle is 19.625000

3.void main()  {
       int d=5;
       printf("%f",d);
  }

Ans: Undefined


4.void main()
{
     int i;
     for(i=1;i<4,i++)
     switch(i)
             case 1: printf("%d",i);break;
             {
             case 2:printf("%d",i);break;
             case 3:printf("%d",i);break;
             }
             switch(i) 

                      case 4:printf("%d",i);
}

Ans: 1,2,3,4

5.void main()
  {
          char *s="\12345s\n";
          printf("%d",sizeof(s));
  }

Ans: 6

6.void main()
  {
           unsigned i=1; /* unsigned char k= -1 => k=255; */
           signed j=-1; /* char k= -1 => k=65535 */
           /* unsigned or signed int k= -1 =>k=65535 */
           if(i<j)
                  printf("less");
           else
                  if(i>j)
                          printf("greater");
                  else
                          if(i==j)
                          printf("equal");
  }

Ans: less


7.void main()   {
          float j;
          j=1000*1000;
          printf("%f",j);
   }

1. 1000000
2. Overflow
3. Error
4. None 


Ans: 4

8.int f()  void main()
  {
       f(1);
       f(1,2);
       f(1,2,3);
  }
  f(int i,int j,int k)
  {
       printf("%d %d %d",i,j,k);
  }
What are the number of syntax errors in the above?

Ans: None.

9.void main() 

  {
        int i=7;
        printf("%d",i++*i++);
  }

Ans: 56

10.#define one 0 
    #ifdef one
    printf("one is defined ");
    #ifndef one
     printf("one is not defined ");
Ans: "one is defined"

11.void main() 
    {
           int count=10,*temp,sum=0;
           temp=&count;
           *temp=20;
           temp=&sum;
           *temp=count;
           printf("%d %d %d ",count,*temp,sum);
   }

Ans: 20 20 20




12.what is alloca()

Ans : It allocates and frees memory after use/after getting out of scope

13.main() 
    {
         static i=3;
         printf("%d",i--);
         return i>0 ? main():0;
    }

Ans: 321

14.char *foo() 
    {
         char result[100]);
         strcpy(result,"anything is good");
         return(result);
    }
    void main()
    {
         char *j;
         j=foo()
         printf("%s",j);
    }

Ans: anything is good.

Can I mix C-style and C++ style allocation and deallocation?

Yes, in the sense that you can use malloc() and new in the same program.

No, in the sense that you cannot allocate an object with malloc() and free it using delete. Nor can you allocate with new and delete with free() or use realloc() on an array allocated by new.

The C++ operators new and delete guarantee proper construction and destruction; where constructors or destructors need to be invoked, they are. The C-style functions malloc(), calloc(), free(), and realloc() doesn't ensure that. Furthermore, there is no guarantee that the mechanism used by new and delete to acquire and release raw memory is compatible with malloc() and free(). If mixing styles works on your system, you were simply "lucky" - for now.

If you feel the need for realloc() - and many do - then consider using a standard library vector. 

For example // read words from input into a vector of strings:

vector<string> words;
string s;
while (cin>>s && s!=".") words.push_back(s);


The vector expands as needed.

Copy Constructor in C++

Copy constructor is a constructor function with the same name as the class used to make copy of objects.

There are 3 important places where a copy constructor is called -

1)When an object is created from another object of the same type
2)When an object is passed by value as a parameter to a function
2)When an object is returned from a function

If a copy constructor is not defined in a class, the compiler itself defines one. This will ensure a shallow copy. If the class does not have pointer variables with dynamically allocated memory, then one need not worry about defining a copy constructor. It can be left to the compiler's discretion.
But if the class has pointer variables and has some dynamic memory allocations, then it is a must to have a copy constructor. 

For ex:

                    class A //Without copy constructor
                    {
                         private:
                                   int x;
                         public:
                                   A() 
                                   {
                                          A = 10;
                                   }
                                   ~A() 
                                   {
                                   }
                    }
                   class B //With copy constructor
                    {
                        private:
                                  char *name;
                        public:
                                   B()
                                   {
                                         name = new char[20];
                                   }
                                   ~B()
                                   {
                                         delete name[];
                                   }
                                 //Copy constructor
                                  B(const B &b)
                                  {
                                         name = new char[20];
                                         strcpy(name, b.name);
                                   }
                     };

Let us Imagine if we don't have a copy constructor for the class B. At the first place, if an object is created from some existing object, we cannot be sure that the memory is allocated. Also, if the memory is deleted in destructor, the delete operator might be called twice for the same memory location. 

This is a major risk. One thing is, if the class is not so complex this will come to the fore during development itself. But if the class is very complicated, then these kind of errors will be difficult to track.
We all know that compiler will generate default constructor, destructor, copy constructor and copy assignment = operator by default if we dont define in our class definitions. 
Assume that, there is a scenario where we should not allow copy constructor and copy assignment operator in the program. 
Lets take some example, 
class A {/*...*/}; 
int main() 

        A a; /* default constructor */ 
        A b(a); /* copy constructor.. We should not allow this */ 
        b = a; /* copy assignment operator.. we should not allow this */ 

How do you achieve this? 

You can acheive this by making your copy constructor and assignment operator private.
here is your modified code 

class A 
{/*... 
      private : 
                 A(const A& ) 
                 { 
                 } 
                 A& operator=(const A ) 
                 { 
                 }
*/};
int main()
{
     A a; /* default constructor */
     A b(a); /* copy constructor.. We should not allow this */
     b = a; /* copy assignment operator.. we should not allow this */
}

now you will get compilation error saying copy constructor and assignment operator are private members.

You are right. You can have these in private and you don't have to implement that.
class A 

     private: 
               A(const A&);
               A& operator=(const A&);
     public: 

The difference between shallow and deep copying is only relevant for compound objects. (i.e objects that contain other objects, like lists/class instances or if objects has pointers to dynamically allocated memory). 


A shallow copy is bitwise copy of any object.
A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.

A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

Thus if the object has no pointers to dynamically allocated memory, a shallow copy is probably sufficient. Therefore the default copy constructor, default assignment operator, and default destructor should be sufficient.
If there are compound objects, then one has to define their own copy constructors, assignment operator and destructors for deep copy.

For Example:

// Shallow copy

Class Test
{       public:
              Test( int a, float b )
              {
                     i = a;
                     j = b;
               }
      private:
               int i;
               float j;
}
Test t1( 10, 20.0 );
Test t2(t1); // In this case, shallow copy is sufficient.


// Deep Copy

Class Test
{       public:
               Test( int a, char* s )
               {
                      i = a;
                      int len = strlen(s);
                      str = new char[len+1];
               }
      private:
                int i;
                char* str;
}
Test t1( 10, "Test" );
Test t2(t1); // In this case, deep copy is needed.