Showing posts with label C programing tutorials. Show all posts
Showing posts with label C programing tutorials. Show all posts

Tuesday

Bitwise operators

0 comments

Bitwise operators

The smallest element in memory on which are able to operate is called byte; and the programming language are byte oriented. One of the c powerful features is a set of bit manipulation operators. There are various bitwise operators in C as following table; we learn all step by step :

Operators    Name
&                Bitwise AND
|                  Bitwise OR
^                 Bitwise XOR(exclusive OR)
>>               Left shift
<<               right shift
~                 One's complement


These operators can operate upon ints and chars but not on floats and doubles. Bits are numbered from zero onwards, increasing from right to left as following figure:

7    6    5    4    3    2    1    0
8 bit Character


16    15    14    13    12    11    10    9    8    7    6    5    4    3    2    1    0
16 bit Integer


 Bitwise AND Operator (&)


The & operator operates on a pair of bits to yield a resultant bit. The rules that decide the value of the resultant bit also called truth table are shown below:

Bit x    Bit y    x & y
0          0            0
0          1            0
1          0            0
1          1            1

The best use of the AND operator is to check whether a particular bit of an operand is ON or OFF. The meaning of ON means 1 and OFF means 0. The following program puts this logic clear:

 /*Example of bitwise AND operator*/

 #include<stdio.h>
 #include<conio.h>
 void main()
 {
  int x=45;
  int y=37;
  int z;
  clrscr();
  z = x & y;
  printf("\nValue of z=%d",z);
 }



 Output of above program:

 Value of z=37


In above program compiler first calculate the binary x and y which is 111101 and 100101 respectly. After this its work on bitwise operator and final result is 37 which binary code are 100101. The following table shown the result : 

Values    binary code
x = 45    111101
y = 37    100101
z = x & y    100101

   Bitwise OR ( | )


Truth table for bitwise OR are as following :
x    y    z = x | y
0    0    0
0    1    1
1    0    1
1    1    1

  Bitwise XOR ( ^ )


It is also called exclusive OR. If there are similar bit then its return 0 otherwise its return 1. Let watch truth table of  x^y :
x    y    z = x ^ y
0    0    0
0    1    1
1    0    1
1    1    0
Example of exclusive OR :
x = 75
y = 64
z = x ^ y

 x = 1 0 0 1 0 1 1
 y = 1 0 0 0 0 0 0
 z = 0 0 0 1 0 1 1
 
hence, the value of z=11

Bitwise right shift ( >> )


Right shift operator shifts each bit in its left operand to the right. The number of places the bits are shifted depends on the number following the operator i.e. its right operand.
In simple meaning of bitwise right shift as :

            insertion(zero)  >  deletation

Example of right shift operator :
x = 15
y = x >> 2

[x=15 before right shifting ]         0000         0000      0000      1111
[y = x >> 2 during right shifting]  000000      0000      0000       1111
[y = x >> 2 after right shifting]     0000          0000      0000       0011

so now value of y=3.

Left Shift operator ( << )


This is similar to the right shift operator, the only difference being that the bits are shifted to the left, and for each shifted, a 0 is added to the right of the number. Following structure shows it :

  deletatio   >  insertion(zero)  

Example of right shift operator :
x = 15
y = x << 2

[x=15 before right shifting ]            0000  0000  0000  1111
[y = x << 2 during right shifting]     0000  0000  0000  111100
[y = x << 2 after right shifting]        0000  0000  0011  1100


so now value of y=60.

One's complement ( ~ ) or Tilde


It is reverse the bit i.e. if bit is 0 then its return 1 and when bit is 1 it is return 0.
example of tilde:
x = 15
y = ~ x

(15)10 = 0000 0000 0000 1111
y = ~ x   1111 1111 1111 0000
hense, 65535 - 15 = 65520.
so the value of y is 65520. 


Read More ->>

Wednesday

Arithmetic Operator

0 comments
Arithmetic Operator
Arithmetic operators are special mathematical symbol which do all arithmetical calculation of the programs. Following table display the operators and their works:
------------------------------------------------------------------------------------
Name of operators    Symbol            works                                     example
----------------------------------------------------------------------------------------
Addition operator         +           Add the numbers                           sum=7+8+1=16
Subtract operator         -            Subtraction of numbers                  sub=100-50=50
Multiply operator         *            Multiple of numbers                        muti=8*9=72
Modulus operator        %          Find the reminder of numbers          mod=45%40=5
Division operator          /           Find the division of numbers             div=45/40=1
Relational operators
-----------------------------------------------------------------------------------------
Read More ->>

