I'm new to these wanderings, sorry if it's a stupid question. but can they enlighten me what what's doing there?
char *ft_strchr(char *s, int c)
{
int i;
i = 0;
if (!s)
return (0);
if (c == '\0')
return ((char *)&s[ft_strlen(s)]); // THIS LINE
while (s[i] != '\0')
{
if (s[i] == (char) c)
return ((char *)&s[i]); // THIS LINE
i ;
}
return (0);
}
I know this is being performed a cast to that variable but I had not yet come apart with this & there in the middle. and to test this function if I take it out of there... it crash.
Someone help me please???
the function is working properly it finds the first occurrence of c in the string and returns the pointer with its position. I just wanted to understand this application better.
CodePudding user response:
Here &
is the pointer-to operator.
With e.g. &s[0]
you get a pointer to the first element of the array s
(which is the same as plain s
). To get a pointer to the character at index i
it's &s[i]
.
To explain more you have to remember that strings in C are really arrays or characters, terminated with the null-terminator character '\0'
.
Such strings are usually represented by pointers to the first character of the string.
For example:
char hello[] = "Hello world"; // An array of 12 characters, including terminator
When you use hello
it decays to a pointer to the first element, i.e. &hello[0]
. When you print it:
printf("%s", hello); // Same as printf("%s", &hello[0])
It will print the whole string: Hello world
.
But you can use a pointer to anywhere in the array as the "first" character of the string, to get only a small part of it. For example &hello[6]
is a pointer to the 'w'
character in the array, basically the start of the second word in the above array. Using that when printing:
printf("%s", &hello[6]);
it will print world
.
On a different note, in the code you show, none of the (char)
and (char *)
casts are needed.
And please be aware of cargo cult programming, which is a rather bad thing.
CodePudding user response:
Regarding why the code is written in this manner/how the function works:
It's a requirement at least from standard C strchr
that the null terminator is considered part of the string. Therefore if the user of the function requests the function to search for the null terminator, it must be handled as a special case.
Basically you have 4 possible, different outcomes:
(normal use)
if (s[i] == (char) c) return ((char *)&s[i]);
The character was found, return a pointer to the found character position. The cast fromint
tochar
is per the requirement of standard Cstrchr
- it behaves like that as well. (And thereby allows to pass stuff likeEOF
.)(normal use)
return (0); }
The character was not found, return NULL.(special case)
if (!s) return (0);
The user passed a null pointer to the function, return NULL. This isn't required by standard Cstrchr
. Since the caller might be perfectly aware they are passing a valid pointer to the function, error checks like this just add extra bloat/branches for nothing. The recommended practice is to place them on the caller side. Naively written library functions are often cluttered with null pointer checks like this.(special case)
if (c == '\0') return ((char *)&s[ft_strlen(s)]);
The user for some reason decided to search for the null terminator. It will always be found at indexstrlen(s)
in the array, so therefore strlen is used for indexing and then a pointer to that location of the null terminator is returned.Also note the subtle distinction between the caller passing something explicitly zero (
'\0'
) and the caller passing anint
which upon conversion tochar
becomes zero. In the latter case, the function will return NULL (not found). That's why there's no cast tochar
atif (c == '\0')
.
Some notes regarding coding style:
- Casting from
char*
tochar*
is nonsense. - Parenthesis at
return (0);
is pointless. - For loops are great for readability:
for(size_t i=0; s[i] != '\0'; i )
.
So it would seem that the function could be rewritten as:
char* ft_strchr (char *s, int c)
{
if(c == '\0')
return &s[strlen(s)];
for(size_t i=0; s[i] != '\0'; i )
{
if(s[i] == (char)c)
{
return &s[i];
}
}
return NULL;
}