Определения, если одна строка встречается в конце другой


Это упражнение 5-4 от К&Р. Я провел часы дорабатываю его, но сейчас, кажется, работает. Я новичок в указатели, и я приветствую любые комментарии о том, как это лучше сделать.

/* Function strend(s, t), which returns 1 if the string t 
 * occurs at the end of string s and zero otherwise */
int strend(const char *s, const char *t)
{   
    const char *s0, *t0;

    if (s == 0) {
        printf("s is NULL pointer\n");
        return (-1);
    }
    if (t == 0) {
        printf("t is NULL pointer\n");
        return (-1);
    }
    s0 = s;
    t0 = t;

    while (*s++)
        ;
    s -= 2;         /* *s points to last real char in s */

    while (*t++)
        ;
    t -= 2;         /* *t points to last real char in t */

    if ((t-t0) > (s-s0))
            return (0);  /* t is longer than s */

    while (t>=t0) {
        if (*s-- != *t--) 
            return (0);  /* Mismatch */
    }

    return (1); /* Match */
}

Здесь главная():

/* Test the function strend(s, t), which returns 1 if the string t 
 * occurs at the end of string s and zero otherwise */
#include "jim.h"
#include "subs.c"

char a[MAXLINE], b[MAXLINE];

int main (void)

{
    printf("Return = %1d, Expect = 1\n", strend("12345", "45"));
    printf("Return = %1d, Expect = 0\n", strend("12345", "35"));
    printf("Return = %1d, Expect = 0\n", strend("45", "345"));
    printf("Return = %1d, Expect = 1\n", strend("12345", "12345"));
    printf("Return = %1d, Expect = 1\n", strend("12345", "5"));
    printf("Return = %1d, Expect = 0\n", strend("12345", "4"));
    printf("Return = %1d, Expect = 1\n", strend("12345", ""));
    printf("Return = %1d, Expect = 0\n", strend("12345", "+"));
    printf("Return = %1d, Expect = 0\n", strend("12345", "a2345"));
    printf("Return = %1d, Expect = 1\n", strend("", ""));
    printf("Return = %1d, Expect = 0\n", strend("", "Z"));
    printf("Return = %1d, Expect = 1\n", strend("1", "1"));
    printf("Return = %1d, Expect = 0\n", strend("1", "1A"));
    printf("Return = %1d, Expect = -1\n", strend(0, "1A"));
    printf("Return = %1d, Expect = -1\n", strend("1", 0));
}

Вот вывод:

Return = 1, Expect = 1
Return = 0, Expect = 0
Return = 0, Expect = 0
Return = 1, Expect = 1
Return = 1, Expect = 1
Return = 0, Expect = 0
Return = 1, Expect = 1
Return = 0, Expect = 0
Return = 0, Expect = 0
Return = 1, Expect = 1
Return = 0, Expect = 0
Return = 1, Expect = 1
Return = 0, Expect = 0
s is NULL pointer
Return = -1, Expect = -1
t is NULL pointer
Return = -1, Expect = -1


453
7
задан 19 мая 2011 в 08:05 Источник Поделиться
Комментарии
3 ответа

Константный правильные указатели. Функция не меняя ничего в памяти, никаких причин, они не должны быть константными. То же самое с переменными, объявленными в функции; сделать их константными

int strend(const char* s, const char* t)

Проверить на null во входном указатели.

Использовать строковые функции библиотеки, где это возможно.
Вместо того, чтобы делать:

while(*s++) ;
s-=2;

вызов функция strlen(ы); а затем вычесть 1 в алго. Поскольку вы все равно перебирать струны замена этого при вызове функции имеет ту же эффективность и делает его более читаемым.

Добавить { во время цикла. Это на будущее.

Блок-тест для подтверждения правильности.

6
ответ дан 19 мая 2011 в 09:05 Источник Поделиться

Похоже, это может быть намного короче....

/* Function strend(s, t), which returns 1 if the string t 
* occurs at the end of string s and zero otherwise */
int strend(const char *s, const char *t)
{
size_t slen, tlen;

if (!s || !t)
return -1;

slen = strlen(s);
tlen = strlen(t);

/* Is t longer than s? */
if (tlen > slen)
return 0;

/* Compare the strings... */
return !strcmp(s + slen - tlen, t);
}

А я все в пользу ума в стиле C указатель арифметические циклы, когда они имеют смысл, я не думаю, что он действительно получает вам много reinvert функция strlen. И делать сравнение в обратную сторону, как-то странно, особенно когда чего strcmp - это вполне разумно. Я имею в виду, вы можете вычислить длины предыдущего прохода... не надо быть таким мачо.

Кроме того, это субъективно, но я не думаю, что имеет смысл возвращать -1 , если значение null передается. Тем более что функция пригоден к использованию в логическое выражение; Если (Стрэнд(нуль, "фу")) будет справедливо, что странно. Может быть, вы должны позволить аварийному завершению программы в этой точке. (Поскольку разыменование null-это ошибка.) Или если это пугает вас, вы можете вернуть 0. (Нулевой указатель нельзя сказать, чтобы суффикса или суффикса, верно?)

Я мог бы также подумать о смене названия. Что-то вроде str_contains_suffix может быть?

3
ответ дан 20 мая 2011 в 03:05 Источник Поделиться

Я бы изменила это больше похоже на...

char* start_of_s = s;
char* start_of_t = t;
if(s == NULL || t==NULL) return 0;
while(*s) s++;
while(*t) t++;
while(*s == *t && s > start_of_s && t> start_of_t)
{
s--; t--;
}
return (t == start_of_t) && (*s == *t);

также модульное тестирование с тестами (и моя), кроме меня звало его "string_is_at_end". Я использую http://code.google.com/p/seatest/ для модульного тестирования. ( в основном потому что я ее написал, хотя у меня есть гораздо более поздней версии, которую я еще не выпустил)

    assert_true(string_is_at_end("12345",""));
assert_true(string_is_at_end("123","23"));
assert_true(string_is_at_end("123","3"));
assert_false(string_is_at_end("","123"));
assert_false(string_is_at_end("123","1"));
assert_false(string_is_at_end("123","2"));
assert_true(string_is_at_end("12345", "45"));
assert_false(string_is_at_end("12345", "35"));
assert_false(string_is_at_end("45", "345"));
assert_true(string_is_at_end("12345", "12345"));
assert_true(string_is_at_end("12345", "5"));
assert_false(string_is_at_end("12345", "4"));
assert_true(string_is_at_end("12345", ""));
assert_false(string_is_at_end("12345", "+"));
assert_false(string_is_at_end("12345", "a2345"));
assert_true(string_is_at_end("", ""));
assert_false(string_is_at_end("", "Z"));
assert_true(string_is_at_end("1", "1"));
assert_false(string_is_at_end("1", "1A"));
assert_false(string_is_at_end(0, "1A"));
assert_false(string_is_at_end("1", 0));

0
ответ дан 20 мая 2011 в 12:05 Источник Поделиться