initialization discards ‘const’ qualifier from pointer target type

2.2k Views Asked by At

I have an array structs that hold char names. I want to sort them alphabetically using qsort however I keep getting an error message saying "initialization discards ‘const’ qualifier from pointer target type". I believe my cmpmi() function and qsort arguments are correct. Any help is greatly appreciated!

My error is:

gcc -std=gnu11 -Werror -Wall -o main main.c -lm -g
main.c: In function ‘compmi’:
main.c:18:25: error: initialization discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
  const student_t **p1 = a;
                         ^
main.c:19:25: error: initialization discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
  const student_t **p2 = b;
                         ^
cc1: all warnings being treated as errors
makefile:2: recipe for target 'main' failed
make: *** [main] Error 1

This is my qsort function:

int compmi(const void *a, const void *b)
{
    const student_t **p1 = a;
    const student_t **p2 = b;
    return strcmp((*p1)->name, (*p2)->name);
}

Code:

int main(int argc, char **argv) {
    unsigned numrecords;
    int i = 0;
    int length_multiplier = 1;
    char *lettergrade;
    //char *input = NULL;
    //char *pItem;
    
    student_t **students = NULL;
    // OPENS THE FILE IN BINARY
    FILE *input_file;
    input_file = fopen("input.bin", "rb");
    // READS THE NUMBER OF RECORDS
    fread(&numrecords, sizeof(u_int32_t), 1, input_file);
    
    // LOOPING THROUGH EACH ENTRY
    for(i = 0; i <= numrecords; i++)
    {
        // ALLOCATES MEMORY
        students = realloc(students, sizeof(student_t *) * length_multiplier);
        students[i] = malloc(sizeof(student_t));
        
        students[i]->name = malloc(sizeof(student_t)* 20);
        fread(students[i]->name, sizeof(student_t), 20, input_file);//READ NAME
        fread(&students[i]->gpa, sizeof(student_t), 1, input_file); // READ GPA
        fread(&students[i]->age, sizeof(u_int32_t), 1, input_file);// READ AGE
        
        length_multiplier++;
        
    }
    //SORTING WITH QSORT
    qsort(*students, numrecords, sizeof(student_t *), compmi);

    // PRINTING OUTPUT
    for(i = 0; i < length_multiplier - 2 ; i++)
    {
        printf("%i of %d:\n", i + 1, numrecords);
        printf("Name: %s\n", students[i]->name);
        //printf("UPDATED GPA USE THIS: %.1f\n", students[i]->gpa);
        printf("GPA:  %.1f \n", students[i]->gpa);
        printf("Age:  %i\n", students[i]->age);
        printf("\n");
    }
    
    // FREEING MEMORY
    for(i = 0; i < length_multiplier; i++)
    {
        free(students[i]);
        
    }
    free(students);
    fclose(input_file);
    
    return 0;
}
2

There are 2 best solutions below

2
dbush On

The variable a points to a const qualified type, but p1 does not point to a const type (but what that points to is). You need to add const between the *s.

int compmi(const void *a, const void *b)
{
    const student_t * const *p1 = a;
    const student_t * const *p2 = b;
    return strcmp((*p1)->name, (*p2)->name);
}
2
chqrlie On

There are multiple problems in the code:

  • the comparison function converts pointers to constant objects to pointers to non constant objects themselves pointers to constant student objects. The original constness is not preserved. The definitions should be:

    const student_t * const *p1 = a;
    const student_t * const *p2 = b;
    
  • the reading loop should stop when i == numrecords so you should use i < numrecords instead of i <= numrecords.

  • the fread sizes are incorrect: you should specify the size of the member type, not that of the student_t structure.

  • you pass *students to qsort instead of the array pointer students.

Here is a modified version:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct student_t {
    char *name;
    float gpa;
    int age;
} student_t;

int compmi(const void *a, const void *b) {
    const student_t * const *p1 = a;
    const student_t * const *p2 = b;
    return strcmp((*p1)->name, (*p2)->name);
}

int main(int argc, char **argv) {
    unsigned numrecords;
    int i = 0;
    char *lettergrade;

    // OPENS THE FILE IN BINARY
    FILE *input_file = fopen("input.bin", "rb");
    if (input_file == NULL) {
        fprintf(stderr, "cannot open input.bin\n");
        return 1;
    }
    // READS THE NUMBER OF RECORDS
    fread(&numrecords, sizeof(unsigned), 1, input_file);
    
    // allocate the array directly, no need for realloc
    student_t **students = malloc(sizeof(*students) * num_records);
    if (students == NULL) {
        fprintf(stderr, "allocation error\n");
        return 1;
    }

    // LOOPING THROUGH EACH ENTRY
    for (i = 0; i < numrecords; i++) {
        // ALLOCATE MEMORY
        if ((students[i] = malloc(sizeof(student_t))) == NULL
        ||  (students[i]->name = calloc(21, 1)) == NULL) {
            fprintf(stderr, "allocation error\n");
            return 1;
        }
        // READ NAME, GPA and AGE
        if (fread(students[i]->name, 20, 1, input_file) != 1
        ||  fread(&students[i]->gpa, sizeof(students[i]->gpa), 1, input_file) != 1
        ||  fread(&students[i]->age, sizeof(students[i]->age), 1, input_file) != 1) {
            fprintf(stderr, "error reading data for record %d / %d\n", i + 1, numrecords);
            return 1;
        }
    }
    fclose(input_file);

    //SORTING WITH QSORT
    qsort(students, numrecords, sizeof(*students), compmi);

    // PRINTING OUTPUT
    for (i = 0; i < numrecords; i++) {
        printf("%i of %d:\n", i + 1, numrecords);
        printf("Name: %s\n", students[i]->name);
        //printf("UPDATED GPA USE THIS: %.1f\n", students[i]->gpa);
        printf("GPA:  %.1f\n", students[i]->gpa);
        printf("Age:  %i\n", students[i]->age);
        printf("\n");
    }
    
    // FREEING MEMORY
    for (i = 0; i < numrecords; i++) {
        free(students[i]->name);
        free(students[i]);
    }
    free(students);
    
    return 0;
}

Note however that using binary format for the data is problematic:

  • the sizes and representation of various types may change from one system to another.
  • binary files require a precise specification and are not easy to debug.
  • text files are a preferred format for interchange. They are easy to read and write.