What is operators?

0 comments

 What is operators?



In simple word operators are those which operator anything like as data,maths,information etc i.e.. When we talking about C operators, i want to say you that C is very rich in operators. Operators tells to compiler that what do with data.

There are mainly operators in c as following:

    1.Logical Operators
    2.Bitwise Operators
    3.Relational Operators
    4.Assignment Operators
    5.Sizeof Operators
    6.Increment and Decrement operators
    7.Comma operators
    8.Type cast operator
    9.Conditional operators or ternary operators

Read More ->>

Opening Files,Closing a File,Writing a File,Reading a File,5.Binary I/O Functions

0 comments

Files

1.Opening Files

You can use the fopen( ) function to create a new file or to open an existing file, this call will initialize an object of the type FILE, which contains all the information necessary to control the stream. Following is the prototype of this function call:

FILE *fopen( const char * filename, const char * mode );
 
 
Here filename is string literal which you will use to name your file and access mode can have one of the following values:


Mode
  Description
r
Opens an existing text file for reading purpose.
w
Opens a text file for writing, if it does not exist then a new file is created. Here your program will start writing content from the beginning of the file.
a
Opens a text file for writing in appending mode, if it does not exist then a new file is created. Here your program will start appending content in the existing file content.
r+
Opens a text file for reading and writing both.
w+
Opens a text file for reading and writing both. It first truncate the file to zero length if it exists otherwise create the file if it does not exist.
a+
Opens a text file for reading and writing both. It creates the file if it does not exist. The reading will start from the beginning but writing can only be appended.


If you are going to handle binary files then you will use below mentioned access modes instead of the above mentioned:


"rb", "wb", "ab", "ab+", "a+b", "wb+", "w+b", "ab+", "a+b"

2.Closing a File

To close a file, use the fclose( ) function. The prototype of this function is:
 int fclose( FILE *fp );
The fclose( ) function returns zero on success, or EOF if there is an error in closing the file. This function actually, flushes any data still pending in the buffer to the file, closes the file, and releases any memory used for the file. The EOF is a constant defined in the header file stdio.h.
There are various functions provide by C standard library to read and write a file character by character or in the form of a fixed length string. Let us see few of the in the next section.

3.Writing a File

Following is the simplest function to write individual characters to a stream:
int fputc( int c, FILE *fp );
 
 
The function fputc() writes the character value of the argument c to the output stream referenced by fp. It returns the written character written on success otherwise EOF if there is an error. You can use the following functions to write a null-terminated string to a stream:

int fputs( const char *s, FILE *fp );
 
The function fputs() writes the string s to the output stream referenced by fp. It returns a non-negative value on success, otherwise EOF is returned in case of any error. You can use int fprintf(FILE *fp,const char *format, ...) function as well to write a string into a file. Try the following example:
 
#include <stdio.h>
main()
{
   FILE *fp;
 
   fp = fopen("/tmp/test.txt", "w+");
   fprintf(fp, "This is testing for fprintf...\n");
   fputs("This is testing for fputs...\n", fp);
   fclose(fp);
}
 
 
When the above code is compiled and executed, it creates a new file test.txt in /tmp directory and writes two lines using two different functions. Let us read this file in next section.

4.Reading a File

Following is the simplest function to read a single character from a file:
int fgetc( FILE * fp );
 
 
The fgetc() function reads a character from the input file referenced by fp. The return value is the character read, or in case of any error it returns EOF. The following functions allow you to read a string from a stream:
char *fgets( char *buf, int n, FILE *fp );
 
 
The functions fgets() reads up to n - 1 characters from the input stream referenced by fp. It copies the read string into the buffer buf, appending a null character to terminate the string.

If this function encounters a newline character '\n' or the end of the file EOF before they have read the maximum number of characters, then it returns only the characters read up to that point including new line character. You can also use int fscanf(FILE *fp, const char *format, ...) function to read strings from a file but it stops reading after the first space character encounters.


