简体   繁体   中英

How to fix the “discard const” in c qsort function (the array is a pointer array), might related to the understanding of pointers

I'm learning C at the moment. currently learning the c pointer (pointer arrays). What the below code (a prototype from C in a nutshell) trying to do is to read the text from stdin, line by line. every array element is a pointer to one line of text, then sort the text by just sort the pointers. When I try to compile my code, the compiler (gcc) give me a warning of "discard const", I tried to add the cast (const char **) in the str_compare function, but still doesn't fix my problem

I think this might related to my understanding to c pointers. can someone help to point out where and i did wrong, what is the problem in my code please?

I turned on a lot of warning flags and treat all the warnings as errors in gcc. I can understand the pointers and I used qsort before, it all turned out fine. But this is the first time i code pointer to pointers. so I think i might have some misunderstanding here.

// Read text line by line then sort them, use point array

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

char *getLine(void);
int str_compare(const void *, const void *);

#define NLINES_MAX 1000
char *linePtr[NLINES_MAX];

int main()
{
    // Read lines;
    int long unsigned n = 0;
    for ( ; n < NLINES_MAX && (linePtr[n] = getLine()) != NULL; ++n)
        ;

    if ( !feof(stdin))
    {
        if (n == NLINES_MAX)
            fputs("sorttex: too many lines.\n", stderr);
        else
        {
            fputs ("sorttext: error reading from stdin.\n", stderr);
        }
    }
    else
    {
        qsort(linePtr, n, sizeof(char *), str_compare);
        for ( char **p = linePtr; p < linePtr +n; ++p)
            puts(*p);
    }
    return 0;
}

int str_compare(const void *p1, const void *p2)
{
    return strcmp(*(const char **)p1, *(const char **)p2);
}

#define LEN_MAX 512

char *getLine()
{
    char buffer[LEN_MAX], *lineP = NULL;
    if (fgets (buffer, LEN_MAX, stdin) != NULL)
    {
        size_t len = strlen(buffer);
        if (buffer[len-1] =='\n')
            buffer[len-1] = '\0';
        else
        {
            ++len;
        }
        if ((lineP = malloc(len)) != NULL)
            strcpy( lineP, buffer);
    }
    return lineP;
}

The gcc flags are:

 -std=c11 -pedantic-errors -pipe -O2 -Wall -Werror -Wextra -Wfloat-equal \\ -Wshadow -Wpointer-arith -Wcast-align -Wstrict-overflow=5 -Wwrite-strings \\ -Waggregate-return -Wcast-qual -Wswitch-default -Wswitch-enum -Wconversion \\ -Wunreachable-code -Winit-self -march=native 

I expect to get rid of the "discard const" warning message

The argument passed to the str_compare function is the address of the array element. The array element has type char * , and the caller of str_compare will treat it as const, and then pass the address in. So, you will actually be receiving a char * const * .

So, the const void * is actually

pointer to a constant pointer to char

and NOT

pointer to a pointer to a constant char

as you had coded.

int str_compare(const void *p1, const void *p2)
{
    char * const *pp1 = p1;
    char * const *pp2 = p2;
    return strcmp(*pp1, *pp2);
}

The line could be:

return strcmp(*(char *const *)p1, *(char *const *)p2);

The items being sorted are pointers to char * (Not pointers to const char * as your code would say). And the inner const is to ensure that the comparison function does not modify the objects being compared (which are the char * objects, hence char * const ).

Of course, expanding it out with extra variables as shown by jxh is not a bad idea either.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM