Hi all.

As a part of my project I need to get the address book information saved in a .txt file into a Binary Search Tree.

The info in the address book is stored like the following:

First Name, Last Name, Date of Birth, E-mail, Phone, Address, City, Zipcode

So far I coded this:

do {
    fgets(temp, 160, pFile);
		
    sscanf(temp, "%s %s %s %s %s %s %s %s", newContact.first_name, newContact.last_name, newContact.date_of_birth, newContact.e_mail, newContact.phone, newContact.address, newContact.city, newContact.zipcode);
		
    node = insert(newContact, node);
} while ( fgets(temp, 160, pFile) != NULL );

It's just the code to retrieve the information as you can see. The rest of the necessary codes are in their place. Since it's huge project I used lots of header files & I can't display all of it. But know that the file is ready to process. I just need to figure out this retrieve code.

Thanks a lot.

Recommended Answers

All 16 Replies

Are you sure that for example Address never has ' ' in it? See for example http://www.crasseux.com/books/ctutorial/sscanf.html how to allocate memory while reading in file and do error check. Notice that arguments of sscanf must be pointers.

Ok, I got that thing with the Address field tonyjv. Good advice. Thanks a lot.

About the pointer thing. I'm inserting the info to a BST. Tried the arguments as pointers and I got an error. So they should not be pointers.

But more than that. How should I edit the code in order to make it do what I want?

without seeing the struct definition and memory allocation code, I at least can not help. It would help also that you would post some example of how you tested those other parts you say are functioning.

Please show the definition of the contact structure, and where and how you are allocating and initializing the newContact instance the you show in your code snippet.

Awright then fellas.

Here is my structure:

//
//  structure.h
//  Proje
//
//  Created by Can Sürmeli on 4/25/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//
//  PURPOSE: Structures

// The structure of a contact(single entry) in the address book
typedef struct entry{
	
	char first_name[15];
	char last_name[10];
	char date_of_birth[11];
	char e_mail[25];
	char phone[15];
	char address[50];
	char city[15];
	char zipcode[6];
	struct contact *next;
	
}ENTRY;



// The structure of a single node in the tree structure
struct tree_node {
	ENTRY data;
	struct tree_node *left;
	struct tree_node *right;
};

Here is the insert function:

//
//  insert.h
//  Proje
//
//  Created by Can Sürmeli on 4/17/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//
//  PURPOSE: Inserts a node into it's proper place

struct tree_node * insert(ENTRY contact, struct tree_node *node) {
	
	// if there is no root
	if( node == NULL )
		node = create_node(NULL, NULL, contact);
	
	
	// if there is a root & the new entry should be placed before the root
	else if( strcmp(contact.first_name, node->data.first_name) < 0 )
		node->left = insert(contact, node->left);
	
	
	// if there is a root & the new entry should be places after the root
	else if ( strcmp(contact.first_name, node->data.first_name) > 0 )
		node->right = insert(contact, node->right);
	
	
	// if there is a root & the first names are identical
	else {
		// if it should be placed before the root
		if ( strcmp(contact.last_name, node->data.last_name) < 0 )
			node->left = insert(contact, node->left);
		
		
		// if it should be places after the root
		else if( strcmp(contact.last_name, node->data.last_name) > 0 )
			node->right = insert(contact, node->right);
			
		
		// if the entries are the same
		else
			return node;
	}
		
	return node;
	
}

And here is the create_node function:

//
//  create_node.h
//  Proje
//
//  Created by Can Sürmeli on 4/29/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//
//  PURPOSE: Creates a node

struct tree_node *create_node(struct tree_node *a, struct tree_node *b, ENTRY contact) {
	
	struct tree_node *newNode;
	
	
	newNode = (struct tree_node *)(malloc(sizeof(struct tree_node)));
	
	newNode->data = contact;
	newNode->left = a;
	newNode->right = b;
	
	return newNode;
	
}

You might find this code slightly familiar:
Check code for simple address book, for improvements

Hope you do not mind me borrowing a start for a practice for refresher, as I have not used C much/for long time.

Hopefully you figured it out, if you did mark tread solved.

Thanks tonyjv. Really appreciate it.

I will try it right away and the report...

Following up, in case it helps:

Looking at your ENTRY struct, you say at the top it's a "struct entry" and then when you define the "next" pointer, you specify "struct contact" -- copy & paste & edit error?

Since the values you're reading into are all char-arrays, they already -are- pointers. It's perfectly valid to say:

char text[100];
char *ptr = &text[0];

