strstr crashes on NULL

L

linq936

Hi,
I have the following code:

#include <stdio.h>

int main(void){
char* str1 = "abc";
char* str2 = '\0';
if ( strstr(str1, str2) == NULL ){
printf("yes\n");
}
else{
printf("no\n");
}

return 0;
}

It crashes on strstr() call, so is it because none of strstr()
parameter can be NULL?
 
W

Walter Roberson

I have the following code:
#include <stdio.h>
int main(void){
char* str1 = "abc";
char* str2 = '\0';
if ( strstr(str1, str2) == NULL ){
printf("yes\n");
}
else{
printf("no\n");
}

return 0;
}
It crashes on strstr() call, so is it because none of strstr()
parameter can be NULL?

Right. Your char* str2 = '\0' is setting str2 to a NULL pointer
instead of to an empty string, which would be "" or "\0";
'\0' happens to be an integral constant with value 0 and so is
a valid NULL pointer initializer (if strange). In C89 at least,
strstr() is not defined for the case of a NULL pointer
(but is defined for the case of a pointer to an empty string.)
 
P

pete

Hi,
I have the following code:

#include <stdio.h>

You're missing:
#include said:
int main(void){
char* str1 = "abc";
char* str2 = '\0';

That's a bad way to write
char* str2 = NULL;

If you change that to
char* str2 = "";
then you can output "no".
if ( strstr(str1, str2) == NULL ){
printf("yes\n");
}
else{
printf("no\n");
}

return 0;
}

It crashes on strstr() call, so is it because none of strstr()
parameter can be NULL?

Yes.
 
K

Keith Thompson

I have the following code:

#include <stdio.h>

int main(void){
char* str1 = "abc";
char* str2 = '\0';
if ( strstr(str1, str2) == NULL ){
printf("yes\n");
}
else{
printf("no\n");
}

return 0;
}

It crashes on strstr() call, so is it because none of strstr()
parameter can be NULL?

Yes. You may also be confused about the various meanings of "null".

In your declaration

char *str2 = '\0';

you're not setting str2 to point to an empty string; you're setting it
to a null pointer, which doesn't point to anything. If you wanted
str2 to point to a empty string, you could have declared:

char *str2 = "";

Normally the character constant '\0' is used to refer to a null
character, the character whose value is zero (sometimes called NUL
with one 'L'). This is the character used to mark the end of a
string.

But as it happens, the character constant '\0' is exactly equivalent
to the integer constant 0, and in this context it indicates a null
pointer, not a null character. Using '\0' in this context isn't
exactly wrong (the compiler is perfectly happy with it), but it's
misleading. If you want a null pointer, it's better to use the NULL
macro.

So, you can either declare:

char *str1 = "abc";
char *str2 = NULL;

(but then passing str2 to strstr invokes undefined behavior), or you
can declare:

char *str1 = "abc";
char *str2 = "";

In that case, strstr(str1, str2) will return the value of str1.

I suggest you take a look at sections 4, 5, and 6 of the comp.lang.c
FAQ, <http://www.c-faq.com/>.

You also need to add a '#include <string.h>' to your program, since
you're calling the strstr function. It may happen to work without it,
but the #include directive is *not* optional. (A note to my fellow
pedants: yes, he could declare strstr himself, but that would be
silly.)
 
L

linq936

Yes. You may also be confused about the various meanings of "null".

In your declaration

char *str2 = '\0';

you're not setting str2 to point to an empty string; you're setting it
to a null pointer, which doesn't point to anything. If you wanted
str2 to point to a empty string, you could have declared:

char *str2 = "";

Normally the character constant '\0' is used to refer to a null
character, the character whose value is zero (sometimes called NUL
with one 'L'). This is the character used to mark the end of a
string.

But as it happens, the character constant '\0' is exactly equivalent
to the integer constant 0, and in this context it indicates a null
pointer, not a null character. Using '\0' in this context isn't
exactly wrong (the compiler is perfectly happy with it), but it's
misleading. If you want a null pointer, it's better to use the NULL
macro.

So, you can either declare:

char *str1 = "abc";
char *str2 = NULL;

(but then passing str2 to strstr invokes undefined behavior), or you
can declare:

char *str1 = "abc";
char *str2 = "";

In that case, strstr(str1, str2) will return the value of str1.

I suggest you take a look at sections 4, 5, and 6 of the comp.lang.c
FAQ, <http://www.c-faq.com/>.

You also need to add a '#include <string.h>' to your program, since
you're calling the strstr function. It may happen to work without it,
but the #include directive is *not* optional. (A note to my fellow
pedants: yes, he could declare strstr himself, but that would be
silly.)

--
Keith Thompson (The_Other_Keith) (e-mail address removed) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Thanks.

My intention is that I use '\0' to initialize a string so that later I
can know its state. How about this code:

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

