Размер иглы в функции strstr

Это простой вопрос, но когда я использую функцию strstr, почему размер иглы должен быть как минимум на один символ больше, чем фактический текст в игле? Это из-за нулевого символа?

Когда я ставлю иглу как иглу [1], она не работает. Почему можно указать точное количество символов для стога сена?

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


int main(void)
{
   const char haystack[21] = "IDontUnderstand?Help!";
   const char needle[2] = "?";
   char *buffer;

   buffer = strstr(haystack, needle);

   printf("The substring is: %s\n", buffer);

   return(0);
}

person Jessup Jong    schedule 26.08.2015    source источник
comment
Строки в стиле C должны заканчиваться '\0', иначе конец не идентифицируется.   -  person Jason    schedule 26.08.2015
comment
Пока вы не изменяете содержимое, используйте const char* needle = "?";. Задача решена.   -  person Karoly Horvath    schedule 26.08.2015
comment
Вместо const char haystack[21] = "IDontUnderstand?Help!"; можно написать const char haystack[] = "IDontUnderstand?Help!";. В последнем случае размер, необходимый для массива, рассчитывается компилятором.   -  person Jabberwocky    schedule 26.08.2015
comment
Примечание: если ваша игла представляет собой один символ, вы можете использовать strchr().   -  person user12205    schedule 26.08.2015


Ответы (3)


Теоретически обе строки должны иметь завершающий нулевой символ в конце ('\0), потому что в противном случае функция не знает, когда прекратить чтение строки:

Возьмите функцию strlen. Он считывает длину строки до нулевого символа и может быть реализован следующим образом:

size_t strlen(const char* str)
{
    size_t len = 0;
    for(; *str; ++str, ++len);
    return (len);
}

Обратите внимание, что условие — *str, что также может означать *str != 0, что показывает, что цикл for увеличивает строку и длину до тех пор, пока не будет найден нулевой символ.

Однако, если нулевой терминатор не указан (например, вы выделили char[5] для "Hello", хотя на самом деле это должно быть char[6] - "Hello\0"), это чистая удача, если используемая вами функция останавливается в конце «привет».

Чтобы сделать это проще, если вы пишете массив символов, вы можете вместо этого не включать число в фигурные скобки и позволить компилятору вывести его для вас, чтобы убедиться, что есть нулевой завершающий символ:

const char haystack[] = "IDontUnderstand?Help!";
const char needle[] = "?";

Обратите внимание, что вы не можете поставить const char haystack[strlen("IDontUnderstand?Help!") + 1] = "IDontUnderstand?Help!";, так как strlen("IDontUnderstand?Help!") + 1 не является постоянным значением.

Однако, если вы хотите динамически выделять память, вы можете использовать strlen, чтобы помочь:

char* get_str_buffer(const char* value)
{
    char* buf = malloc(strlen(value) + 1);
    strcpy(buf, value);
    return (buf);
}

int main(void)
{
    const char *haystack = get_str_buffer("IDontUnderstand?Help!");
    const char *needle = get_str_buffer("?");
    char *buffer;

    buffer = strstr(haystack, needle);
    printf("The substring is: %s\n", buffer);


    free(haystack);
    free(needle);
    return(0);
}
person Joe    schedule 26.08.2015
comment
Спасибо, что очень помогли! - person Jessup Jong; 08.09.2015

почему размер иглы должен быть как минимум на один символ больше, чем фактический текст в игле? Это из-за нулевого символа?

Да, именно из-за null character. Если вы видите формат strstr(), то это -

char *strstr(const char *haystack, const char *needle)

Нужны аргументы -

haystack -This is the main C string to be scanned.

needle -This is the small string to be searched with-in haystack string.

Поскольку needle — это короткая строка, для ее завершения требуется '\0'.

person ameyCU    schedule 26.08.2015

Для стога сена тоже не годится. Вам действительно нужно место для завершающего байта NULL, чтобы функции знали, где заканчивается строка. В противном случае они будут продолжать читать память, пока не обнаружат там NUL.

Если вы пропустите лишний символ из haystack, поиск иглы "f" может фактически вернуть результат, все зависит от того, что содержится в памяти.

Это одна из причин, почему лучше использовать const char* для хранения строковых литералов. Используйте массивы только при создании значений в коде.

person Zastai    schedule 26.08.2015
comment
Чтение за конец массива является поведением undefined. Это может проявляться так, как вы описали, но говорить, что это произойдет, неправильно. - person Karoly Horvath; 26.08.2015
comment
Истинный. В зависимости от установленной защиты памяти он также может немедленно дать сбой. Или он может выйти из строя несколькими творческими способами. - person Zastai; 26.08.2015