SIGBART в коде C с malloc / free - PullRequest
       18

SIGBART в коде C с malloc / free

0 голосов
/ 23 февраля 2012

Я написал эту небольшую программу, чтобы найти все вхождения подстроки в большую строку или иглу в стоге сена . Когда я запускаю программу локально, она работает нормально. Однако, когда я отправляю его на онлайн-конкурс на судейство, он выдает ошибку SIGBART. Я предположил, что это из-за плохого управления памятью, поэтому я удалил вызовы функций free(), но затем я получил ошибку Time Limit Exceeded (но ошибка SIGBART исчезла). Замедляет ли free() вызовы программу? И есть ли утечки в моей программе?

Вот конкурс, о котором я говорил: Игла в стоге сена

Вот код:

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

#define RAW_INPUT_SIZE 10000

#define BOOL unsigned int
#define NO 0
#define YES 1

int main (int argc, char **argv)
{
   int needleLength;
   char *rawNeedle = (char *)malloc(RAW_INPUT_SIZE);
   char *rawHaystack = (char *)malloc(RAW_INPUT_SIZE);
   char *needle; // to be allocated later
   char *haystack; // to be allocated later, but not deallocated
   while (scanf("%i\n%s\n%s", &needleLength, rawNeedle, rawHaystack) != EOF)
   {
      needle = (char *)malloc(needleLength);
      strncpy(needle, rawNeedle, needleLength);
      haystack = strchr(rawHaystack, needle[0]);
      int i = haystack - rawHaystack;
      BOOL matchesFound = NO;
      if (i + needleLength - 1 < strlen(rawHaystack))
      {
         while (haystack != NULL)
         {
            if (i + needleLength - 1 < strlen(rawHaystack))
            {
               char *substr = (char *)malloc(needleLength);
               strncpy(substr, haystack, needleLength);
               if (strcmp(needle, substr) == 0)
               {
                  printf("%i\n", i);
                  matchesFound = YES;
               }
               free(substr);
               substr = NULL;
            }
            haystack = strchr(haystack+1, needle[0]);
            i = haystack - rawHaystack;
         }
      }
      if (matchesFound == NO)
         printf("\n");
      free(needle);
      needle = NULL;
   }
   free(rawNeedle);
   free(rawHaystack);
   rawNeedle = NULL;
   rawHaystack = NULL;
   return 0;
}

Транскрипция спецификации ввода и вывода из вопроса

Input

Входные данные состоят из нескольких контрольных примеров. Каждый тестовый набор состоит из трех строк, содержащих:

  • длина иглы,
  • сама игла,
  • стог сена.

Длина иглы ограничена только объемом памяти, доступной вашей программе, поэтому не делайте никаких предположений - вместо этого считывайте длину и выделяйте память по мере необходимости. Стог сена не ограничен по размеру, что означает, что ваша программа не должна читать весь стог сена сразу. Алгоритм KMP основан на потоке, т. Е. Обрабатывает стог сена символ за символом, поэтому это не проблема.

Контрольные примеры выполняются один за другим, каждая занимает три строки, без дополнительного пробела или разрывов между ними.

выход

Для каждого тестового случая ваша программа должна выводить все положения вхождений иглы в стоге сена. Если совпадение найдено, выходные данные должны содержать позицию первого символа совпадения. Символы в стоге сена нумеруются, начиная с нуля.

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

Ответы [ 3 ]

1 голос
/ 23 февраля 2012

Зачем использовать какое-либо распределение памяти?Если в спецификации указана максимальная длина иглы 10 000, просто используйте локальные массивы:

char needle[RAW_INPUT_SIZE];
char haystack[RAW_INPUT_SIZE];

Прочтите непосредственно в них;не копируйте их вокруг.

char *substr = (char *)malloc(needleLength);
strncpy(substr, haystack, needleLength);
if (strcmp(needle, substr) == 0)

Не ясно, что длина вашей иглы включает в себя завершающий ноль.Следовательно, это не выделяет достаточно места и не гарантирует нулевое завершение, оба из которых могут легко привести к проблемам SIGABRT.

Повторное использование strlen() в вашем стоге сена заставит вашу программу работать медленно.Вы можете рассчитать длину без необходимости делать strlen() более одного раза для каждой иглы и стога сена.

Если вам не гарантировано отсутствие пробелов в данных, ваш код scanf() будет читать меньше, чем вы ожидаете,Вы всегда должны проверять, что вы получаете все ожидаемые значения.

Вам следует поискать функцию strstr().

1 голос
/ 23 февраля 2012

Я не уверен, является ли это прямой причиной вашей проблемы, но одна очевидная проблема заключается в том, что вы не используете strncpy правильно.strncpy не обязательно означает NUL-конец

0 голосов
/ 23 февраля 2012

Вы, вероятно, перезаписываете важную память.

Длина иглы ограничена только объемом памяти, доступной вашей программе, поэтому не делайте никаких предположений - вместо этого считывайте длину и выделяйте память по мере необходимости. Стог сена не ограничен по размеру, что означает, что ваша программа не должна читать весь стог сена сразу. Алгоритм KMP основан на потоке, т. Е. Обрабатывает стог сена символ за символом, поэтому это не проблема.

Вы можете рассчитывать на то, что некоторые входы длиннее 10000 char с. Это означает, что вы используете нераспределенную память с непредсказуемыми последствиями.

Более предсказуемым является то, что - как уже упоминалось Джонатаном Леффлером - ваш substr обычно не будет завершаться 0, поэтому strcmp может возвращать только 0, если за случайностью substr сразу же следует '\ 0' символ, таким образом, вы, вероятно, пропустите вхождения needle в haystack (и, вероятно, закроете стог сена в ходе вашего алгоритма).

А ваш алгоритм - наивный алгоритм (несколько улучшенный сканированием специально для первого символа needle), который, вероятно, слишком медленный:

Однако наивный подход, вероятно, превысит ограничение по времени, тогда как другие алгоритмы более сложны ... Выбор за вами.

Вы должны для каждого теста

  1. прочитайте длину иглы
  2. выделить достаточно места для иглы (включая 0-терминатор)
  3. читайте в игле
  4. чтение в стоге сена кусками, чередование со сканированием для иглы

SPOJ рекомендует использовать алгоритм KMP не без причины. Использование алгоритма Бойера-Мура является хорошей альтернативой, но усложняет обработку совпадений, пересекающих границы фрагментов.

...