Domanda

so I'm using C, I cant seem to get this to work right. It's an array of pointers to structs which contain some contact info. I can't seem to get the qsort to sort correctly. Here is my code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 20
#define ELEMENTS 50

int sortZips(const void *a, const void *b);

typedef struct contactInfo {
char name[MAX];
char street[MAX];
char cityState[MAX];
char zipCode[MAX];
} contacts;


int main() {
int i = 0;
contacts **contactArray = malloc(ELEMENTS * sizeof(contacts *));     

/*  allocate array  */
for (i = 0; i < ELEMENTS; i++) {
    contactArray[i] = malloc(sizeof(contacts));
}
/*  populate array  */
for (i = 0; i < ELEMENTS; i++) {
    fgets(contactArray[i]->name,MAX,stdin);
    fgets(contactArray[i]->street,MAX,stdin);
    fgets(contactArray[i]->cityState,MAX,stdin);
    fgets(contactArray[i]->zipCode,MAX,stdin);

    printf("%s", contactArray[i]->name);
    printf("%s", contactArray[i]->street);
    printf("%s", contactArray[i]->cityState);
    printf("%s", contactArray[i]->zipCode);

}
printf("\n");


/*  qsort((void *)contactArray, ELEMENTS, sizeof(contacts *), sortZips);  */


for (i = 0; i < ELEMENTS; i++) {
    fputs(contactArray[i]->name,stdout);
    fputs(contactArray[i]->street,stdout);
    fputs(contactArray[i]->cityState,stdout);
    fputs(contactArray[i]->zipCode,stdout);
}


}


/*  sortZips() sort function for qsort  */

int sortZips(const void *a, const void *b) {

const contacts *ia = *(contacts **)a;
const contacts *ib = *(contacts **)b;
return strcmp(ia->zipCode, ib->zipCode);



}

The output is printing the addresses (I have 50 in an input file) and then some random characters, like a huge block of them, then the sorted list after that which is messed up and not sorted right.

Please any help would be appreciated. I need to learn what's wrong here and why. Thanx.

È stato utile?

Soluzione

First rule: always check input functions - in this case, fgets(). You don't know whether everything is working correctly or not if you do not check.

Second: use enum in preference to #define in general.

With the check for early EOF in place, your code sorted my sample data (6 rows) cleanly. It also compiled cleanly - which is very unusual (that's a compliment; I use stringent warnings and even my code seldom compiles cleanly the first time). My amended version of your code is very similar to yours:

int main(void)
{
    int i = 0;
    int num;
    contacts **contactArray = malloc(ELEMENTS * sizeof(contacts *));

    /*  allocate array  */
    for (i = 0; i < ELEMENTS; i++)
        contactArray[i] = malloc(sizeof(contacts));

    /*  populate array  */
    for (i = 0; i < ELEMENTS; i++)
    {
        if (fgets(contactArray[i]->name,MAX,stdin) == 0 ||
            fgets(contactArray[i]->street,MAX,stdin) == 0 ||
            fgets(contactArray[i]->cityState,MAX,stdin) == 0 ||
            fgets(contactArray[i]->zipCode,MAX,stdin) == 0)
            break;
        printf("%s", contactArray[i]->name);
        printf("%s", contactArray[i]->street);
        printf("%s", contactArray[i]->cityState);
        printf("%s", contactArray[i]->zipCode);
    }
    printf("\n");
    num = i;

    qsort(contactArray, num, sizeof(contacts *), sortZips);

    for (i = 0; i < num; i++)
    {
        fputs(contactArray[i]->name,stdout);
        fputs(contactArray[i]->street,stdout);
        fputs(contactArray[i]->cityState,stdout);
        fputs(contactArray[i]->zipCode,stdout);
    }
    return 0;
}

The data I used was trivial repetitions of sets of 4 lines like this:

First LastName7
7 Some Street
City, CA
95437

Note that the 'error checking' I do in the input is the bare minimum that 'works'. If you get an over-long line in the input, one field will not contain a newline, and the next will contain the next section of the input line (possibly all the rest, possibly not - it depends on how badly overlong the line is).

Altri suggerimenti

If your addresses are printing out rubbish at the end, then it's almost certainly because you haven't allocated enough space for them. Twenty characters is a little on the low side for addresses.

What's probably happening is that you have an address like:

14237 Verylongstreetname Avenue

and, when you do fgets (street,20,stdin);, only 14237 Verylongstree will be read (19 characters, leaving space for the null terminator).

And, here's the crux: the file pointer will still be pointing at the tname Avenue bit so that, when you try to read the cityState, you'll get that. And, when you try to read the zipCode, you'll get the cityState line, effectively stuffing up your sorting.

I believe that you have enough space. Because you are using fgets and your size of MAX, the strings should be cut to fit and have a terminating NUL at the end.

Two things that might be messing it up:

  • fgets will read from where it stopped reading if the line is too long. That will result in an address of "This is too long so", " it will be cut\n". And then the rest of the input will be all over the place.
  • If you do not have enough input to fill ELEMENTS items then you'll get whatever random data was in the malloc'd memory. If you were to use calloc instead, it would zero the memory for you. Although the better idea would be to use a counter of how many items were actually read, instead of assuming there will be ELEMENTS items.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top