Thread: array of pointers to structures sorting addresses by zip code

  1. #1
    Registered User
    Join Date
    Apr 2011
    Posts
    5

    array of pointers to structures sorting addresses by zip code

    Hello. I am working on a C program that reads in an input file with a bunch of addresses in alphabetical order and outputs the names and addresses to another file sorted by zip code. The program uses array of pointers to structures and malloc with no global variables. I have written the input and output functions thus far. Still working on the sort function. My program is outputting strange characters when I run it. I have 3 files with the following code so far:

    record.h
    Code:
    #define size 40
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct{
    	char name[size];
    	char address[size];
    	char citystate[size];
    	char zipcode[size];
    }CITYRECORDS;
    
    typedef CITYRECORDS *CRP;
    CRP p;
    
    void readin(CITYRECORDS *city[], int num);
    void writot(CITYRECORDS *city[], int num);
    record.c
    Code:
    #define MAXCITYREC 50
    #include "record.h"
    
    char buffer[81];
    
    void readin(CITYRECORDS *city[], int num){
    	num=0;
    
    	while((gets(buffer)!=NULL)&&(num<MAXCITYREC)){
    		p=(CRP)malloc(sizeof(CITYRECORDS));
    		strcpy(p->name, buffer);
    		gets(p->address);
    		gets(p->citystate);
    		gets(p->zipcode);
    	}
    	city[num++]=p;
    	free(p);
    }
    
    void writot(CITYRECORDS *city[], int num){
    /*	CITYRECORDS *p;*/
    	
    	for(p=*city;p<*city+num;p++){
    		printf("%c %c %c %c\n", p->name, p->address, p->citystate, p->zipcode);
    	}
    }
    prog6b.c
    Code:
    #define CITIZENS 50
    #include "record.h"
    
    void main(void){
    	CITYRECORDS *city[50];
    	int n=CITIZENS;
    
    	readin(city, n);
    	writot(city, n);
    }
    I am getting the following output in the file after I run the program.

    è  8 `
    ˆ ° Ø
    ( P x ..
    È ğ  @
    h ¸ à
     0 X €
    ¨ Ğ ø
    H p ˜ À
    è  8 `
    ˆ ° Ø
    ( P x ..
    È ğ  @
    h ¸ à
     0 X €
    ¨ Ğ ø
    H p ˜ À
    è  8 `
    ˆ ° Ø
    ( P x ..
    È ğ  @
    h ¸ à
     0 X €
    ¨ Ğ ø
    H p ˜ À
    è  8 `
    ˆ ° Ø
    ( P x ..
    È ğ  @
    h ¸ à
     0 X €
    ¨ Ğ ø
    H p ˜ À
    è  8 `
    ˆ ° Ø
    ( P x ..
    È ğ  @
    h ¸ à
     0 X €
    ¨ Ğ ø
    H p ˜ À
    è  8 `
    ˆ ° Ø
    ( P x ..
    È ğ  @
    h ¸ à
     0 X €
    ¨ Ğ ø
    H p ˜ À
    è  8 `
    ˆ ° Ø
    Any help on how to fix this will be greatly appreciated.

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Why are you freeing what you are filling? What did you expect to happen? (Plus, you use gets, but that's a different issue.)


    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered User claudiu's Avatar
    Join Date
    Feb 2010
    Location
    London, United Kingdom
    Posts
    2,094
    Also, void main should be int main and should return 0.
    1. Get rid of gets(). Never ever ever use it again. Replace it with fgets() and use that instead.
    2. Get rid of void main and replace it with int main(void) and return 0 at the end of the function.
    3. Get rid of conio.h and other antiquated DOS crap headers.
    4. Don't cast the return value of malloc, even if you always always always make sure that stdlib.h is included.

  4. #4
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    I stuffed all your code into one file, but it shouldn't matter:
    Code:
    $ gcc -Wall address.c
    test.c: In function ‘writot’:
    test.c:42: warning: format ‘%c’ expects type ‘int’, but argument 2 has type ‘char *’
    test.c:42: warning: format ‘%c’ expects type ‘int’, but argument 3 has type ‘char *’
    test.c:42: warning: format ‘%c’ expects type ‘int’, but argument 4 has type ‘char *’
    test.c:42: warning: format ‘%c’ expects type ‘int’, but argument 5 has type ‘char *’
    test.c: At top level:
    test.c:46: warning: return type of ‘main’ is not ‘int’
    /tmp/ccSq7Hvk.o: In function `readin':
    test.c:(.text+0x41): warning: the `gets' function is dangerous and should not be used.
    You need to compile with the warning level turned all the way up, and make sure you have 0 warnings in your code. You need to read the printf docs and figure out how you should print a string (yep, p->name is a string).

    Code:
    void readin(CITYRECORDS *city[], int num){
    Any changes you make to num inside readin don't show up in main. You only pass in a copy of the number, not the actual variable. Make the function return an int, and declare num to be a local variable instead of a parameter. Then, at the end, return num from the function:
    Code:
    readin(CITYRECORDS *city[]){
        int num = 0;
        ...
        return num;
    }
    Save that return value in main, and pass that into writeot instead of n (CITIZENS).

    Code:
        city[num++]=p;
        free(p);
    You allocate memory, assign city[num++] to point to it, then free it. Once it's free'd, you have no guarantee that any data is still in there. Don't free that memory until you're totally done using it (probably when you exit the program).

    Two more things:
    1. It's int main(void), and return an int at the end, usually 0.
    2. gets is a horrible, nasty, dirty function...never use it.

  5. #5
    Registered User
    Join Date
    Apr 2011
    Posts
    5
    Thanks for the help. I made the changes to the program and also read the info on why not using the gets function. Unfortunately, I can't use fgets on this assignment. I have to use that command until the next assignment. I am getting this output now:
    A1, A2
    20294 Lorenzana Dr
    Woodland Hills, CA
    91364
    ııııİİİİ
    5
    ÍÍÍÍÍÍÍÍ19831 Henshaw St
    ÍÍÍÍÍÍÍÍCulver City, CA
    ÍÍÍÍÍÍÍÍ94023
    ÍÍÍÍÍÍÍÍııııİİİİ
    ..
    ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ5142 Dumont Pl
    ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍAzusa, CA
    ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ91112
    ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍııııİİİİ

    ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ20636 De Forest St
    St
    CA
    ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍııııİİİİ
    @4
    İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİ İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİ İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİ İİJ
    İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİ İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİ İİİİİİİİİİİİJ
    İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİ İİİİİİİİİİİİİİİİİİİİİİJ
    İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİJ
    Ğ 4

    stuvwxyz

    ëìíîïğñòóôõö
    ÓÔÕÖ
    œ& u
    Ğ34
    °64
    ..:4
    è=4
    4
    ents and Settings\All Users
    24
    C:\Documents and Settings\Heathcliff\Application Data
    lication Data
    œ& ~
    ion=file;OnFirstLog=command,environment,parent
    parent
    :
    iles\Java\jre6\lib\ext\QTJava.zip
    
    CLIENTNAME=Console
    œ& ~
    es=C:\Program Files\Common Files

    COMPUTERNAME=GARFIELD
    P44
    C:\WINDOWS\system32\cmd.exe
    ˜44
    ST_CHECK=NO

    HOMEPATH=\Documents and Settings\Heathcliff
    iff
    
    NUMBER_OF_PROCESSORS=1

    I don't know why all this extra information is getting thrown in the file.

    Here's my new code:
    Code:
    record.h
    #define size 40
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct{
    	char name[size];
    	char address[size];
    	char citystate[size];
    	char zipcode[size];
    }CITYRECORDS;
    
    typedef CITYRECORDS *CRP;
    CRP p;
    
    int readin(CITYRECORDS *city[]);
    void writot(CITYRECORDS *city[], int num);
    
    record.c
    #define MAXCITYREC 50
    #include "record.h"
    
    char buffer[81];
    
    int readin(CITYRECORDS *city[]){	
    	int num=0;
    
    	while((gets(buffer)!=NULL)&&(num<MAXCITYREC)){
    		p=(CRP)malloc(sizeof(CITYRECORDS));
    		strcpy(p->name,buffer);
    		gets(p->address);
    		gets(p->citystate);
    		gets(p->zipcode);
    		city[num++]=p;		
    	}
    	return num;
    }
    
    void writot(CITYRECORDS *city[], int num){
    	CITYRECORDS *pcr;
    	for(pcr=*city;pcr<*city+num;pcr++){
    		printf("%s\n%s\n%s\n%s\n", pcr->name, pcr->address, pcr->citystate, pcr->zipcode);
    	}
    }
    
    progb6b.c
    #define CITIZENS 50
    #include "record.h"
    
    int main(void){
    	CITYRECORDS *city[CITIZENS];
    
    	int n=readin(city);
    	writot(city, n);
    	return 0;
    }

  6. #6
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Code:
    record.h
    
    #define size 40
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct{
    	char name[size];
    	char address[size];
    	char citystate[size];
    	char zipcode[size];
    }CITYRECORDS;
    
    typedef CITYRECORDS *CRP;
    CRP p;
    
    int readin(CITYRECORDS *city[]);
    void writot(CITYRECORDS *city[], int num);
    1) It sometimes causes problems to hide a pointer type by typedefing it and obscuring its presence.

    2) Don't put variables in your header files like what you have for CRP p. This file is included in two separate source files which means each one, when compiled, gets its own version of the variable p. When the linker tries to merge the two object files record.obj and progb6b.obj it should be spitting out a linker error about variable already being defined somewhere else. The CRP type variable p is only used in the record source file so it should only be declared there. This error should really have prevented you from building your program at all.

    3) Might be a matter of personal taste, but those #includes don't really belong there. The header should be minimalist in that it should only contain #include statements that are required for that header to compile. Since the header itself doesn't contain anything other than some prototypes and struct definitions and typedefs, no #include statements should be necessary at this point. These should be in the individual source files themselves.

    4) Your two source files define the values CITIZENS/MAXCITYREC as 50. To avoid confusion you should simply create a single define and place it in the header and reference that identifier in both of your source files.

    5) Consider using header inclusion guards in any header as well.

    Considering all of that I would have this as my record.h header file:
    Code:
    #ifndef RECORD_H
    #define RECORD_H
    
    #define size 40
    #define MAX_CITIZENS 50
    
    typedef struct{
    	char name[size];
    	char address[size];
    	char citystate[size];
    	char zipcode[size];
    }CITYRECORDS;
    
    int readin(CITYRECORDS *city[]);
    void writot(CITYRECORDS *city[], int num);
    
    #endif RECORD_H




    Code:
    progb6b.c
    #define CITIZENS 50
    #include "record.h"
    
    int main(void){
    	CITYRECORDS *city[CITIZENS];
    
    	int n=readin(city);
    	writot(city, n);
    	return 0;
    }
    6) As mentioned, that #define statement should be gone, use the one you declare in the header (I've named it MAX_CITIZENS in my example). Nothing in this source file requires any of the stdio/stdlib/string headers so record.h not having them is not an issue here.





    Code:
    record.c
    #define MAXCITYREC 50
    #include "record.h"
    
    char buffer[81];
    
    int readin(CITYRECORDS *city[]){	
    	int num=0;
    
    	while((gets(buffer)!=NULL)&&(num<MAXCITYREC)){
    		p=(CRP)malloc(sizeof(CITYRECORDS));
    		strcpy(p->name,buffer);
    		gets(p->address);
    		gets(p->citystate);
    		gets(p->zipcode);
    		city[num++]=p;		
    	}
    	return num;
    }
    
    void writot(CITYRECORDS *city[], int num){
    	CITYRECORDS *pcr;
    	for(pcr=*city;pcr<*city+num;pcr++){
    		printf("%s\n%s\n%s\n%s\n", pcr->name, pcr->address, pcr->citystate, pcr->zipcode);
    	}
    }
    Disregarding, for the moment, your use of gets we have...
    7) If you need to place your typedef for the CITYRECORDS* here then do so in this source file, it doesn't need to be anywhere else.

    8) The define should be removed and in its place simply use whatever you choose as its replacement in the header.

    9) This source file requires the use of the stdio/stdlib/string headers so they should be included here.

    10) The return value from malloc calls should not be typecast. The malloc function returns a void* pointer that can be safely assigned without need of a typecast to CRP.

    11) You do not test the return value of the malloc call, you simply assume that it works.

    12) There is the possibility your gets call will read more than the number of bytes/characters that can be safely stored in your struct members. In particular, your input into the variable buffer can safely be up to 80 characters (for whatever the reason you've decided). Then, you call strcpy into a destination buffer that can only hold up to 40 characters. So here, there might be a case where a gets call succeeds only to have the strcpy cause problems.

    13) Your output code is a bit messy and the likely cause of some of your weird output. I'd suggest something more like:
    Code:
    void writot(CITYRECORDS *city[], int num){
        for(int i = 0;i<num;i++){
            printf("%s\n%s\n%s\n%s\n", city[i]->name, city[i]->address, city[i]->citystate, city[i]->zipcode);
        }
    }
    In general...
    14) What you malloc you should also free. Modern operating systems will recover the memory as your program exits but you should not rely on this yourself. Be neat and pick up after yourself. Put some code in there to free up that memory.
    Last edited by hk_mp5kpdw; 05-26-2011 at 07:38 AM. Reason: Correct some minor spelling/syntax issues
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Sorting array structures
    By Jaxtomtom89 in forum C Programming
    Replies: 1
    Last Post: 11-30-2010, 06:09 AM
  2. sorting an array of structures
    By kisiellll in forum C Programming
    Replies: 15
    Last Post: 04-06-2009, 05:25 AM
  3. Array of Structures: Sorting
    By Drainy in forum C Programming
    Replies: 3
    Last Post: 04-13-2005, 09:55 AM
  4. Sorting an array of structures with sort()
    By rmullen3 in forum C++ Programming
    Replies: 3
    Last Post: 01-03-2003, 03:02 PM
  5. Sorting an Array of Structures
    By bob2509 in forum C++ Programming
    Replies: 7
    Last Post: 05-12-2002, 08:26 AM

Tags for this Thread