2016-03-20 3 views
-2

У меня проблема с печатью строки в C (ну, строка, на которую указывает *ptr).Странное поведение printf после memcpy

У меня есть следующий код:

char *removeColon(char *word) { 
    size_t wordLength; 
    char word1[MAXLENGTH]; 

    wordLength = strlen(word); 
    wordLength--; 
    memcpy(word1, word, wordLength); 
    printf("word1: %s\n", word1); 
    return *word1; 
} 

Я выбежала это со словом = "MAIN:" (значение слова происходит от strtok на строку чтения из файла). Работает нормально до printf, где результат:

word1: MAIN╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠

а затем есть исключение, и все ломается.

Любые мысли?

+4

null terminator, (guess) –

+0

У вас есть информация о подробностях? Я попытался добавить '\ 0' в конец слова1, но это не помогло. –

+0

Если это не так, я могу прочитать вопрос позже. –

ответ

0
wordLength = strlen(word); 

Вы должны включить нулевой терминатор в длину, потому что каждая строка имеет согласующий символ с ASCII значение 0, пишется \0 в С. Кроме того, используйте str... семейство функций вместо mem..., так как прежний предназначен для строк с нулевым завершением, но последний для массивов. Кроме того, вы не можете вернуть выделенный массив локального стека. Основываясь на коде функции, это звучит так, будто вы удаляете последний символ. Если это так, то лучше сделать

void remlast(char *str) 
{ 
    str[strlen(str) - 1] = '\0'; 
} 

Обратите внимание, что это не работает при пустых строках.

+1

Давай, «пересмотренная функция» по-прежнему содержит много ошибок. Также 'remlast' ломается для пустых строк. –

+0

исправлено @ M.M [16 символов] – stackptr

+0

@stackptr: на самом деле не исправлено ;-) на самом деле было бы меньше затрат, чтобы исправить код, чтобы задокументировать недостаток. – chqrlie

0

Вы копируете более wordLength байт, но вы не можете добавить нулевой завершающий байт. Поскольку word1 неинициализирован до этой копии, остальные байты не определены.

Поэтому, когда printf пытается распечатать строку, она не находит нулевой ограничитель и продолжает читать, пока не найдет нулевой байт где-то вне границ массива. Это неопределенное поведение.

После копирования байтов, необходимо вручную добавить нулевой терминатор:

memcpy(word1, word, wordLength); 
word1[wordLength] = '\0'; 

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

Вместо того, чтобы word1 локальный массив, вы можете выделить память динамически для него:

char *word1 = malloc(strlen(word)); 

Если вы сделаете это, вы должны будете free эту память где-то в вызывающей функции. Другой вариант, чтобы иметь пропуск абоненте в буфер нужного размера:

void removeColon(char *word, char *word1) { 
1

Вы должны убедиться, что (1) каждая строка NUL-прекращается, и (2) вы не пытаетесь изменить строка-буквал. У вас есть много подходов, которые вы можете предпринять. Простой подход, чтобы удалить последний символ (любой символ) с strlen:

char *rmlast (char *s) 
{ 
    if (!*s) return s;  /* return if empty-string */ 
    s[strlen (s) - 1] = 0; /* overwrite last w/nul */ 
    return s; 
} 

(вы также можете использовать string.h функции strchr (поиск 0), strrchr (поиск целевой полукокса, если он будет принят), strpbrk (поиск по одному из нескольких символов), и т.д .., чтобы найти последний символ, а)

Или вы можете сделать то же самое с указателями:

char *rmlast (char *s) 
{ 
    if (!*s) return s; /* return if empty-string */ 
    char *p = s; 

    for (; *p; p++) {} /* advance to end of str */ 
    *--p = 0;   /* overwrite last w/nul */ 

    return s; 
} 

Вы также можете передать последний интересующий персонаж, если хотите ограничить удаление на любой конкретный символ и сделать простое сравнение в функции перед перезаписью его с номером nul-terminating.

Осмотрите и сообщите мне, если у вас есть вопросы.

+0

Разве не 0 (целое число), отличное от '\ 0'? – RastaJedi

+0

Нет, 'nul-character'' '\ 0'' имеет значение ASCII '0' - нет никакой разницы. Для ввода четырех символов '' \ 0'' просто нужно ввести больше символов '0'':)' –

+0

Итак, это просто представление символа. Я не был уверен, что целочисленный ноль был каким-то образом представлен чем-то иным, чем «нулевой байт». Очевидно, что «0» совершенно иное, но этого даже не нужно было указывать. – RastaJedi

1

Ваша функция removeColon должна либо

  • работают на месте и изменить строку, переданную в качестве аргумента
  • дать буфер назначения и скопировать укороченную строку к нему или
  • выделить память для укороченного string и вернуть это.

Вы копируете только символы в локальный массив, а не нулевой терминатор, и вы не установите один в буфере, передавая этот массив printf("%s", ...) вызывает неопределенное поведение: printf продолжает печатать содержимое буфера до тех пор, пока не найдет '\0' байт, он даже выходит за пределы массива, вызывая неопределенное поведение, печатает мусор и в конечном итоге умирает в результате сбоя.

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

Вот функция, которая работает на месте:

char *removeColon(char *word) { 
    if (*word) word[strlen(word) - 1] = '\0'; 
    return word; 
} 

Вот один, который копирует в буфер назначения, предполагается достаточно долго:

char *removeColon(char *dest, const char *word) { 
    size_t len = strlen(word); 
    memcpy(dest, word, len - 1); 
    dest[len - 1] = '\0'; 
    return dest; 
} 

Вот один, который выделяет память:

char *removeColon(const char *word) { 
    size_t len = strlen(word); 
    char *dest = malloc(len); 
    memcpy(dest, word, len - 1); 
    dest[len - 1] = '\0'; 
    return dest; 
} 
Смежные вопросы