However, if the values in your input file are actually comma-separated, you need to specify the commas in your format string to keep them from being included in your values. The %s also stops at and ignores white-space, so if a first name is "Mary Kay" or a last name is "van Wilder", you're going to have even more problems. Otherwise, it's useful to note that any number of spaces (or tabs or whatever) will be ignored, which is wonderfully useful when reading a set of column-aligned numbers (not that it's relevant to your use-case)! And sscanf() returns the number of arguments successfully read, so you can double-check your expectations.

So try:

while (fgets(temp, 160, pFile) != NULL ) {
    if (sscanf(temp, "%s,%s,%s,%s,%s,%s,%s,%s", ...) != 8) {
        fprintf(stderr, "wrong number of arguments read from string '%s'\n", temp);
        continue;
    }
    ...
}

But now that I think about it, I'm betting you have embedded white-space in the "address" field. So using strtok() will probably be a better bet. If you can also have commas inside your address field, you're in a world of hurt, but with any luck, your input has been sanitized to make things easy for you.

So. I'm not succeeded yet. :(

I've modified my retrieve code like the following:

//
//  retrieve.h
//  Proje
//
//  Created by Can Sürmeli on 4/26/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//
//  PURPOSE: Retrieves information from the text file into the BST.

void retrieve(struct tree_node *node, FILE *pFile) {
	
	char buffer[255];
	
	ENTRY contact;
	
    int i = 0,
		result;
	
	int maxData= 1000000;
	
	
	while( fgets(buffer, 255, pFile) != NULL && i < maxData ) {
		result = sscanf(buffer, " %14[^;\t\n] ; %19[^;\t\n] ; %10[^;\t\n] ; %44[^;\t\n] ; %14[^;\t\n] ; %49[^;\t\n] ; %14[^;\t\n] ; %5[^;\t\n]",
						contact.first_name,
						contact.last_name,
						contact.date_of_birth,
						contact.e_mail,
						contact.phone,
						contact.address,
						contact.city,
						contact.zipcode);
		
		insert(contact, node);
		
		if(result < 8) {
			printf("\nData reading failed in field number %d, record %d:\n%s\n", result, i+1, buffer);
			exit(2);
		}
		i++;
    }
}

But with no luck in working. Still it doesn't retrieve any of the info stored in the file into the BST. What am I doing wrong here. What should I modify?

Also I've a question about Tonyjv's coding. What are the meanings of those arguments in quotes in the sscanf function? Is it because you used a .csv file?

Rather than that Tonyjv, I really liked some of your ideas in your coding. Very useful.

I am taking anything but \t, \n or the separator ; including space upto maximum record length - 1 (for termination).

You prepared your data ; separated? See my test data.

Yeah. My save file is like you wanted it to be.

void save(struct tree_node *node, FILE *pFile) {
	
	if( node != NULL ) {
		save(node->left, pFile);
		fprintf(pFile, "%s;%s;%s;%s;%s;%s;%s;%s\n", node->data.first_name, node->data.last_name, node->data.date_of_birth, node->data.e_mail, node->data.phone, node->data.address, node->data.city, node->data.zipcode);
		save(node->right, pFile);
	}
	
}

Is my modifications to the retrieve code correct?

Should be, you can test my code and it does run with arrays. You should get "Data reading...." error message if data is in wrong format. Previous poster mentioned by the way strtok, like I was mentioning in my thread. Should be nicer with that than with sscanf. You could prove to read your data with my program.

I'm finally in a better shape.

I changed the while loop in the retrieve code into a do while loop. Seems that was my problem. Maybe Tonyjv coded in C99.

Now I'm getting the following error:

Data reading failed in field number -1, record 1:

More than that, as you've suggested Tonyjv, I used strtok instead of sscanf after getting the above error.

Here is what I've coded so far:

//
//  retrieve.h
//  Proje
//
//  Created by Can Sürmeli on 4/26/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//
//  PURPOSE: Retrieves information from the text file into the BST.

void retrieve(struct tree_node *node, FILE *pFile) {
	
	char	*ptr,
			buffer[200];
	
	int i;
	
	ENTRY contact;
	
		
	do {
		
		fgets(buffer, 200, pFile);
		
		i = 0;
		
		do {
			if (i==0) {
				ptr = strtok(NULL, ";");
				strcpy(contact.first_name, ptr);
			}
			
			else if (i==1) {
				ptr = strtok(NULL, ";");
				strcpy(contact.last_name, ptr);
			}
			
			else if (i==2) {
				ptr = strtok(NULL, ";");
				strcpy(contact.last_name, ptr);
			}
			
			else if (i==3) {
				ptr = strtok(NULL, ";");
				strcpy(contact.last_name, ptr);
			}
			
			else if (i==4) {
				ptr = strtok(NULL, ";");
				strcpy(contact.last_name, ptr);
			}
			
			else if (i==5) {
				ptr = strtok(NULL, ";");
				strcpy(contact.last_name, ptr);
			}
			
			else if (i==6) {
				ptr = strtok(NULL, ";");
				strcpy(contact.last_name, ptr);
			}
			
			else if (i==7) {
				ptr = strtok(NULL, ";");
				strcpy(contact.last_name, ptr);
			}
		} while (ptr != NULL);
		
	} while (fgets(buffer, 200, pFile) != NULL);
	
}

But it goes into GDB. And I can't see why.

You never call the first time with strtok(buffer, ";");
Also you do not consider failure to read (NULL returned) (the test in end is after you do strcopy and outer do loop does not react any way for inner NULL ptr.

http://www.cplusplus.com/reference/clibrary/cstring/strtok/

Then you are dropping every second line in line 69 without saving (line 23 overwrites).
You should use while loop, not do...while.

P.S. also you do not check if the read info fits in the field or not.
P.P.S. :( why if not switch? Inside for loop incrementing i!

If it "goes into GDB" you're in good shape, if you compile with the -g flag. You can solve most programming errors knowing only a few GDB commands:
+ "stop at <line>" tells the debugger to pause at the specified line
+ "run [args]" starts the program in the debugger
+ "step" continues to the next relevant line of code
+ "cont/continue" continues to the next breakpoint
+ "where" shows you what line you're at now
+ "print <var>" tells you the current value of the variable, e.g. "print i"
+ "up/down" move down into a called function's stack-frame, or up to the caller's
+ "help" always works! (especially in case I have the syntax slightly off here, I'm doing it from memory, and haven't used it in a year or so)

I admit it, parsing text in C is just plain painful. :)

Thanks raptr_dflo. Really appreciate your knowledge here. But I usually prefer to use Apple's Xcode. So my debugging is just a touch of a button. :))

But from time to time I use Terminal at the campus. So I'm sure someday they will come in handy.

Thanks buddy. :D

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.