Thread: Help problem with bsearch trashing values?

  1. #1
    Registered User
    Join Date
    Feb 2011
    Posts
    96

    Help problem with bsearch trashing values?

    I'm trying to develop a key value pair search tool using bsearch.
    I'm not really a C programmer, I'm more used to C# but its bsearch function is *much* slower.

    When I load the values into DB they display (printf) correctly.
    When I do the actual comparison it doesn't return the value.

    So, for debugging I'm printing the key & the value when I load it from the file. The value looks right.
    In the bsearch comparison function I print the key and the value.
    In this case the Key is fine but the Value looks like foreign characters. The file is in ANSI.
    When I try to retrieve the value bsearch, though it found the key (and very quickly) it will not return the value.

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/time.h>
    #include "SLSKeyValueFinder.h"
    
    typedef struct db {
      char  *sKey;
      char  *sValue; 
      int	Idx;
    } db_st;
    
    char *stringDup ( const char *s ) {
      char *p = malloc( strlen(s) + 1);
      if ( p ) {
        strcpy(p,s);
      }
      return p;
    }
    
    db_st parseLine ( char *line ) {
      db_st result = { "","" };
      {
        int i=0;
    	char *token[2];
    	token[0] = NULL;
    	token[1] = NULL;
    	
    	char *p = strchr(line,'\n');
        if ( p ) *p = '\0';             // remove the \n
        p = strchr(line,'\r');
        if ( p ) *p = '\0';             // remove the \n	
    	
    	//Get Key & Value in Master list
    	char delims[] = "|";
    	char *tokResult = NULL;
    	tokResult = strtok( line, delims );
    	while( tokResult != NULL ) 
    	{
    		token[i] = tokResult;
    		tokResult = strtok( NULL, delims );		
    		i++;
    	}	
    	if(token[0] != NULL)
    	{
    		result.sKey = stringDup(token[0]);
    		if(token[1] != NULL && strlen(token[1]) > 0)
    		{
    			result.sValue = token[1];			
    		}
    		else
    		{
    			result.sValue = "";
    		}		
    	}
    	else
    	{	
    		result.sKey = stringDup(line);
    		result.sValue = "";
    	}	
      }  
    
      return result;
    }
    
    db_st *readFile ( const char *filename, int *nRecords ) {
    	db_st     *result = NULL;
    	int       numRecords = 0;
    	int       maxRecords = 0;
    	int		  curIdx = -1;
    	char      buff[BUFSIZ];
    	FILE     *fp = fopen(filename,"r");
    	if ( fp != NULL ) 
    	{
    		while ( fgets(buff, sizeof buff, fp) != NULL ) 
    		{
    			curIdx++;
    			if(strlen(buff) == 0) continue;
    			
    			if ( numRecords == maxRecords ) 
    			{
    				int newMax = maxRecords == 0 ? 16 : maxRecords * 2;
    				db_st *p = realloc( result, newMax * sizeof(*p));
    				if ( p != NULL ) 
    				{
    					result = p;
    					maxRecords = newMax;
    				} 
    				else 
    				{
    					break;
    				}
    			}
    			
    			db_st r = parseLine(buff);			
    			result[numRecords].sKey = r.sKey;
    			result[numRecords].sValue = r.sValue;
    			result[numRecords].Idx = curIdx;
    			printf("%s %s \n", result[numRecords].sKey, result[numRecords].sValue);
    			numRecords++;
    		}
    		*nRecords = numRecords;
    		fclose(fp);
    	}
    	
    	return result;
    }
    
    int ckValueFromKey ( const void *sKey, const void *DB ) {
      const char *pKey = sKey;
      const db_st *pDB = DB; 
      printf("%s - %s \n", pKey, pDB->sValue);
      return strcmp( pKey, pDB->sKey );
    }
    
    db_st	*dGlblList = NULL;
    int 	nGlblList;
    
    void freedb ( db_st *db, int numRecords ) {
      for ( int i = 0 ; i < numRecords ; i++ ) {	
    	db[i].Idx = 0;
        free( db[i].sKey );
        free( db[i].sValue );
      }
      free( db );
    }
    
    int sortfn ( const void *a, const void *b ) {
      const db_st *pa = a;
      const db_st *pb = b; 
      return strcmp( pa->sKey, pb->sKey );
    }
    
    int main(int argc, char *argv[])
    {
    	static char* sRsltVal;
    	
    	char *ListFilePath = "XRKeyVal.txt";
    	char *sKey = argv[1];
    	
    	if(dGlblList == NULL)
    	{
    		dGlblList = readFile(ListFilePath, &nGlblList);		
    		qsort( dGlblList, nGlblList, sizeof(*dGlblList), sortfn );
    	}
    	printf("Count: %d\n",  nGlblList);
    	
    	db_st *f = bsearch(sKey, dGlblList, nGlblList, sizeof(*dGlblList), ckValueFromKey);
    	if ( f ) 
    	{
    		 sRsltVal = (*f).sValue;		
    		 printf("Value Found: %s",  sRsltVal);
    	}
    	//printf("Value: %s",  sRsltVal);
    	
    	freedb( dGlblList, nGlblList );
    	dGlblList = NULL;
    	nGlblList = 0;
    	
    	return 0;
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > while( tokResult != NULL )
    This needs to be
    while( i < 2 && tokResult != NULL )
    otherwise unexpected numbers of tokens will cause array overrun.

    > result.sValue = token[1];
    You dup() token[0], but this is just a pointer to someone else's local buffer (which goes out of scope)
    It will also screw you up when you try to free it.

    > result.sValue = "";
    Ditto on the freeing
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Feb 2011
    Posts
    96
    Thanks Salem. You and someone else helped me get the original version of this written, I think about a year ago.
    I'm confused.
    The file contains | delimited lines like this:
    postpoll|Empty:::String
    location[postal_code]|143090
    fio|REALNAME

    I don't see how token could ever end up with more than 2.

    I thought the idea of stringDup was to malloc the var so that it would be available outside the scope of the parser. No?
    Also, it's returning sKey just fine. bsearch is finding it with no problem.
    It's sValue that I'm getting wrong.

    I tried adding the i < 2 but it's still returning gibberish in the ckValueFromKey function.

    I changed result.sValue = "" to result.sValue = "Empty:::String" which was what I really wanted anyway.
    Can I do that? Will that help with the freeing?

    Ah, I just found it. I was NOT duping token[1].
    I just changed the code to result.sValue = stringDup(token[1]);
    It's returning sValue correctly now.

    Will that work OK? or should I still expect memory leakage?

  4. #4
    Registered User
    Join Date
    Feb 2011
    Posts
    96
    I had it working but only if it found the Key and I had to change a few other things to make sure I could free the memory.
    First:
    Code:
    result.sValue = "Empty:::String"
    needed to be changed to
    Code:
    result.sValue = stringDup("Empty:::String")
    Second - in main I did not initialize sRsltVal
    If Key was not found then sRsltVal was never set to anything so I couldn't return it.

    Thanks Salem, for helping me with the initial code and now for helping me spot my problem with this version.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Does bsearch ever miss?
    By MAtkins in forum C Programming
    Replies: 4
    Last Post: 02-17-2011, 09:10 AM
  2. bsearch problem
    By hawaiian robots in forum C Programming
    Replies: 5
    Last Post: 04-06-2010, 10:19 AM
  3. bsearch( ) and qsort( ) not agreeing
    By Thumper333 in forum C Programming
    Replies: 1
    Last Post: 10-24-2004, 09:56 PM
  4. Problem Using bsearch
    By Zildjian in forum C Programming
    Replies: 4
    Last Post: 11-13-2003, 08:14 PM
  5. bsearch
    By Kev2 in forum C Programming
    Replies: 4
    Last Post: 05-18-2002, 08:56 PM