#include <stdio.h>
main()
{
   FILE *fp;
   char buff[100];
 
   fp = fopen("/tmp/test.txt", "r");
   fscanf(fp, "%s", buff);
   printf("1 : %s\n", buff );
 
   fgets(buff, 255, (FILE*)fp);
   printf("2: %s\n", buff );
   
   fgets(buff, 255, (FILE*)fp);
   printf("3: %s\n", buff );
   fclose(fp);
 
}
 
 
When the above code is compiled and executed, it reads the file created in previous section and produces following result:


1 : This
2: is testing for fprintf...
 
3: This is testing for fputs...
 
 
Let's see a little more detail about what happened here. First fscanf() method read just This because after that it encountered a space, second call is for fgets() which read the remaining line till it encountered end of line. Finally last call fgets() read second line completely.

5.Binary I/O Functions

There are following two functions which can be used for binary input and output:


size_t fread(void *ptr, size_t size_of_elements, 
 
             size_t number_of_elements, FILE *a_file);
              
size_t fwrite(const void *ptr, size_t size_of_elements, 
             size_t number_of_elements, FILE *a_file);
  
Both of these functions should be used to read or write blocks of memories - usually arrays or structures.

Read More ->>

malloc(),calloc(),realloc()and free()

0 comments

malloc()

             The malloc()  function dynamically allocates memory when required. This function allocates ‘size’ byte of memory and returns a pointer to the first byte or NULL if there is some kind of error.span>
Format is as follows.

void * malloc (size_t size);

Specifies in bytes the size of the area you want to reserve the argument. It returns the address as the return value of the dynamically allocated area. In addition, returns NULL if it fails to secure the area. The failure to ensure that the situation is usually that is out of memory.

The return type is of type void *, also receive the address of any type. The fact is used as follows.

double * p = (double *) malloc (sizeof (double));

The size of the area using the sizeof operator like this. The return value is of type void *, variable in the receiving side can be the pointer of any type in the host language C language called C + +, the pointer type to other type void * is, without casting, so can not be assigned, Use a cast. In C, a pointer type to void * type from another, so that the cast automatically, there is no need to explicitly cast originally.Of course, should not write because not explicitly given as well as portability to C + +, I wrote better.
In addition, the secured area is unknown at this point that's on it? That is the same as a normal state to declare a local variable. Thus, with reference values ??must not be left without initialization.
          
With this feature, you get a pointer to an allocated block of memory. Its structure is:

code:

pointer = (type) malloc (size in bytes);

An example:code:


int * p;
p = (int *) malloc (sizeof (int));
* p = 5;

First we declare a pointer, which is still pointing nowhere. Then the pointer, not the content but the pointer itself is equal to a pointer type int that contains the memory address space for an int. Sizeof () gets the space it occupies what you want, if you put int in, such as 2 bytes, because we have assigned two bytes. This feature also serves to get the size of pointers, variables, or whatever it takes.
Finally, now that the pointer is contained, we give a value.
For example:
               int *ptr = malloc(sizeof(int) * 10);      // allocates 10 ints!
                 If it is unable to find the requested amount of memory, malloc() function returns NULL. So you should really check the result for errors:
int *ptr = malloc(sizeof(int) * 5000);
if (ptr == NULL)
       {
       printf(" Out of memory!\n");
       exit(1);
       }
                 There are only two ways to get allocated memory back. They are exit from the program and calling free() to free function. If your program runs a while and keeps malloc()ing and never free()ing when it should, it is said to “leak” memory. Make sure to avoid memory leaks! free() that memory when you are done with it!

The following example illustrates the use of  malloc() function.

calloc() function

           

The calloc function is used to allocate storage to a variable while the program is running. This library function is invoked by writing calloc(num,size).This function takes two arguments that specify the number of elements to be reserved, and the size of each element in bytes and it allocates memory block equivalent to num * size . The function returns a pointer to the beginning of the allocated storage area in memory. The important difference between malloc and calloc function is that calloc initializes all bytes in the allocation block to zero and the allocated memory may/may not be contiguous.
calloc function is used to reserve space for dynamic arrays. Has the following form.

void * calloc (size_t n, size_t size);

