Динамическое выделение памяти + усечение строки - PullRequest
2 голосов
/ 06 января 2010

Я дурачился с malloc, realloc и free, чтобы написать некоторые базовые функции для работы со строками C (char *). Я столкнулся с этой странной проблемой при удалении последнего символа из строки. Я написал функцию с таким прототипом:

int string_erase_end (char ** dst, size_t size);

Предполагается, что строка "dst" должна быть сокращена на один символ. До сих пор я придумал этот код:

int string_erase_end (char ** dst, size_t size)
{
    size_t s = strlen(*dst) - size;
    char * tmp = NULL;
    if (s < 0) return (-1);
    if (size == 0) return 0;
    tmp = (char*)malloc(s);
    if (tmp == NULL) return (-1);
    strncpy(tmp,*dst,s);
    free(*dst);
    *dst = (char*)malloc(s+1);
    if (*dst == NULL) return (-1);
    strncpy(*dst,tmp,s);
    *dst[s] = '\0';
    free(tmp);
    return 0;
}

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

У меня нет опыта динамического распределения памяти, и я всегда использовал C ++ и его std :: string для выполнения всей такой грязной работы, но на этот раз мне нужно сделать эту работу в C. Я был бы признателен, если бы кто-то помог мне найти и исправьте мою ошибку (ы) здесь. Заранее спасибо.

Ответы [ 3 ]

2 голосов
/ 06 января 2010

Первый strncpy () не ставит '\ 0' в конце tmp.

Кроме того, вы можете избежать двойной копии: * dst = tmp;

2 голосов
/ 06 января 2010

Согласно вашему описанию ваша функция должна стереть последние n символов в строке:

/* Assumes passed string is zero terminated... */
void string_erase_last_char(char * src, int num_chars_to_erase)
{
    size_t len = strlen(src);

    if (num_chars_to_erase > len)
    {
        num_chars_to_erase = len;
    }

    src[len - num_chars_to_erase] = '\0';
} 
1 голос
/ 06 января 2010

Я не понимаю назначение параметра size.

Если ваши строки изначально выделены с помощью malloc(), вам просто нужно использовать realloc(), чтобы изменить их размер. Это автоматически сохранит содержимое и потребует меньше операций:

int string_erase_end (char ** dst)
{
  size_t len;
  char *ns;

  if (dst == NULL || *dst == NULL)
   return -1;

  len = strlen(*dst);
  if (len == 0)
    return -1;

  ns = realloc(*dst, len - 1);
  if (ns == NULL)
   return -1;
  ns[len - 1] = '\0';
  *dst = ns;

  return 0;
}

В «реальном мире» вы, как правило, не изменили бы выделенный размер для усечения 1 символа; это слишком неэффективно. Вместо этого вы должны отслеживать длину строки и ее выделенный размер отдельно. Это облегчает рост струн; до тех пор, пока уже выделено место, добавление символа очень быстро.

Кроме того, в C вам никогда не нужно приводить возвращаемое значение malloc(); это не имеет смысла и может скрывать ошибки, поэтому не делайте этого.

...