int main(void){
char str1[10], str2[10];

memset( str1, '\0', 10);
memset( str2, '\0', 10);

strcpy(str1, "abc");
if ( strstr(str1, str2) == NULL ){
printf("yes");
}
else{
printf("no");
}

return 0;
}

This code works fine on the same machine with same compiler, of
course I see "no". I tried commenting out string.h include, it still
works.

So does this mean it is really an un-expected behavior?
 
R

Richard Heathfield

(e-mail address removed) said:

My intention is that I use '\0' to initialize a string so that later I
can know its state.

An empty string is very different to a null pointer.

const char *nullpointer = '\0';
const char *emptystring = "\0";

or, equivalently: const char *emptystring = "";
How about this code:

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

int main(void){
char str1[10], str2[10];

memset( str1, '\0', 10);
memset( str2, '\0', 10);

That's fine, but this works just as well:

char str1[10] = "", str2[10] = "";
strcpy(str1, "abc");
if ( strstr(str1, str2) == NULL ){

Yes, that's fine now.
This code works fine on the same machine with same compiler, of
course I see "no".

Yes - strstr is defined to return str1 if str2 is an empty string.
I tried commenting out string.h include, it still
works.

It is true that the program may give the appearance of continuing to
work when you chop off important bits, in much the same way that a used
car continues to work (for a while) with sand in the carburettor.
So does this mean it is really an un-expected behavior?

The code you posted this time is fine. Perfectly well-defined.
 
S

santosh

Yes. You may also be confused about the various meanings of "null".

In your declaration

char *str2 = '\0';

you're not setting str2 to point to an empty string; you're setting it
to a null pointer, which doesn't point to anything. If you wanted
str2 to point to a empty string, you could have declared:

char *str2 = "";

Normally the character constant '\0' is used to refer to a null
character, the character whose value is zero (sometimes called NUL
with one 'L'). This is the character used to mark the end of a
string.

But as it happens, the character constant '\0' is exactly equivalent
to the integer constant 0, and in this context it indicates a null
pointer, not a null character. Using '\0' in this context isn't
exactly wrong (the compiler is perfectly happy with it), but it's
misleading. If you want a null pointer, it's better to use the NULL
macro.

So, you can either declare:

char *str1 = "abc";
char *str2 = NULL;

(but then passing str2 to strstr invokes undefined behavior), or you
can declare:

char *str1 = "abc";
char *str2 = "";

In that case, strstr(str1, str2) will return the value of str1.

I suggest you take a look at sections 4, 5, and 6 of the comp.lang.c
FAQ, <http://www.c-faq.com/>.

You also need to add a '#include <string.h>' to your program, since
you're calling the strstr function. It may happen to work without it,
but the #include directive is *not* optional. (A note to my fellow
pedants: yes, he could declare strstr himself, but that would be
silly.)

Thanks.

My intention is that I use '\0' to initialize a string so that later I
can know its state. How about this code:

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

int main(void){
char str1[10], str2[10];

memset( str1, '\0', 10);
memset( str2, '\0', 10);

Well, just initialising str1 and str2 with 0 would do.
strcpy(str1, "abc");
if ( strstr(str1, str2) == NULL ){
printf("yes");

Unless you terminate the string supplied to printf with a newline
character, '\n', or call fflush(stdout), your output is not guaranteed
to appear immediately
}
else{
printf("no");
}

return 0;
}

This code works fine on the same machine with same compiler, of
course I see "no". I tried commenting out string.h include, it still
works.

So does this mean it is really an un-expected behavior?

If you do not provide the correct declaration for the functions that
you call, (in this case by including string.h), you invoke undefined
behaviour. When you invoke undefined behaviour, anything is possible,
including seemingly expected behaviour.

Your compiler should warn about missing prototypes for memset, strcpy
and strstr. If it does not, then read it's documentation to find out
the command line switches you can use to set it to the maximum
diagnostic level. It's very useful when learning C or first developing
a program. For gcc I use the '-Wall', '-Wextra', '-ansi' and '-
pedantic' switches. If you want C99 features, (partial), you can use '-
std=c99' instead of '-ansi'.
 
K

Keith Thompson

santosh said:
(e-mail address removed) wrote: [...]
strcpy(str1, "abc");
if ( strstr(str1, str2) == NULL ){
printf("yes");

Unless you terminate the string supplied to printf with a newline
character, '\n', or call fflush(stdout), your output is not guaranteed
to appear immediately
[...]

Actually, it's not guaranteed to appear *at all* unless the last
character you write to stdout is a new-line. It's
implementation-defined whether a text stream must end in a new-line.
The standard doesn't say what happens if a text stream does require a
trailing new-line and you don't provide one, so the behavior is
undefined; you might get no output at all, or demons might fly out of
your nose.

This is another of those things that will *probably* work just the way
you expect it to (the program will print "yes" or "no" without a
new-line), but if you write it correctly in the first place, you don't
have to worry about it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top