Number of elements in the first argument specifies the size in bytes of one element to the second argument. A successful partitioning, that address is returned, NULL is returned on failure.
For example, an int array of 10 elements can be allocated as follows.

int * array = (int *) calloc (10, sizeof (int));

Note that this function can also malloc, written as follows.

int * array = (int *) malloc (sizeof (int) * 10);
However, the malloc function, whereas the area reserved to the states that are undefined, the area allocated by the calloc function contains a 0. In fact, the calloc function is internally may be a function that calls malloc. After securing function by malloc, the area is filled with 0.
            

            ptr = malloc(10 * sizeof(int));          
             ptr = calloc(10, sizeof(int));

 realloc()

With the function realloc, you can change the size of the allocated area once. Has the following form.
void * realloc (void * ptr, size_t size);

The first argument specifies the address of an area that is currently allocated to the size in bytes of the modified second argument. Change the size, the return value is returned in re-allocated address space. Otherwise it returns NULL.

Size may be smaller but larger than the original. If you have small, reduced what was written in part will be inaccessible. If you increase the portion of the region will remain an indefinite increase.

The address of the source address changed, but the same could possibly be different, even if the different areas of the old style, because it is automatically released in the function realloc, for the older areas it is not necessary to call the free function. However, if the function fails and returns NULL, realloc, the older area is to remain still valid. Therefore, the first pointer argument of the function realloc, both can be NULL pointer return value is not returned.

# Include
int main (void)
{
int * p1, * p2;
p1 = (int *) calloc (5, sizeof (int)); /* number of elements in an array of type 5 int */
/ * To do something * /
p2 = (int *) realloc (p1, sizeof (int)); * / re-acquire the space of one type / * int
if (p2 == NULL) * / check if successful * /
{
free (p1); if it fails to get re-/ *, the region remains valid since the original * / to free myself
return 0;
}
p1 = NULL; safety measure * /. p1 is realloc () because it is released inside, / * Keep assigning NULL to clear the other can not use / * To do something * /
free (p2);
return 0;
}

The realloc function is a very feature-rich functions. This is not the pros, cons and rather may be better. For example, if a NULL pointer to the first argument passed to the malloc function with the same behavior as the size specified in the second argument. Meanwhile, the second argument to zero, the operation to free the space pointed to by the free function specified in the first argument.

In other words, whatever the arguments, it is the sister supposed to mean something to the result, which may not have to be an error with the error should really be something. In particular, even in very common use, such as the following:

char * p2 = realloc (p1, size);

Happened, if the variable size is zero, this is not the same behavior as the function becomes free. If it is NULL p1, is the handling function malloc. NULL and 0 respectively when and what behavior is undefined.
In addition, the pointer argument to realloc function first must point to a secure area using one of the functions malloc / calloc / realloc (if a NULL pointer may be, in which case the above equal to the malloc function and so on).


Quite complex because, you have put a sample implementation of realloc function to aid understanding.

void * realloc (void * ptr, size_t size)
{
char * p;
if (ptr == NULL)
{
return malloc (size); if the first argument is NULL / * * / function which works the same as malloc }
if (size == 0)
{
free (ptr); second argument is 0 / * * / function which works the same as free
return NULL; * / return NULL because no new areas to be reserved * /
}

p = malloc (size); using the function / * malloc, * / a space equivalent to the size of the newer
if (p == NULL) {return NULL; if the function fails} / * malloc, return NULL. The original area * / remain
memcpy (p, ptr, size); the data in the source area / * * / to be copied to newly allocated space
free (ptr); source area / * the * / to be released
return p; * / return the address of the beginning of a new space * / }
Here are the points you need to remember.

•    The contents of the object will remain unaltered up to the lesser of the new and old sizes.
•    If the new size of the memory object would require movement of the object, the space for the previous 
instantiation of the object is freed.

•    If the new size is larger, the contents of the newly allocated portion of the object are unspecified.
•    If size is zero and ptr isn't a null pointer, the object pointed to is freed.
•    If the space can't be allocated, the object remains unaltered.
•    If ptr is a null pointer, realloc() acts like malloc() for the specified size.

This chapter will explain dynamic memory management in C. The C programming language provides several functions for memory allocation and management. These functions can be found in the <stdlib.h> header file.

Allocating Memory Dynamically

