Warning when trying to run Anagram(John Bentley-Programming Pearls)-C - c

completely new to C. just trying to get the hang of linux and C programming by getting John Bentley's Anagram (column 2 I believe)program to run. Pretty sure ive copied this code verbatim(had to add headers, etc) but im receiving a warning, which when compiled and run with my squash.c program gives an undesired output. ill admit, i dont even know how this charcomp function behaves, or what it even does. (some enlightenment there would also be nice).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int charcomp(char *x, char *y) {return *x - *y;}
#define WORD_MAX 100
int main(void)
{
char word[WORD_MAX], sig[WORD_MAX];
while (scanf("%s", word) != EOF) {
strcpy(sig, word);
qsort(sig, strlen(sig), sizeof(char), charcomp);
printf("%s %s\n", sig, word);
}
return 0;
}
Here's the warning.
sign.c:13:41: warning: incompatible pointer types passing 'int (char *, char *)'
to parameter of type '__compar_fn_t' (aka 'int (*)(const void *, const
void *)') [-Wincompatible-pointer-types]
qsort(sig, strlen(sig), sizeof(char), charcomp);
^~~~~~~~
/usr/include/stdlib.h:766:20: note: passing argument to parameter '__compar'
here
__compar_fn_t __compar) __nonnull ((1, 4));
^

The qsort() function takes a comparison function as a fourth argument, with the following signature:
int (*compar)(const void *, const void *)
Therefore, to avoid compiler warnings, you have to modify you charcomp() function in the following way, to fit that signature:
int charcomp(const void *x, const void *y) { return *(char *)x - *(char *)y; }
Your charcomp function just takes two char* pointers to and compares first their first characters.

Related

How to fix "conflicting types" for a function and its declaration?

