B
Ben Bacarisse
arnuld said:I have shown you the output and it seems ok to me. Did you find something
wrong ?
Yes. Not in the sense of "it won't work" but wrong in the sense of
not right! If I do this:
#define MAX_SIZE 1000
...
char line[MAX_SIZE];
...
if (fgets(line, 902, fp) != NULL) ...
is it wrong? I think so, but the code will compile and execute quite
safely. That is all I was pointing out (see below).
I can't understand the 13.8 of FAQs: http://c-faq.com/lib/qsort1.html
/* compare strings via pointers */
int pstrcmp(const void *p1, const void *p2)
{
return strcmp(*(char * const *)p1, *(char * const *)p2);
}
parameters are made void* but in fact we are passing char**, which is 2 levels of
indirection. and what about the cast:
(char* const*)p1
we are casting a <pointer to void> to <pointer to a const pointer to char>
, right ?
Yup. qsort is given an array to sort. All it know about this data is
how big each element is and how many there are:
+----------+----------+----------+----------+----
base-----> | element1 | element2 | element3 | element4 | ...
+----------+----------+----------+----------+----
If qsort needs to compare element1 with element4, it passes a pointer
to these elements to the comparison function. These pointers must be
void * because qsort has no type information at all. Your comparison
function gets two pointers like this:
+----------+----------+----------+----------+----
base-----> | element1 | element2 | element3 | element4 | ...
+----------+----------+----------+----------+----
^ ^
| |
+---------------+ |
| |
int compare(const void *p1, const void * p2)
In your case, the elements are actually char *s -- they point to
strings like this:
+---+---+---+---+---+ +---+---+---+---+---+
| a | b | c | \n| \0| | d | e | f | \n| \0|
+---+---+---+---+---+ +---+---+---+---+---+
^ ^
| |
+---|------+----------+----------+---|------+----
base-----> | element1 | element2 | element3 | element4 | ...
+----------+----------+----------+----------+----
^ ^
| |
+---------------+ |
| |
int compare(const void *p1, const void * p2)
so although p1 is declared void * what it *really* is is a char ** --
it points to a char *. To get at the strings to compare you must
convert p1 to a char ** and access the char * it finds there (by
applying the * operator to the result). We make everything const, but
just blank that out to follow the intent:
int compare(const void *p1, const void * p2)
{
const char *const *cp1 = p1; /* char **cp1 = p1; in effect */
const char *const *cp2 = p2;
return strcmp(*cp1, *cp2);
}
*cp1 is 'element1' -- a char * pointing at "abc\n" and *cp2 is a char
pointing at "def\n". The code in the FAQ does the same (with one less
const) all in a single expression. I prefer to avoid the cast. Does
that help?
incorrect ?
Yes, you pass ARR_SIZE as the max parameter, but temp_arr is of size
STR_SIZE. Now, as it happens, max is smaller than STR_SIZE so this is
safe but fgets shoudl be passed the size of the thing is is to use,
not some other size that relates to something else!
you mean, by default, if I type: <malloc( size_arr )> then it will be
converted to <malloc(size_arr * 1)> ?
Not really. If you write x it is not converted to x * 1 even though
they are the same. If you write malloc(size_arr) you get size_arr
bytes. Multiplying by sizeof(char) is pointless because sizeof(char)
is 1. Some people like to write it out because it reminds them that
are allocating space for chars, but I prefer not to do that.