While doing programming, if you are aware about the size of an array, then it is easy and you can define it as an array. For example to store a name of any person, it can go max 100 characters so you can define something as follows:

char name[100];

But now let us consider a situation where you have no idea about the length of the text you need to store, for example you want to store a detailed description about a topic. Here we need to define a pointer to character without defining how much memory is required and later based on requirement we can allocate memory as shown in the below example:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
   char name[100];
   char *description;

   strcpy(name, "Zara Ali");

   /* allocate memory dynamically */
   description = malloc( 200 * sizeof(char) );
   if( description == NULL )
   {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   }
   else
   {
      strcpy( description, "star");
   }
   printf("Name = %s\n", name );
   printf("Description: %s\n", description );
}
When the above code is compiled and executed, it produces the following result.
Same progam can be written using calloc() only thing you need to replace malloc with calloc as follows:
calloc(200, sizeof(char));
So you have complete control and you can pass any size value while allocating memory unlike arrays where once you defined the size can not be changed.

     Resizing and Releasing Memory

When your program comes out, operating system automatically release all the memory allocated by your program but as a good practice when you are not in need of memory anymore then you should release that memory by calling the function free().

Alternatively, you can increase or decrease the size of an allocated memory block by calling the function realloc(). Let us check the above program once again and make use of realloc() and free() functions:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
   char name[100];
   char *description;

   strcpy(name, "Zara Ali");

   /* allocate memory dynamically */
   description = malloc( 30 * sizeof(char) );
   if( description == NULL )
   {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   }
   else
   {
      strcpy( description, "Zara ali a DPS student.");
   }
   /* suppose you want to store bigger description */
   description = realloc( description, 100 * sizeof(char) );
   if( description == NULL )
   {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   }
   else
   {
      strcat( description, "She is in class 10th");
   }
  
   printf("Name = %s\n", name );
   printf("Description: %s\n", description );

   /* release memory using free() function */
   free(description);
}
Read More ->>

Dynamic memory allocation

0 comments

Dynamic memory allocation 


Dynamic memory allocation is the practice of assigning memory locations to variables during execution of the program by explicit request of the programmer. Dynamic allocation is a unique feature to C (amongst high level languages). It enables us to create data types and structures of any size and length to suit our programs need within the program.

                 For example, to use arrays, dynamic memory allocation and use, eliminating the need to determine the size of the array at declaration time. What do I say it is that extra space does not have to. Areas that could use up to 1000 minutes, but you know, actually do not know how much is used, the worst case, might well end up without one. In such cases, to specify precisely the number of elements in the declaration is a very difficult time. If too much waste of memory, and the less accessible outside of the array, may result in an error.

                 Dynamically allocated memory is freed when finished should not be used without. When released, this area no longer use that system to manage memory (OS) and I'll tell it to. When you exit the program without a release, essentially freed automatically. But I say with certainty, it should be freed by calling a dedicated function explicitly.

                 Finally, the dynamically allocated memory area, the area is secured in a location different from the usual definition of a variable. There is also the name depending on the role of memory space and just go. Used in the dynamic memory allocation area is called the heap. In contrast, the variables are usually allocated to the location of the stack. Variables are allocated on the heap, even if it was secured out of the scope, continues to exist. For example, in function, if you create a dynamic variable, but missing out the function and will continue to exist on the heap.

                  The functions malloc (), realloc (), calloc () and free (), the Library functions stdlib.h, malloc.h or are responsible for this task. All data are stored in the free store (heap), which is limited to 64k a stack in the beginning, this varies from machine. All variables were declared so far on the stack, now you tell me where to go, in an indirect way.

                 The following functions are used in c for purpose of memory management.

 
Read More ->>

void pointer

0 comments

Define void pointer.

A void pointer is pointer which has no specified data type. The keyword ‘void’ is preceded the pointer variable, because the data type is not specific. It is also known as a generic pointer. The void pointer can be pointed to any type. If needed, the type can be casted.
Ex: float *float_pointer;
int *int_pointer;
void *void_pointer;
. . . . . . . .
. . . . . . . .
void_pointer = float_pointer;
. . . . . . . .
. . . . . . . .
void_pointer = int_pointer;
A void pointer is generally used as function parameters, when the parameter or return type is unknown.   
Read More ->>

