|< C Run-Time 3 | Main | C & Win32 Programming 1 >| Site Index | Download |












What are in this Module?

  1. A Simple Searching and Sorting

  2. Searching and Sorting Functions

  3. Time

  4. Some Error Handling

  5. A pseudocode and a very long program example

















My Training Period: pp hours. Before you begin, read some instruction here. Functions and structure used in the program examples were dumped at Win32 functions & structures.


The Win32 programming abilities:

  • Able to recognize the standard and implementation specific C.

  • Able to find and collect the required and related information in order to use functions to accomplish your tasks.

  • Able to understand and use functions that available in the libraries in your own programs.

A Simple Searching and Sorting

  • The following functions used for searching and sorting.  It is very limited and basic :o).

Searching and Sorting Functions



Search or Sort


Binary search.


Linear search for given value.


Linear search for given value, which is added to array if not found.


Quick sort.


Table 12:  Search and sort functions.

  • The following Table is an example of the needed information in order to use the bsearch() function.



The function


The use

Performs a binary search of a sorted array.

The prototype

void *bsearch( const void *key, const void *base, size_t num, size_t width,
int (__cdecl *compare) (const void *, const void *));


int compare(char **arg1, char *arg2[ ]);

char *key = "red";

bsearch((char *) &key, (char *)argv, argc, sizeof(char *), (int (*)(const void*, const void*))compare);

The parameters

key - Object to search for.

base - Pointer to base of search data.

num - Number of elements.

width - Width of elements.

compare - Callback function that compares two elements. The first is a pointer to the key for the search and the second is a pointer to the array element to be compared with the key.

The return value

Returns a pointer to an occurrence of key in the array pointed to by base. If key is not found, the function returns NULL.  If the array is not in ascending sort order or contains duplicate records with identical keys, the result is unpredictable.

The header files

<stdlib.h> and <search.h>


Table 13:  bsearch() function information.



Value returned by compare routine


< 0

element1 less than element2


element1 equal to element2

> 0

element1 greater than element2

/*****program example using bsearch()*****/

/*****If it is C++, better to use STL****/

#include <search.h>

#include <string.h>

#include <stdio.h>


/* a compare function prototype */

int compare(char **arg1, char *arg2[ ]);


int main(int argc, char *argv[ ])


   char **result;

   char *key = "red";

   int i;


  if(argc == 1)


    printf("Usage: %s <some strings> \n", argv[0]);

    printf("Example: %s blue yellow red black white\n", argv[0]);



   /* sort using qsort algorithm */

   qsort((void *)argv, (size_t)argc, sizeof(char *), (int (*)(const void*, const void*))compare);

    /* output the sorted list */

   for(i = 0; i < argc; ++i)

   printf("%s ", argv[i]);

    /* find the word "cat" using a binary search algorithm */

   result = (char **)bsearch((char *) &key, (char *)argv, argc, sizeof(char *), (int (*)(const void*, const void*))compare);


   printf("\n\'%s\' word found at address: %p\n", *result, result);


      printf("\n\'%s\' word not found!\n", *result);

   return 0;



int compare(char *arg1[ ], char *arg2[ ])


   /* compare all of both strings */

   return _strcmpi(*arg1, *arg2);


The output:


G:\vcnetprojek\mcruntime\Debug>mcruntime blue yellow red black white

black blue mcruntime red white yellow

'red' word found at address: 00320CF4



Time Functions



The Use

asctime(), _wasctime()

Convert time from type struct tm to character string.


Return elapsed CPU time for process.

ctime(), _ctime64(), _wctime(), _wctime64()

Convert time from type time_t or __time64_t to character string.


Compute difference between two times.

_ftime(), _ftime64()

Store current system time in variable of type struct _timeb or type struct __timeb64.

_futime(), _futime64()

Set modification time on open file.

gmtime(), _gmtime64()

Convert time from type time_t to struct tm or from type __time64_t to struct tm.

localtime(), _localtime64()

Convert time from type time_t to struct tm or from type __time64_t to struct tm with local correction.

mktime(), _mktime64()

Convert time to calendar value.

_strdate(), _wstrdate()

Return current system date as string.

strftime(), wcsftime()

Format date-and-time string for international use.

_strtime(), _wstrtime()

Return current system time as string.

time(), _time64()

Get current system time as type time_t or as type __time64_t.


Set external time variables from environment time variable, TZ.

_utime(), _utime64(), _wutime(), _wutime64()

Set modification time for specified file using either current time or time value stored in structure.


Table 14:  Time management functions.



The function

time(), _time64().

The use

Get the system time.

The prototype

time_t time(time_t *timer);

__time64_t _time64(__time64_t *timer);

The parameters

timer – Is a pointer to the storage location for time.


__time64_t lgtime;



The return value

Return the time in elapsed seconds.  There is no error return.

A call to time() or _time64() can fail, however, if the date passed to the function is:

  • Before midnight, January 1, 1970.

  • After 19:14:07, January 18, 2038, UTC (using time and time_t structure).

  • After 23:59:59, December 31, 3000, UTC (using _time64 and __time64_t structure).

The header files



Table 15:  time(), _time64() functions information.

/* playing with time. Program example for time management functions...*/

#include <time.h>

#include <stdio.h>

#include <sys/types.h>

#include <sys/timeb.h>

#include <string.h>


int main()


    char buff[128], ampm[ ] = "AM";

    __time64_t lgtime;

    struct __timeb64 timstruct;

    struct tm *today, *thegmt, xmas = {0, 0, 12, 25, 11, 90};

    /* set time zone from TZ environment variable. If TZ is not set,

     * the operating system is queried to obtain the default value

     * for the variable.*/


    /* get UNIX-style time and display as number and string. */


    printf("Time in seconds since UTC 1/1/70:\t%ld seconds\n", lgtime);

    printf("UNIX time and date:\t\t\t%s", _ctime64(&lgtime));

    /* display UTC. */

    thegmt = _gmtime64(&lgtime);

    printf("Coordinated universal time, UTC:\t%s", asctime(thegmt));

    /* display operating system-style date and time. */


    printf("OS time:\t\t\t\t%s\n", buff);


    printf("OS date:\t\t\t\t%s\n", buff);

    /* convert to time structure and adjust for PM if necessary. */

    today = _localtime64(&lgtime);

    if(today->tm_hour >= 12)


       strcpy(ampm, "PM");

       today->tm_hour -= 12;


    /* adjust if midnight hour. */

     if(today->tm_hour == 0)

        today->tm_hour = 12;

    /* pointer addition is used to skip the first 11

     * characters and printf() is used to trim off terminating

     * characters.*/

    printf("12-hour time:\t\t\t\t%.8s %s\n", asctime(today) + 11, ampm);

    /* print additional time information. */


    printf("Plus milliseconds:\t\t\t%u\n", timstruct.millitm);

    printf("Zone difference in hours from UTC:\t%u hours\n", timstruct.timezone/60);

    printf("Time zone name:\t\t\t\t%s\n", _tzname[0]);

    printf("Daylight savings:\t\t\t%s\n", timstruct.dstflag ? "YES" : "NOT SET");

    /* make time for noon on Christmas, 1990. */

    if(_mktime64(&xmas) != (__time64_t)-1)

      printf("Christmas\t\t\t\t%s", asctime(&xmas));

    /* use time structure to build a customized time string. */

    today = _localtime64(&lgtime);

     /* use strftime to build a customized time string. */

    strftime(buff, 128, "Today is %A, day %d of %B in the year %Y.\n", today);


    return 0;


The output:


Time in seconds since UTC 1/1/70:       1116770651 seconds

UNIX time and date:                     Sun May 22 23:34:11 2005

Coordinated universal time, UTC:        Sun May 22 14:04:11 2005

OS time:                                23:34:11

OS date:                                05/22/05

12-hour time:                           11:34:11 PM

Plus milliseconds:                      453

Zone difference in hours from UTC:      4294967287 hours

Time zone name:                         AUS Central Standard Time

Daylight savings:                       NOT SET

Christmas                               Tue Dec 25 12:00:00 1990

Today is Sunday, day 22 of May in the year 2005.

Press any key to continue

Some Error Handling



The function


The use

Print an error message.

The prototype

void perror( const char *string );

/* for wide character */

void _wperror( const wchar_t *string );

The parameters

string - String message to print.


perror("Using perror()");

The return value


The header files

<stdio.h> or <wchar.h> (for _wperror()).


Table 16:  perror() function information.


System error message



Argument list too long



Permission denied



No more processes or not enough memory or maximum nesting level reached



Bad file number



No spawned processes



Resource deadlock would occur



Math argument



File exists



Invalid argument



Too many open files



No such file or directory



Exec format error



Not enough memory



No space left on device



Result too large



Cross-device link



Table 17:  errno values.



The function

strerror(), _strerror(), _wcserror(), __wcserror().

The use

