3

So, I am learning C language and was trying to make a function that returns the length of a string. In the if statement I mistakenly used "" instead of ''. So, instead of comparing to char '\0' it was comparing to (string) "\0". Something like this

if(*newchar == "\0"){...}

Curiously, the compiler returned
warning: comparison between pointer and integer

Why is "\0" interpreted as an integer by the compiler?

EDIT: Below is my code. Also, my print statement was copied wrong; it is printf("%d","\0"); which outputs a random number every time now that I tested.

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

int stringlen(char *newChar)
{
    char newint = *newChar;
    bool flag = false;
    while (!flag)
    {
        newint = *newChar;
        newChar++;
        printf("%c", newint);
        if (*newChar == "\0")
        {
            flag = true;
        }
    }

    if (flag == true)
    {
        return 1;
    }
    else if (flag == false)
    {
        return 0;
    }
}

int main(void)
{
    char *newChar = "Some string WOOOw";
    int run = stringlen(newChar);
    printf("%c\n", *newChar);
    printf("%d", "\0");
    return 0;
}

And below is the warning that the compiler gives

 warning: comparison between pointer and integer
   13 |         if (*newChar == "\0")

The program compiles, but it prints random symbols.

7
  • Can't reproduce printf("%s","\0"); And by "it returns..." do you mean "it outputs"? Please post a Minimal Reproducible Example, the shortest complete code that shows the problem. Aside: "\0" is the same as "". Commented Sep 8 at 18:19
  • 1
    ""\0" is the same as """ No, the former has type char[2] while the latter has type char[1] Commented Sep 8 at 18:28
  • @dbush so sorry, effectively the same but 5 mins had passed and I thought it too trifling to repost. And those aren't types. They are the same char* type. Commented Sep 8 at 18:33
  • 1
    @WeatherVane: The type of "" is char [1], not char *. It will be converted to char * in some, but not all uses, but it is an array of 1 char, and that is its type. Commented Sep 8 at 18:39
  • 2
    @WeatherVane: No, the type of "" is char [1]. That is a fact. It is clearly specified in the C standard. You may want to construe it as equivalent to char * because it is often automatically converted to that, but it is not the same thing, and teaching students the wrong thing leads to misconceptions we see play out repeatedly in Stack Overflow. "" is not a char *, and saying it it is a false statement that harms learning. “And those aren't types” is a false statement; char [2] and char [1] are types. “They are the same char* type” is a false statement. Commented Sep 8 at 19:42

2 Answers 2

7

Why does the "\0" is interpreted as integer by the compiler?

It's not. It's a string constant with type array of char, and when used in an expression it decays to a pointer to the first element of that array.

Assuming *newchar has an integer type such as int or char, it is this that is being compared with the pointer which is the address of the first element of "\0".

Also, the fact that the warning is stated as "comparison between pointer and integer" doesn't necessarily mean the left hand side is a pointer and the right hand side is an integer. It's just stating what the two types are.

As for this:

printf("%d", "\0")

The %d format specifier expects an int as an argument, but you're instead passing char * (which was converted from a char array as above). Passing a parameter to printf that doesn't match the format specifier triggers undefined behavior. What likely happened was that the pointer value was reinterpreted as an integer, however because this is undefined behavior you can't depend on anything specific happinging.

Sign up to request clarification or add additional context in comments.

7 Comments

Might be worth changing "error message" in your answer to "warning message" as that's what it is in the absence of an option like -Werror.
Good point, updated.
meh, non-fatal error messages are still error messages
"Incipient error messages"
Perhaps it'd be good to mention the difference between string literals and character literals, as in the difference between "\0" and '\0' too?
Detail: C defines 2 literals: compound literals and string literals (like "\0"), but not character literals. C defines '\0' as a character constant.
@chux Ah... My bad. :-)
3

Why does the "\0" is interpreted as integer by the compiler?

You are wrong. The string literal "\0" has array type char[2]. Arrays used in expressions with rare exceptions are implicitly converted to pointers to their initial elements. From the C23 Standard (6.3.2.1 Lvalues, arrays, and function designators):

3 Except when it is the operand of the sizeof operator, or typeof operators, or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

On the other hand, if an object of an integer type used in expressions has a rank less than the rank of the type int (or unsigned int) then it is converted to the type int (or unsigned int ) (the C23 Standard, 6.3.1.1 Boolean, characters, and integers):

2 The following may be used in an expression wherever an int or unsigned int may be used:

— An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to the rank of int and unsigned int.

...

If the original type is not a bit-precise integer type (6.2.5): if an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; 50) otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.

So in the expression with the equality operator in this if statement

 if (*newChar == "\0")

the value of the left operand *newChar having type char is converted to the type int due to the integer promotions while the right operand having array type is converted to a pointer to its initial element. The equality operator is not defined for such types of its operands. So the compiler issues the message.

As for this statement

printf("%d", "\0");

then it invokes undefined behavior because there is used invalid conversion specifier for an object of the type char * (again due to the implicit conversion arrays to pointers to their initial elements).

From the C23 Standard (7.23.6.1 The fprintf function):

9 If a conversion specification is invalid, the behavior is undefined.

You may use either the conversion specifier s if you want to output a string

printf("%s\n", "\0");

or the conversion specifier p if you want to output the address of a string

printf("%p\n", ( void *)"\0");

In any case your function does not make sense. First of all it should be declared like

size_t stringlen( const char *newChar );

The function shall deal only with strings. Thus introducing the variable flag and using this if statement

    else if (flag == false)
    {
        return 0;
    }

are wrong. Otherwise the function will have undefined behavior if the user will pass not a string.

Also your function in any case has undefined behavior if the user will pass an empty string due to this increment of the pointer

        newChar++;  // <===
        printf("%c", newint);
        if (*newChar == "\0")
        {
            flag = true;
        }

2 Comments

Got it thanks for the info. I was playing around with strings and pointers to understand them and had not considered undefined behaviour. Thanks for pointing it out.
No at all. You are welcome.:)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.