patterncModerate
Determine if one string occurs at the end of another
Viewed 0 times
theoneanotherdetermineendoccursstring
Problem
Exercise 5-4
Write the function
Write the function
strend(s,t), which returns one if the string t occurs at the end of the string s, and zero otherwise.#include
int str_end(const char *, const char*);
int main(void)
{
char *s1 = "Man is a rope stretched over an abyss.";
char *s2 = "an abyss.";
printf("%s\n", str_end(s1, s2) ? "Yes" : "No");
return 0;
}
int str_end(const char *s, const char *t)
{
const char *init = t; /* Hold the initial position of *t */
while (*s) {
while (*s == *t) {
if (!(*s)) {
return 1;
}
s++;
t++;
}
s++;
t = init;
}
return 0;
}Solution
A few notes:
-
Analyzing your code, I see a simple bug that isn't accounted for. Consider the following case:
Your method still returns
-
You are somewhat approaching this inefficiently. You are comparing all of the characters in the string. You don't need to do this, we can just compare at the index
-
You could shorten your while loop a bit.
Increment
-
You could also forgo the
-
You wouldn't need the function prototype if you define your
-
What if you pass an invalid string to your function? Right now it can't handle it and will throw a "Segmentation fault". That's not any fun, so let's implement a simple test to check for that.
Based on the discussion between @RolandIllig and myself, I have decided to not implement this check. Why? Because this is a runtime check that comes with a certain overhead time to process. That time may not be much, but on certain systems (such as embedded ones) that processing power would be better used somewhere else. Therefore, I decided to follow the philosophy behind the design of the C standard library: that the programmer is ultimately in the best position to know whether a runtime check really needs to be performed.
-
I'm not sure how you want to handle empty strings. I'm not going to mess with that too much since there was nothing stating so in the exercise.
-
You should document all of your code. Even for a simple function such as this.
Final Product
Tests and Benchmarking
Here are a few trial runs I did of the method, and their output. All seems well by the tests.
-
-
-
-
-
-
Using a benchmarking program I wrote to profile the code, I tested your function as well as the others supplied against mine. Here are the results, averaged out over 100000000 test iterations:
As you can see, my function runs a tiny bit faster than yours and the other functions supplied here (watch the scientific notation).
-
Analyzing your code, I see a simple bug that isn't accounted for. Consider the following case:
char *s1 = "Man is a rope stretched over an abyss.";
char *s2 = "an abyss..c9f0c50bc2e417b078e3b0bf82d5386d418cfba4";Your method still returns
1 even though it clearly shouldn't, because you only checked for \0 in s and not in t. You need to check if the NULL terminators are in matching positions. Also, s2 is clearly a larger string than s1, we never compared the lengths to see if s2 could even fit into s1.-
You are somewhat approaching this inefficiently. You are comparing all of the characters in the string. You don't need to do this, we can just compare at the index
strlen(s) - strlen(t).-
You could shorten your while loop a bit.
while (*s == *t) {
if (!(*s)) {
return 1;
}
s++;
t++;
}Increment
s and t inside of your while test conditional.-
You could also forgo the
while loop completely and use the standard function strncmp(). However, I would use memcmp() since it is faster.-
You wouldn't need the function prototype if you define your
strend() function before you define main().-
What if you pass an invalid string to your function? Right now it can't handle it and will throw a "Segmentation fault". That's not any fun, so let's implement a simple test to check for that.
if (!s || !t) return 0;Based on the discussion between @RolandIllig and myself, I have decided to not implement this check. Why? Because this is a runtime check that comes with a certain overhead time to process. That time may not be much, but on certain systems (such as embedded ones) that processing power would be better used somewhere else. Therefore, I decided to follow the philosophy behind the design of the C standard library: that the programmer is ultimately in the best position to know whether a runtime check really needs to be performed.
-
I'm not sure how you want to handle empty strings. I'm not going to mess with that too much since there was nothing stating so in the exercise.
-
You should document all of your code. Even for a simple function such as this.
Final Product
#include // strlen(), memcmp()
/**
* @fn int strend(const char *s, const char *t)
* @brief Searches the end of string s for string t
* @param s the string to be searched
* @param t the substring to locate at the end of string s
* @return one if the string t occurs at the end of the string s, and zero otherwise
*/
int strend(const char *s, const char *t)
{
size_t ls = strlen(s); // find length of s
size_t lt = strlen(t); // find length of t
if (ls >= lt) // check if t can fit in s
{
// point s to where t should start and compare the strings from there
return (0 == memcmp(t, s + (ls - lt), lt));
}
return 0; // t was longer than s
}Tests and Benchmarking
Here are a few trial runs I did of the method, and their output. All seems well by the tests.
-
strend("Man is a rope stretched over an abyss.", "an abyss..c9f0c"); returns 0.-
strend("Man is a rope stretched over an abyss.", "an abyss"); returns 0.-
strend("Man is a rope stretched over an abyss.", "an abyss."); returns 1.-
strend("Man is an man man.", "an man."); returns 1.-
strend("an abyssan abyssan abyssan abyss.", "an abyss."); returns 1.-
strend(NULL, NULL); returns 0.Using a benchmarking program I wrote to profile the code, I tested your function as well as the others supplied against mine. Here are the results, averaged out over 100000000 test iterations:
Search string: simple
End string: le
syb0rg's function average runtime: 1.47728e-08 seconds
ao2130's function average runtime: 1.87163e-08 seconds
Edward's function average runtime: 2.29287e-08 seconds
Josay's function average runtime: 2.58304e-08 seconds
Search string: this is a test
End string: test
syb0rg's function average runtime: 1.81173e-08 seconds
ao2130's function average runtime: 4.7522e-08 seconds
Edward's function average runtime: 2.31506e-08 seconds
Josay's function average runtime: 4.62652e-08 seconds
Search string: this is a longer string and may cause certain functions to take a bit longer to process
End string: a bit longer to process
syb0rg's function average runtime: 3.17312e-08 seconds
ao2130's function average runtime: 2.44403e-07 seconds
Edward's function average runtime: 3.33028e-08 seconds
Josay's function average runtime: 3.25736e-07 seconds
As you can see, my function runs a tiny bit faster than yours and the other functions supplied here (watch the scientific notation).
Code Snippets
char *s1 = "Man is a rope stretched over an abyss.";
char *s2 = "an abyss..c9f0c50bc2e417b078e3b0bf82d5386d418cfba4";while (*s == *t) {
if (!(*s)) {
return 1;
}
s++;
t++;
}if (!s || !t) return 0;#include <string.h> // strlen(), memcmp()
/**
* @fn int strend(const char *s, const char *t)
* @brief Searches the end of string s for string t
* @param s the string to be searched
* @param t the substring to locate at the end of string s
* @return one if the string t occurs at the end of the string s, and zero otherwise
*/
int strend(const char *s, const char *t)
{
size_t ls = strlen(s); // find length of s
size_t lt = strlen(t); // find length of t
if (ls >= lt) // check if t can fit in s
{
// point s to where t should start and compare the strings from there
return (0 == memcmp(t, s + (ls - lt), lt));
}
return 0; // t was longer than s
}Context
StackExchange Code Review Q#54722, answer score: 19
Revisions (0)
No revisions yet.