Get a system error message (strerror(), _wcserror()) or prints a user-supplied error message (_strerror(), __wcserror()).

The prototype

char *strerror(int errnum);

char *_strerror(const char *strErrMsg);

wchar_t * _wcserror(int errnum);

wchar_t * __wcserror(const wchar_t *strErrMsg);

The parameters

errnum - Error number.

strErrMsg - User-supplied message.



The return value

All these functions return a pointer to the error-message string.  Subsequent calls can overwrite the string.

The header files



Table 18:  strerror() family functions information.

if((_access("thefile.dat", 13)) == -1)

   fprintf(stderr, strerror(NULL));

#include <fcntl.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <io.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>


int main()


   char fname[20] = "testnofile.txt";

   int  fhndl;

   /* try to open non-existing file */

   if((fhndl = _open(fname, _O_RDONLY)) == -1)


      /* using the possible ways to create error message */

      perror("Using perror()");

      printf("Using strerror(): %s\n", strerror(errno));


      printf("There is some error opening %s file\n", fname);




      printf("Open %s for reading succeeded!\n", fname);



   return 0;



A sample output:

Using perror(): No such file or directory

Using strerror(): No such file or directory

_strerror(): No such file or directory

There is some error opening testnofile.txt file

Press any key to continue


-------------------------------------Pre End----------------------------------------

Some silly thought:  The pseudo code/algorithm


Receive the filename as a command line argument, store it somewhere

First of all get all the available drives in the machine, use _getdrives()

   Translate all the bitmask to the respective drive.

For every found drive search the file, call user defined FindThePath()

       Strip the filename string, call the user defined TheRightSide()

       Test the filename string, call the user defined TestTheStrings()

               Test the wildcards/extensions if any

        If it is a directory, it is current working or parent directory (. and ..)?

        If it is a valid root/drive, search in the current root

        If not found, construct a path to traverse to other directories in finding the file

                      Recurse, call FindThePath()

         If found, construct the full path and display it/return.


                    Optionally, implement other routines or function calls for the found file.


          If finish, no more files, no more directories in current drive, return to the main program's 


Repeat for other drives


Then, comes the silly program:

/*****  mysearch.cpp  *********/

/* compiled using VC++ 7.0/.Net, run at command prompt, tested on Win Xp Pro machine */

#include <windows.h>

#include <direct.h>

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <ctype.h>

#include <io.h>

#include <tchar.h>


/* prototype for recursive function */

void FindThePath(TCHAR*, TCHAR*, TCHAR*);


/* filename stripping */

static void TheRightside(TCHAR *str, size_t num)


      size_t i = _tcslen(str);

       size_t chs = 0, chr = 0;

       /* may use malloc() */

       TCHAR *hld = new TCHAR[num+1];

       if((i > num) || (i == num))


              for(chs = (i-num); chs<i; chs++)


                     hld[chr] = str[chs];



              hld[num] = '\0';

              for(chs = 0; chs < (num+1); chs++)


                     str[chs] = hld[chs];



       /* don't forget to free() up if using malloc() */

       delete [ ] hld;


/* test the searched string/filename */

static bool TestTheStrings(TCHAR *str1, TCHAR *str2)


       char *mp,*cp;

       size_t x1 = 0;

       bool ret = true;


       x1 = _tcslen(str1);

       if(_tcslen(str2) != (unsigned)x1)

       {ret = false;}



              for(size_t i=0; i<x1; i++)


                     if(str1[i] != str2[i])

                           ret = false;




       while ((*str2) && (*str1 != '*'))


     if((*str1 != *str2) && (*str1 != '?'))

        {return 0;}




    while (*str2)


    if(*str1 == '*')



       {return 1;}

      mp = str1;

      cp = str2+1;


       else if ((*str1 == *str2) || (*str1 == '?'))







      str1 = mp;

      str2 = cp++;



   while (*str1 == '*')


    return !*str1;

       return ret;


/* search and construct the path */

void FindThePath(TCHAR *root, TCHAR *file, TCHAR *buffer)


       HANDLE     hFind;

       BOOL        ok;

       WIN32_FIND_DATA   fd;


       TCHAR start[_MAX_PATH];

       TCHAR dir[_MAX_PATH];

       /* search flag */

       bool found = false;


       TCHAR test[_MAX_PATH];

       /* using test as a temp location */

       _tcscpy(test, buffer);

       /* get the length of the file name */

       size_t tlen = _tcslen(file);

       /* strip off possible filename if it is in the buffer */

       TheRightside(test, tlen);

       /* test for it */

       if(TestTheStrings(test, file))

       /* return if it is there...no need to look further */



       /* if they passed a valid string for the root */

       if(_tcslen(root) > 0)


              /* modify it to search for all files/folders.... */

              _tcscpy(start, root);

              _tcscat(start, "\\*");



