Реализация функции копирования строк в C - PullRequest
2 голосов
/ 17 апреля 2011

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

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

char * mycpy(char * d, char * s);

int main() {

  int i;
  char buffer[1];

  mycpy(buffer, "hello world\n");
  printf("%s", buffer);

  return 0;
}

char * mycpy (char * destination, char * source) {

  if (!destination || !source) return NULL;

  char * tmp = destination;

  while (*destination != NULL || *source != NULL) {
    *destination = *source;
    destination++;
    source++;
  }

  return tmp;
}

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

Однако одна вещь, которая меня интересует, это то, как обрабатывается память. Я заметил, что если бы я использовал библиотечную функцию strcpy (), я мог бы скопировать строку из 10 символов в массив символов размера 1. Как это возможно? Функция strcpy () каким-то образом выделяет больше памяти для назначения?

Ответы [ 9 ]

9 голосов
/ 18 апреля 2011

Хороший вопрос для интервью состоит из нескольких слоев, на которых кандидат может продемонстрировать разные уровни понимания.

На уровне синтаксиса 'язык C' следующий код взят из классической книги Кернигана и Ричи ('Язык программирования C'):

while( *dest++ = *src++ )
    ;

В интервью вы действительно могли бы указать, что функция небезопасна, в частности, буфер на *dest недостаточно велик. Кроме того, может иметь место перекрытие, т. Е. Если dest указывает на середину буфера src, у вас будет бесконечный цикл (который в конечном итоге приведет к ошибке доступа к памяти).

2 голосов
/ 17 апреля 2011

Как и в других ответах, вы перезаписываете буфер, поэтому ради теста измените его на:

char buffer[ 12 ];

Для собеседования, на которое они, возможно, надеялись:

char *mycpy( char *s, char *t )
{
    while ( *s++ = *t++ )
    {
        ;
    }
    return s;
}
2 голосов
/ 17 апреля 2011

Нет, дело в том, что strcpy() небезопасен и после него перезаписывает память, я думаю.Вы должны использовать strncpy() вместо.

1 голос
/ 17 апреля 2011

Нет, вы пишете за пределами буфера и перезаписываете (в этом случае) оставшуюся часть стека за пределами буфера. Это очень опасное поведение.

В общем, вы всегда должны создавать методы, которые предоставляют ограничения. В большинстве библиотек C эти методы обозначаются n в имени метода.

0 голосов
/ 11 июня 2016

Версия ниже работает для меня. Я не уверен, если это плохой дизайн, хотя:

while(source[i] != '\0' && (i<= (MAXLINE-1)))
{
dest[i]=source[i];
++i;
}
0 голосов
/ 03 марта 2015
char * mycpy (char * destination, char * source) {

  if (!destination || !source) return NULL;

  char * tmp = destination;

  while (*destination != NULL || *source != NULL) {
    *destination = *source;
    destination++;
    source++;
  }

  return tmp;
}

В приведенной выше реализации копирования ваши tmp и destination имеют одинаковые данные. Лучше, чтобы вы не перезапускали какие-либо данные, а вместо этого позволяли получателю быть вашим параметром out. Можешь переписать тоже самое.

0 голосов
/ 18 апреля 2011

В общем, всегда полезно иметь модификатор const там, где это возможно, например, для параметра source .

0 голосов
/ 18 апреля 2011

Функция strcpy() полностью отказывается от управления памятью, поэтому все выделения должны быть выполнены перед вызовом функции и освобождены впоследствии, когда это необходимо.Если в вашей исходной строке больше символов, чем в целевом буфере, strcpy() просто продолжит запись после конца буфера в нераспределенное пространство или в пространство, выделенное для чего-то другого.

Это может быть очень плохо.

strncpy() работает аналогично strcpy(), за исключением того, что позволяет передавать дополнительную переменную, описывающую размер буфера, поэтому функция прекратит копирование, когда достигнет этого предела.Это безопаснее, но все же полагается на вызывающую программу для правильного размещения и описания буфера - он может пройти через конец буфера, если вы укажете неправильную длину, что приведет к тем же проблемам.

0 голосов
/ 17 апреля 2011

C не выполняет никакой проверки границ времени выполнения, как другие языки (C #, Java и т. Д.).Вот почему вы можете писать вещи после конца массива.Тем не менее, вы не сможете получить доступ к этой строке в некоторых случаях, потому что вы можете покушаться на не принадлежащую вам память, что приведет к ошибке сегментации.K & R была бы хорошей книгой для изучения таких понятий.

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