2017-01-22 4 views
0

Я новичок в C, поэтому я немного поиграл с ним и придумал эту функцию поиска, которую планирую перейти на функцию поиска и замены. Я уверен, что это работает, так как я тестировал его с кучей входов и всегда получал соответствующее количество «Word found!». печать.Эта функция поиска выглядит хорошо?

void searchString() { 
    char message[] = "This is a test message test test"; 
    char wordToFind[] = "message"; 

    int i = 0; 
    for (i = 0; i < sizeof(message) - 1; i++) { 
     if (message[i] == wordToFind[0]) { 
      int i2 = 0; 
      for (i2 = 1; i2 < sizeof(wordToFind) - 1; i2++) { 
       if (message[i + i2] != wordToFind[i2]) { 
        i++; 
        break; 
       } 
       if (i2 == sizeof(wordToFind) - 2) { 
        printf("Word found!\n"); 
        break; 
       } 
      } 
     } 
    } 
} 

Вопрос в том, эффективен ли это или есть ли лучший способ сделать это в C?

+0

Первое впечатление, что есть * способ * слишком много уровней отступа. Как правило, если у вас более трех, перепишите код. Также обратите внимание, что 'sizeof' даст неожиданные результаты, если, скажем, передал указатель. Я думаю, вы имеете в виду 'strlen'. –

+0

Спасибо, я смотрел на нее и думал то же самое. Я чувствую, что могу найти способ покончить со вторым за цикл. – Genthorn

+0

Ах, просто прочитайте на strlen(), и это выглядит намного больше, чем то, что я хотел использовать – Genthorn

ответ

1

Есть несколько проблем в вашей функции:

  • При обнаружении несоответствия, вы увеличиваете i два раза, следовательно, вы не нашли бы message в This is a test mmessage test test.
  • Вы произвольно кодируете длины строк. Использование sizeof() возможно только для строк, известных во время компиляции, поэтому ваша функция вообще не является общей. Вместо этого вы должны написать функцию, которая принимает 2 указателя на строки C и использует strlen() экономно или проверяет наличие нулевых терминаторов в циклах.

Вот модифицированная версия, которая является более общим:

void searchString(const char *message, const char *wordToFind) { 

    int i = 0; 
    for (i = 0; message[i] != '\0'; i++) { 
     if (message[i] == wordToFind[0]) { 
      int i2 = 0; 
      for (i2 = 1; wordToFind[i2] != '\0'; i2++) { 
       if (message[i + i2] != wordToFind[i2]) { 
        break; 
       } 
      } 
      if (wordToFind[i2] == '\0') { 
       printf("Word found at offset %d\n", i); 
      } 
     } 
    } 
} 

Примечания:

  • ваша функция не обрабатывает специальный случай пустой wordToFind[].
  • Что касается эффективности, вероятно, было бы более эффективно использовать стандартную библиотечную функцию strstr(), поскольку она может быть реализована очень эффективным образом.

Вот альтернатива с strstr():

void searchString(const char *message, const char *wordToFind) { 
    for (const char *p = message; (p = strstr(p, wordToFind)) != NULL; p++) { 
     printf("Word found at offset %d\n", (int)(p - message)); 
     if (*p == '\0') { /* handle special case of empty wordToFind */ 
      break; 
     } 
    } 
} 
+2

Стоит отметить, что 'strlen' не находит длину по магии. Он должен сканировать каждый символ, чтобы найти конечный нуль. Какой алгоритм O (n). Если вы повторяете каждый символ и вызываете 'strlen()' каждую итерацию, то у вас есть алгоритм O (n^2). То, что chqrlie сделал, проверяя, что конечный нуль намного лучше. Если n и m - длина сообщения и wordToFind, его код равен O (nm) при использовании strlen(), каждая итерация будет O (n^2 m^2). (если компилятор достаточно умен, чтобы оптимизировать strlen() как инвариант цикла для вас). – TrentP

+0

@TrentP: Я изменил ответ на вопрос об использовании 'strlen()'. Обратите внимание, что сложность имеет худший случай ** O (nm) **, если «wordToFind» имеет длинный префикс, который соответствует значительной части «сообщения», но средний случай только немного больше, чем ** O (n) **. – chqrlie

Смежные вопросы