for(hFind = FindFirstFile(start, &fd), ok = 1;

       hFind != INVALID_HANDLE_VALUE && ok;

       ok = FindNextFile(hFind, &fd))


// bitwise AND to test the returned fileattributes

if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)


/* assuming it is a dir so copy over */

_tcscpy(dir, fd.cFileName);

/* make sure it is not the default parent directory...*/

if((TestTheStrings(dir, ".") == false))


/* or current working directory, copying this over results in infinite recursion */

if((TestTheStrings(dir, "..") == false))


if(found == false)

/* if we have not found the file in this current call, then make a call */


/* constructs the path or you can try the _fullpath() */

_tcscpy(test, root);

_tcscat(test, "\\");

_tcscat(test, dir);


/*and recurse through them.....*/

FindThePath(test, file, buffer);

}/* end found */

}/* end .. test */

}/* end . test */

}/* end dir test */


/* bitwise AND to check for file flag */



/* if we have a file is it the one we want? */

found = TestTheStrings(file, fd.cFileName);

if(found == true)


/* if it is, then create the full path name for it and copy into the buffer */

_tcscpy(buffer, root);

_tcscat(buffer, "\\");

_tcscat(buffer, fd.cFileName);

printf("%s\n", buffer);



/* other routines can be implemented/called here for the found files */

/* such as delete, rename, replace, search the file contents,       */

/* move, append, create a file, change the file attributes etc...   */



}/* end found test */

}/* end archive test */

}/* end for */


    /* 18 = ERROR_NO_MORE_FILES, that is if other than no more files... */

    /* Check the error if any */

       if(GetLastError() != 18)

           printf("FindFile() error: %d\n", GetLastError());

       if(hFind != INVALID_HANDLE_VALUE)


           BOOL ok = FindClose(hFind);


               /* check the last error if any, very good for troubleshooting/debug */ 

               printf("FindClose() error: %d", GetLastError());




/* the main() program */

int main(int argc, char *argv[ ])


    TCHAR buffer[_MAX_PATH];

    TCHAR mydrives[ ] = "A:";


       /* if not enough arguments supplied */

       if(argc != 2)


       printf("Example usage: %s <test.txt> or <test.*> or <*.txt> or <*.*>\n", argv[0]);

       printf("It is case sensitive!\n");

       /* just exit */

       exit (-1);



   /*Some prompt*/

   printf("Example usage: %s <test.txt> or <test.*> or <*.txt> or <*.*>\n", argv[0]);

   printf("It is case sensitive!\n\n");


   /* get the drives bit masks...1 is available, 0 is not available */

   /* A = least significant bit... */

   ULONG DriveMask = _getdrives();

   /* if something wrong */

   if(DriveMask == 0)

      printf("_getdrives() failed with failure code: %d\n", GetLastError());



               printf("Found %s and start digging...\n", mydrives);

               if(DriveMask & 1)


                  /* for every found drive...do the file search */

                  FindThePath(mydrives, argv[1], buffer);

            /* pointer increment */


         /* shift the bit masks binary to the right and repeat, means go to the next found drive */

         DriveMask >>= 1;


   return 0;


A sample output:



Example usage: mysearch <test.txt> or <test.*> or <*.txt> or <*.*>

It is case sensitive!


G:\vcnetprojek\win32prog\Debug>mysearch *.txt

Example usage: mysearch <test.txt> or <test.*> or <*.txt> or <*.*>

It is case sensitive!


Found A: and start digging...

A:FindFile() error: 21

Found B: and start digging...

FindFile() error: 3

Found C: and start digging...

















[Has been trimmed]














Further reading and digging:


  1. Check the best selling C, C++ and Windows books at Amazon.com.

  2. Microsoft Visual C++, online MSDN.

  3. For Multibytes, Unicode characters and Localization please refer to Locale, Wide Character & Unicode (Story) and Windows Users & Groups tutorial (Implementation).

  4. Notation used in MSDN is Hungarian Notation instead of CamelCase and is discussed in C & C++ Notations.







|< C Run-Time 3 | Main | C & Win32 Programming 1 >| Site Index | Download |

Some Old Part of the C-Run Time: Part 1 | Part 2 | Part 3 | Part 4


C & C++ Programming Tutorial | C Programming Practice