Determine if one string occurs at the end of another Exercise 5-4
  
  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 &lt;stdio.h&gt;

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;
}
A few notes:


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 &lt;string.h&gt;  // 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 &gt;= 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).