[c] Assignment makes pointer from integer without cast

Coming from a Java background I'm learning C, but I find those vague compiler error messages increasingly frustrating. Here's my code:

/*
 * PURPOSE
 *      Do case-insensetive string comparison.
 */
#include <stdio.h>
#include <string.h>
#include <ctype.h>

int compareString(char cString1[], char cString2[]);
char strToLower(char cString[]);

int main() {
    // Declarations
    char cString1[50], cString2[50];
    int isEqual;

    // Input
    puts("Enter string 1: ");
    gets(cString1);
    puts("Enter string 2: ");
    gets(cString2);

    // Call
    isEqual = compareString(cString1, cString2);
    if (isEqual == 0)
        printf("Equal!\n");
    else
        printf("Not equal!\n");

    return 0;
}

// WATCH OUT
//      This method *will* modify its input arrays.
int compareString(char cString1[], char cString2[]) {
    // To lowercase
    cString1 = strToLower(cString1);
    cString2 = strToLower(cString2);

    // Do regular strcmp
    return strcmp(cString1, cString2);
}

// WATCH OUT
//      This method *will* modify its input arrays.
char strToLower(char cString[]) {
    // Declarations
    int iTeller;

    for (iTeller = 0; cString[iTeller] != '\0'; iTeller++)
        cString[iTeller] = (char)tolower(cString[iTeller]);

    return cString;
}

This generates two warnings.

  • assignment makes pointer from integer without a cast
    • cString1 = strToLower(cString1);
    • cString2 = strToLower(cString2);
  • return makes integer from pointer without a cast
    • return cString;

Can someone explain these warnings?

This question is related to c warnings

The answer is


C strings are not anything like Java strings. They're essentially arrays of characters.

You are getting the error because strToLower returns a char. A char is a form of integer in C. You are assigning it into a char[] which is a pointer. Hence "converting integer to pointer".

Your strToLower makes all its changes in place, there is no reason for it to return anything, especially not a char. You should "return" void, or a char*.

On the call to strToLower, there is also no need for assignment, you are essentially just passing the memory address for cString1.

In my experience, Strings in C are the hardest part to learn for anyone coming from Java/C# background back to C. People can get along with memory allocation (since even in Java you often allocate arrays). If your eventual goal is C++ and not C, you may prefer to focus less on C strings, make sure you understand the basics, and just use the C++ string from STL.


strToLower should return a char * instead of a char. Something like this would do.

char *strToLower(char *cString)

You are returning char, and not char*, which is the pointer to the first character of an array.

If you want to return a new character array instead of doing in-place modification, you can ask for an already allocated pointer (char*) as parameter or an uninitialized pointer. In this last case you must allocate the proper number of characters for new string and remember that in C parameters as passed by value ALWAYS, so you must use char** as parameter in the case of array allocated internally by function. Of course, the caller must free that pointer later.


  • 1) Don't use gets! You're introducing a buffer-overflow vulnerability. Use fgets(..., stdin) instead.

  • 2) In strToLower you're returning a char instead of a char-array. Either return char* as Autopulated suggested, or just return void since you're modifying the input anyway. As a result, just write

 

 strToLower(cString1);
 strToLower(cString2);
  • 3) To compare case-insensitive strings, you can use strcasecmp (Linux & Mac) or stricmp (Windows).

strToLower's return type should be char* not char (or it should return nothing at all, since it doesn't re-allocate the string)


You don't need these two assigments:

cString1 = strToLower(cString1); 
cString2 = strToLower(cString2);

you are modifying the strings in place.

Warnings are because you are returning a char, and assigning to a char[] (which is equivalent to char*)


char cString1[]

This is an array, i.e. a pointer to the first element of a range of elements of the same data type. Note you're not passing the array by-value but by-pointer.

char strToLower(...)

However, this returns a char. So your assignment

cString1 = strToLower(cString1);

has different types on each side of the assignment operator .. you're actually assigning a 'char' (sort of integer) to an array, which resolves to a simple pointer. Due to C++'s implicit conversion rules this works, but the result is rubbish and further access to the array causes undefined behaviour.

The solution is to make strToLower return char*.


As others already noted, in one case you are attempting to return cString (which is a char * value in this context - a pointer) from a function that is declared to return a char (which is an integer). In another case you do the reverse: you are assigning a char return value to a char * pointer. This is what triggers the warnings. You certainly need to declare your return values as char *, not as char.

Note BTW that these assignments are in fact constraint violations from the language point of view (i.e. they are "errors"), since it is illegal to mix pointers and integers in C like that (aside from integral constant zero). Your compiler is simply too forgiving in this regard and reports these violations as mere "warnings".

What I also wanted to note is that in several answers you might notice the relatively strange suggestion to return void from your functions, since you are modifying the string in-place. While it will certainly work (since you indeed are modifying the string in-place), there's nothing really wrong with returning the same value from the function. In fact, it is a rather standard practice in C language where applicable (take a look at the standard functions like strcpy and others), since it enables "chaining" of function calls if you choose to use it, and costs virtually nothing if you don't use "chaining".

That said, the assignments in your implementation of compareString look complete superfluous to me (even though they won't break anything). I'd either get rid of them

int compareString(char cString1[], char cString2[]) { 
    // To lowercase 
    strToLower(cString1); 
    strToLower(cString2); 

    // Do regular strcmp 
    return strcmp(cString1, cString2); 
} 

or use "chaining" and do

int compareString(char cString1[], char cString2[]) { 
    return strcmp(strToLower(cString1), strToLower(cString2)); 
} 

(this is when your char * return would come handy). Just keep in mind that such "chained" function calls are sometimes difficult to debug with a step-by-step debugger.

As an additional, unrealted note, I'd say that implementing a string comparison function in such a destructive fashion (it modifies the input strings) might not be the best idea. A non-destructive function would be of a much greater value in my opinion. Instead of performing as explicit conversion of the input strings to a lower case, it is usually a better idea to implement a custom char-by-char case-insensitive string comparison function and use it instead of calling the standard strcmp.