Callback Functions Tutorial

0 comments

Callback Functions Tutorial


If you are reading this article, you probably wonder what callback functions are. This article explains what callback functions are, what are they good for, why you should use them, and so forth. However, before learning what callback functions are, you must be familiar with function pointers. If you aren't, consult a C/C++ book or consider reading the following:

What Is a Callback Function?

The simple answer to this first question is that a callback function is a function that is called through a function pointer. If you pass the pointer (address) of a function as an argument to another, when that pointer is used to call the function it points to it is said that a call back is made.

Why Should You Use Callback Functions?

Because they uncouple the caller from the callee. The caller doesn't care who the callee is; all it knows is that there is a callee with a certain prototype and probably some restriction (for instance, the returned value can be int, but certain values have certain meanings).
If you are wondering how is that useful in practice, imagine that you want to write a library that provides implementation for sorting algorithms (yes, that is pretty classic), such as bubble sort, shell short, shake sort, quick sort, and others. The catch is that you don't want to embed the sorting logic (which of two elements goes first in an array) into your functions, making your library more general to use. You want the client to be responsible to that kind of logic. Or, you want it to be used for various data types (ints, floats, strings, and so on). So, how do you do it? You use function pointers and make callbacks.
A callback can be used for notifications. For instance, you need to set a timer in your application. Each time the timer expires, your application must be notified. But, the implementer of the time'rs mechanism doesn't know anything about your application. It only wants a pointer to a function with a given prototype, and in using that pointer it makes a callback, notifying your application about the event that has occurred. Indeed, the SetTimer() WinAPI uses a callback function to notify that the timer has expired (and, in case there is no callback function provided, it posts a message to the application's queue).
Another example from WinAPI functions that use callback mechanism is EnumWindow(), which enumerates all the top-level windows on the screen. EnumWindow() iterates over the top-level windows, calling an application-provided function for each window, passing the handler of the window. If the callee returns a value, the iteration continues; otherwise, it stops. EnumWindows() just doesn't care where the callee is and what it does with the handler it passes over. It is only interested in the return value, because based on that it continues its execution or not.
However, callback functions are inherited from C. Thus, in C++, they should be only used for interfacing C code and existing callback interfaces. Except for these situations, you should use virtual methods or functors, not callback functions.

A Simple Implementation Example

Now, follow the example that can be found in the attached files. I have created a dynamic linked library called sort.dll. It exports a type called CompareFunction:
  1. typedef int (__stdcall *CompareFunction)(const byte*, const byte*);
which will be the type of your callback functions. It also exports two methods, called Bubblesort() and Quicksort(), which have the same prototype but provide different behavior by implementing the sorting algorithms with the same name.
  1. void DLLDIR __stdcall Bubblesort(byte* array,
  2. int size,
  3. int elem_size,
  4. CompareFunction cmpFunc);
  5.  
  6. void DLLDIR __stdcall Quicksort(byte* array,
  7. int size,
  8. int elem_size,
  9. CompareFunction cmpFunc);
These two functions take the following parameters:
  • byte* array: a pointer to an array of elements (doesn't matter of which type)
  • int size: the number of elements in the array
  • int elem_size: the size, in bytes, of an element of the array
  • CompareFunction cmpFunc: a pointer to a callback function with the prototype listed above
The implementation of these two functions performs a sorting of the array. But, each time there is a need to decide which of two elements goes first, a callback is made to the function whose address was passed as an argument. For the library writer, it doesn't matter where that function is implemented, or how it is implemented. All that matters it is that it takes the address of two elements (that are the two be compared) and it returns one of the following values (this is a contract between the library developers and its clients):
  • -1: if the first element is lesser and/or should go before the second element (in a sorted array)
  • 0: if the two elements are equal and/or their relative position doesn't matter (each one can go before the other in a sorted array)
  • 1: if the first element is greater and/or should go after the second element (in a sorted array)
With this contract explicitly stated, the implementation of the Bubblesort() function is this (for Quicksort(), which a little bit more complicated, see the attached files).
  1. void DLLDIR __stdcall Bubblesort(byte* array,
  2. int size,
  3. int elem_size,
  4. CompareFunction cmpFunc)
  5. {
  6. for(int i=0; i < size; i++)
  7. {
  8. for(int j=0; j < size-1; j++)
  9. {
  10. // make the callback to the comparison function
  11. if(1 == (*cmpFunc)(array+j*elem_size,
  12. array+(j+1)*elem_size))
  13. {
  14. // the two compared elements must be interchanged
  15. byte* temp = new byte[elem_size];
  16. memcpy(temp, array+j*elem_size, elem_size);
  17. memcpy(array+j*elem_size,
  18. array+(j+1)*elem_size,
  19. elem_size);
  20. memcpy(array+(j+1)*elem_size, temp, elem_size);
  21. delete [] temp;
  22. }
  23. }
  24. }
  25. }
Note: Because the implementation uses memcpy(), these library functions should not be used for types other than POD (Plain-Old-Data).
On the client side, there must be a callback function whose address is to be passed to the Bubblesort() function. As a simple example, I have written a function that compares two integer values and one that compares two strings:
  1. int __stdcall CompareInts(const byte* velem1, const byte* velem2)
  2. {
  3. int elem1 = *(int*)velem1;
  4. int elem2 = *(int*)velem2;
  5.  
  6. if(elem1 < elem2)
  7. return -1;
  8. if(elem1 > elem2)
  9. return 1;
  10.  
  11. return 0;
  12. }
  13.  
  14. int __stdcall CompareStrings(const byte* velem1, const byte* velem2)
  15. {
  16. const char* elem1 = (char*)velem1;
  17. const char* elem2 = (char*)velem2;
  18.  
  19. return strcmp(elem1, elem2);
  20. }
To put all these to a test, I have written this short program. It passes an array with five elements to Bubblesort() or Quicksort() along with the pointer to the callback functions.
  1. int main(int argc, char* argv[])
  2. {
  3. int i;
  4. int array[] = {5432, 4321, 3210, 2109, 1098};
  5.  
  6. cout << "Before sorting ints with Bubblesort\n";
  7. for(i=0; i < 5; i++)
  8. cout << array[i] << '\n';
  9.  
  10. Bubblesort((byte*)array, 5, sizeof(array[0]), &CompareInts);
  11.  
  12. cout << "After the sorting\n";
  13. for(i=0; i < 5; i++)
  14. cout << array[i] << '\n';
  15.  
  16. const char str[5][10] = {"estella",
  17. "danielle",
  18. "crissy",
  19. "bo",
  20. "angie"};
  21.  
  22. cout << "Before sorting strings with Quicksort\n";
  23. for(i=0; i < 5; i++)
  24. cout << str[i] << '\n';
  25.  
  26. Quicksort((byte*)str, 5, 10, &CompareStrings);
  27.  
  28. cout << "After the sorting\n";
  29. for(i=0; i < 5; i++)
  30. cout << str[i] << '\n';
  31.  
  32. return 0;
  33. }
If I decide that I want the sorting to be done descending (with the biggest element first), all I have to do is to change the callback function code, or provide another that implements the desired logic.

Calling Conventions

In the above code, you can see the word __stdcall in the function's prototype. Because it starts with a double underscore, it is, of course, a compiler-specific extension, more exactly a Microsoft-specific one. Any compiler that supports development of Win32-based applications must support this or an equivalent one. A function that is marked with __stdcall uses the standard calling convention so named because all Win32 API functions (except the few that take variable arguments) use it. Functions that follow the standard calling convention remove the parameters from the stack before they return to the caller. This is the standard convention for Pascal. But in C/C++, the calling convention is that the caller cleans up the stack instead of the called function. To enforce that a function uses the C/C++ calling convention, __cdecl must be used. Variable argument functions use the C/C++ calling convention.
Windows adopted the standard calling convention (Pascal convention) because it reduces the size of the code. This was very important in the early days of Windows, when it ran on systems with 640 KB RAM.
If you don't like the word __stdcall, you can use the CALLBACK macro, defined in windef.h, as
  1. #define CALLBACK __stdcall
or
  1. #define CALLBACK PASCAL
where PASCAL is #defined as __stdcall.


Read More ->>
 

| C programing tutorials © 2009. All Rights Reserved | Template Style by My Blogger Tricks .com | Design by Brian Gardner | Back To Top |