I want to pass a two-dimensional char array to a function but don't know how to declare the function before the main(). The function compiles and works well before I declare it. But after I declare it, I encounter compiling issues.
I'm using EMACS on MacBook pro. The compiler is gcc.I tried to declare my function print string various ways including
void printstring(int, int,char **);
or
void printstring(int, int,char *);
But none of them work. My Full codes are:
#include<stdio.h>
#include<stdlib.h>
void printstring(int, int,char **);
int main(){
char word[3][6]= {"hello","world","I"};
printstring(3,6,word);
return 0;
}
void printstring(int n, int m, char (*w)[m]){
for (int i = 0; i < n; i++){
printf("%s\n",w[i]);
}
return;
}
I expected that there is no compiling error but I got one error and one warning. Details can be found below:
test.c: In function 'main':
test.c:9:19: warning: passing argument 3 of 'printstring' from incompatible pointer type [-Wincompatible-pointer-types]
printstring(3,6,word);
^~~~
test.c:5:6: note: expected 'char **' but argument is of type 'char (*)[6]'
void printstring(int, int,char **);
^~~~~~~~~~~
test.c: At top level:
test.c:13:6: error: conflicting types for 'printstring'
void printstring(int n, int m, char (*w)[m]){
^~~~~~~~~~~
test.c:5:6: note: previous declaration of 'printstring' was here
void printstring(int, int,char **);
^~~~~~~~~~~
the problem is that you're using a variable length array. The last argument (the list of strings) depends on the second argument (m). And char ** is not suitable, as it's just a pointer on pointers. So the max dimension of the strings would be lost when iterating on the 2D array.
Use a standard forward declaration, copying exactly the real declaration if you don't want to put the function before the main one.
void printstring(int n, int m, char (*w)[m]);
int main(){
char word[3][6]= {"hello","world","I"};
printstring(3,6,word);
return 0;
}
void printstring(int n, int m, char (*w)[m]){
for (int i = 0; i < n; i++){
printf("%s\n",w[i]);
}
return;
}
If you have read-only strings, I suggest that you use a standard array of constant pointers instead:
void printstring(int n, const char *w[]);
int main(){
const char *word[] = {"hello","world","I"};
printstring(3,word);
return 0;
}
void printstring(int n, const char *w[])
{
for (int i = 0; i < n; i++){
printf("%s\n",w[i]);
}
return;
}
note that
printstring(3,word);
can be replaced by
printstring(sizeof(word)/sizeof(word[0]),word);
before array decays to pointer (that autocomputes the number of strings)
If you want to maintain a name free declaration for whatever reason, you can use the * notation (reserved to function prototype scope) for the variably modified type
void printstring(int, int,char (*)[*]);
Still a VLA, and in fact, exactly equivalent to the notation that uses m. Though, ostensibly, it may convey intent not as clearly as using m in the forward declaration.
The following should just work:
void printstring(int n, int m, char (*w)[m]);
The function prototype and definition should be kept identical, except maybe for certain qualifiers such as const and default arguments in C++.
char** cannot be used to point at 2D arrays, it can only be used to point at the first element of a 1D array of char*, which is something else.
Your compiler error is from having non-matching declaration and definition. Correct code:
void printstring(int n, int m, char w[n][m]);
...
void printstring(int n, int m, char w[n][m]){
...
}
Alternatively, you can write void printstring(int n, int m, char (*w)[m]) and it is completely equivalent. But that is just harder to read, so why would you?

How to convert explicitly from const type to type, in C?

If I compile the following code (in file "myfile.c") by gcc:
void bar(int *pi)
{
/* do something */
}
foo(const int *pi)
{
bar(pi);
}
Using the following command line:
gcc myfile.c -ansi -pedantic-errors
I get the following error:
error: passing argument 1 of 'bar' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
bar(pi);
note: expected 'int *' but argument is of type 'const int *'
void bar(int *pi)
My question is, without changing the command line, how to avoid this error? e.i. just by writing some code in foo, because I can't change bar and foo prototypes.
First, const-ness can be cast away, as long as the actual pointer points to a non-const location:
foo(const int *pi) {
bar((int*)pi); // <<== Be very careful with this!
}
The assumption here is that pi is really a non-const pointer, so the best course of action is to have the compiler enforce it by removing const from foo's declaration:
void foo(int *pi) { // Remove const
...
}
If you cannot do that, and since bar takes an int pointer without const qualifier, you need to pass it a location that can be written. For example, if this is a single item, not an array, you could make a copy of what the pointer points to, and pass that to the function:
void bar(int *pi, size_t n) {
/* do something */
}
foo(const int *pi) {
int tmp = *pi;
bar(&tmp);
}
If pi points to an array of n elements, you would need to make a temporary buffer for it:
void bar(int *pi, size_t n) {
/* do something */
}
foo(const int *pi, size_t n) {
int *buf = malloc(sizeof(int) * n);
memcpy(buf, pi, sizeof(int) * n);
bar(buf, n);
free(buf);
}

Call a c function with a const matrix argument using a const cast

I am trying to call a c function with a const matrix argument using a const cast, but can't find the syntax that stops the gcc compiler complaining. The code below compiles without complaining if all "const " casts are removed. The quesion is similar to C function const multidimensional-array argument strange warning but no fully satisfactory solution was offered there. In the following code, if the first call to g() works, then the second call to g() should also work, since it is syntactically identical. But it does not. The second version of g() is preferred, because it does not require knowing in advance the type of the matrix.
/* file t.c */
void f(const int a[2]) {/*empty*/}
void g(const int b[2][2]) {/*empty*/}
int main()
{
int a[2];
int b[2][2];
f((const int (*)) a); /* ok */
f((const typeof(&a[0])) a); /* ok */
g((const int (*)[2]) b); /* ok */
g((const typeof(&b[0])) b); /* compiler complains */
}
$ gcc -o t t.c
t.c: In function ‘main’:
t.c:13:2: warning: passing argument 1 of ‘g’ from incompatible pointer type [enabled by default]
g((const typeof(&b[0])) b); /* compiler complains */
^
t.c:3:10: note: expected ‘const int (*)[2]’ but argument is of type ‘int (*)[2]’
void g(const int b[2][2]) {/*empty*/}
Yes, this lack of possibility to call a function with const 2D arrays with a non-const argument is really a defect in the C specification.
To move around it remember that
void g(const int b[2][2]) {/*empty*/}
is rewritten as
void g(const int (*b)[2]) {/*empty*/}
so this shows you how you'd have to convert, to a const int (*)[2], that is a pointer to an array of 2 double.
g( (const int (*)[2])b );
The const in the declaration header means that the function cannot change the contents of the argument. It is an information to the caller(compiler) and programmer. So there is no reason to make a const typecast then calling the function. It is totally superfluous.

ISO C Void * and Function Pointers

While following some tutorials and reading about function pointers I learned that evidently assigning a void pointer to a function pointer in ISO C is undefined, is there any way to resolve the warning I receive during compile time (e.g. a better way of coding it) or should I just ignore it?
Warning:
ISO C forbids assignment between function pointer and 'void *' [-pedantic]
Example Code:
void *(*funcPtr)();
funcPtr = GetPointer();
GetPointer is a function that returns a void pointer E.G.
void *GetPointer();
In tlpi-book I found this trick very interesting:
#include <dlfcn.h>
int
main(int argc, char *argv[])
{
...
void (*funcp)(void); /* Pointer to function with no arguments */
...
*(void **) (&funcp) = dlsym(libHandle, argv[2]);
}
No. The compiler is right, and you too: in C89 and C99, you can't convert between data pointers (which void * is) and function pointers, so the only way for resolving the warning is returning a function pointer from the function.
(Note, however, that in practice this works despite the warning, and even there's this inconsistency in the standard library - the dlsym() function is used for obtaining function pointers, but it returns void * - so essentially you can ignore the warning. It will work, although strictly speaking the behavior is undefined here.)
I encountered this problem using glib. Glib data structures, such as GSList usually have a field called void *data. I wanted to store functions in a list and got a bunch of errors similar to this:
warning: ISO C forbids passing argument 2 of ‘g_slist_append’ between function pointer and ‘void *’ [-pedantic]
This example generates a bunch of warnings using gcc -Wall -ansi -pedantic
typedef int (* func) (int);
int mult2(int x)
{
return x + x;
}
int main(int argc, char *argv[])
{
GSList *functions = NULL;
func f;
functions = g_slist_append(functions, mult2);
f = (func *) functions->data;
printf("%d\n", f(10));
return 0;
}
So I wrapped the function in a struct and all the warnings go away:
struct funcstruct {
int (* func) (int);
};
int mult2(int x)
{
return x + x;
}
int main(int argc, char *argv[])
{
GSList *functions = NULL;
struct funcstruct p;
p.func = mult2;
functions = g_slist_append(functions, &p);
p = * (struct funcstruct *) functions->data;
printf("%d\n", p.func(10));
return 0;
}
It's arguable that this is quite a bit of extra code to make a few warnings disappear, but I don't like my code to generate warnings. Also, the above are toy examples. In the real code I'm writing, it turns out to be quite useful to wrap the list of functions in a struct.
I'd be interested to hear if this is problematic or if there's a better way of doing it.

Problem compiling K&R example

I'm having trouble compiling the example program presented in section 5.11 of the book. I have removed most of the code and left only the relevant stuff.
#define MAXLINES 5000
char *lineptr[MAXLINES];
void qsort1(void *lineptr[], int left, int right, int (*comp)(void *, void *));
int numcmp(char *, char *);
main(int argc, char *argv[]) {
int numeric = 1;
/* ... */
qsort1((void**) lineptr, 0, 100, (int (*)(void*, void*))(numeric ? numcmp : strcmp));
}
void qsort1(void *v[], int left, int right, int (*comp)(void *, void *)) {
/* ... */
}
int numcmp(char *s1, char *s2) {
/* ... */
}
The problem is that the code doesn't compile (I'm using Digital Mars compiler). The error I get is this:
qsort1((void**) lineptr, 0, nlines - 1, (int (*)(void*, void*))(numeric
? numcmp : strcmp));
^
go.c(19) : Error: need explicit cast to convert
from: int (*C func)(char const *,char const *)
to : int (*C func)(char *,char *)
--- errorlevel 1
There must be something wrong with the declarations although I pasted the code from the book correctly. I don't know enough to make the right changes (the section about the function pointers could certainly have been written more extensively).
EDIT: I should have mentioned that I'm reading the ANSI version of the book.
I think the error comes from the fact that old C did not know const yet: strcmp there took two pointers to non-const characters (char *) i think (which could be the reason why it compiled back then, but not with your compiler). However, nowadays strcmp takes char const* (const char* is the same thing). Change your function prototype to this:
int numcmp(char const*, char const*);
That's a common problem :)
The following line tells qsort to expect a pointer to a function with two void* parameters. Unfortunately, strcmp takes two non-modifiable strings hence it's signature is
int (*comp)(const char*, const char*)
instead of what you have:
int (*comp)(void *, void *)
Change the signature of both qsort1 and numeric:
qsort1(void *v[], int left, int right, int (*comp)(const void *, const void *))
and:
int numcmp(const char*, const char*)
The standard function pointer expected by qsort() or bsearch() has the prototype:
int comparator(const void *v1, const void *v2);
The qsort1() defined in the code expects:
int comparator(void *v1, void *v2);
The comparator functions defined in the code do not have that prototype, and there is no automatic conversion between different function pointer types.
So, fixes for qsort1() are either:
Introduce a cast: (int (*)(void *, void *)), or
Rewrite the comparators:
int numcmp(void *v1, void *v2)
{
char *s1 = v1;
char *s2 = v2;
...
}
int str_cmp(void *v1, void *v2) // Note new function name!
{
return(strcmp(v1, v2));
}
Obviously, the call to qsort1() would reference str_cmp instead of strcmp. The authors sought to avoid an intermediate function, but run foul of the (legitimately) fussier compilers in use nowadays.
The standard version of qsort() would require a bunch of const qualifiers, as in the first version of this answer.
Note that strcmp takes two const arguments, whereas your numcmp does not. Therefore, the two functions' types do not match, and the ? : operator will complain.
Do one of:
change numcmp to match the strcmp prototype in terms of constness
push the (int (*)(void*, void*)) cast inside the ? :, e.g.
numeric ? (int (*)(void*, void*))numcmp : (int (*)(void*, void*))strcmp
Its been awhile since I have done any pure C programming, I'm not certain on the new standard.
However casting to void ** creates a pointer to a pointer where the function requires a pointer to an array. Sure, they are the same thing internally, but strong typechecking will catch that as an error.
rewrite the qsort to accept ** instead of *[] and you should be ok.

Resources