2016-02-27 2 views
-3

Отредактированный вопрос

я понял свою ошибку в коде, я дал в оригинальный вопрос, а персонажи я получаю мусорные символы. Хотя, у меня есть еще несколько вопросов о мусорных символов в C:Мусорные символов в C

  • Почему не символ enter image description here копироваться?

  • Есть ли у мусора персонажи какой-то узор? Это означает, что вы можете предсказать для пустой строки, какой может быть персонаж, для пустого целого, что придет, и так далее.

  • Когда объявляется переменная, почему у нее есть символ мусора, а не пустой? Есть ли конкретная причина хранить его с мусором?

  • Для строки, которая не заканчивается на нуль, будет ли отображаться тот же символ мусора на каждой ОС? Если да, то какой?

  • Есть ли одинаковые символы мусора на каждой ОС? Или они разные?

  • Есть ли способ распечатать эти символы в буфере stdout в C/C++?

  • Если вы внимательно посмотрите на символ enter image description here, в нем есть символы и цифры. Они что-то представляют?

  • Есть ли список символов мусора, которые могут быть напечатаны на C/C++?



Оригинал Вопрос

Название оригинального вопроса: Таинственная выводимый символ в C

Я пришел через этот код в K & R:

int scanline (char str [], int lim)              /* Line will be read in 'str []', while lim is the maximum characters to be read */ 
{ 
    int c, len, j;                  /* 'len' will have the length of the read string */ 

    j = 0;                    /* Initializing 'j' */ 
    for (len = 0; (c = getchar()) != EOF && c != '\n'; ++len)       /* Reading a character one by one, till the user enters '\n', and checking for failure of 'getchar' */ 
    { 
     if (len < (lim -2))                /* Checking that string entered has not gone beyond it's boundaries. '-2' for '\n' and '\0' */ 
     { 
      str [j] = c;                 /* Copying read character into 'string [j]' */ 
      ++ j;                  /* Incrementing 'j' by 1 */ 
     } 
    } 
    if (c == '\n')                  /* Checking if user has finished inputting the line */ 
    { 
     str [j] = c;                 /* Copying newline into string */ 
     ++j; 
     ++ len; 
    } 

    return len;                   /* Returning number of characters read */ 
} 

В K & R, он известен как getline, но я внес изменения, добавили комментарии, и, таким образом, как это определено scanline. Чтобы проверить это, я сделал демонстрационную программу:

#include <mocl/cancel.h> 

int main (int argc, char **argv) 
{ 
    int len; 
    char str [50]; 
    len = scanline (str, 50); 
    printf ("len = %d\n str = %s\n", len, str); 
    return 0; 
} 

необходимые заголовки и функция была в моей библиотеке, cancel.h. Затем, когда я скомпилировал свою программу, она прошла успешно. Хотя, когда я запустил исполняемый файл, я получил неожиданный выход (я не могу ввести его, как я получить символ, который, когда я копирую, он просто получает вставленный как «м»):

enter image description here

Таинственный персонаж enter image description here который при копировании копируется как письмо m.Кроме того, при запуске программы с разными входами, я получаю различные загадочные выходы:

enter image description here

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

enter image description here

Я также встретил вопрос this, в котором пользователь получает тот же символ.


Что я сделал до сих пор?

Я искал много, и я не мог найти любой ключу о enter image description here этого символа, но если вы видите тщательно, на втором изображении, я получаю больше символов, когда я вхожу «привет это Ashish». Один из них - косая черта, а один - enter image description here. Но я получаю еще одного персонажа enter image description here. Я получил ссылку this, в которой было показано, как ее воспроизвести, и объяснил это, хотя я не мог понять. Когда вы запускаете код, указанный здесь, вы получаете много символов, а один из них - enter image description here. Хотя даже автор этой статьи не мог ее скопировать и не опубликовал. Так вот вывод:

enter image description here

Это был фактический объем производства, так как это не ясно, вот вырезают версия:

enter image description here

Поэтому в основном я должен знать, что и персонажи enter image description here и enter image description here - это расширенные символы из строки. В этот момент я действительно выяснил, что вызвало проблему в scanline.

Линии

if (c == '\n')                  /* Checking if user has finished inputting the line */ 
{ 
    str [j] = c;                 /* Copying newline into string */ 
    ++j; 
    ++ len; 
} 

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


Мои вопросы

  • Как удаление этих строк сделать работу программы правильно?

  • Каковы символы enter image description here и enter image description here? Что они должны делать и как они появились здесь?

  • Есть ли еще такие символы?

  • Почему эти символы не могут быть скопированы?

  • Это Неопределенное поведение?

+4

'str' не имеет значения null-terminate. – BLUEPIXY

+1

Может ли пояснитель объяснить? Я бы хотел улучшить свой пост. –

+0

Некоторые наборы инструментов сделают DEBUG строит и заполняет память, которая в противном случае не была бы заполнена (потому что ваш код не говорит), так что вы и его библиотеки отладки можете легко поймать _some_ ошибки при тестировании _some_ путей выполнения. –

ответ

3

Там какая-то путаница в отношении термина мусора символов. К ним относится любой байт, который находится в переменной, которая не была назначена определенным образом. Символ A может быть символом мусора, если он появляется в (например) блоке памяти, возвращаемом malloc, или неинициализированной переменной char.

Это отличные от непечатаемые символы, которые являются символами, которые не имеют четко определенного представления при печати в качестве символов. Например, коды ASCII 0 - 31 и 127 (0 - 1F и 7F hex) являются управляющими символами и, следовательно, непечатаемы. Существуют также многобайтовые символы, для которых конкретный терминал может не знать, как их отображать.

Чтобы попасть в конкретные вопросы:

Почему не символ (изображение) копируется?

В качестве непечатаемого символа его экранное представление не определено. Поэтому попытка скопировать и вставить его с терминала приведет к неожиданным результатам.

Есть ли у мусора персонажи какой-то узор? Это означает, что вы можете предсказать для пустой строки, какой символ может прийти, для пустого целого числа, что придет, и так далее.

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

В стандарте не указано, какие значения должны идти туда, поэтому реализации могут свободно обрабатывать его, но они хотят. Они могли бы оставить любые значения на этих адресах памяти, они могли бы выбрать запись 0 ко всем адресам, они могли бы последовательно записывать значения 0, 1, 2, 3 и т. Д. Другими словами, содержание: undefined.

Когда объявлена ​​переменная, почему у нее есть символ мусора вместо того, чтобы быть пустым? Есть ли конкретная причина его хранения с символом мусора?

Глобальные переменные и статические локальные переменные инициализируются нулевыми байтами, что и диктует стандарт. Это то, что делается легко во время компиляции. Локальные переменные, с другой стороны, находятся в стеке. Таким образом, их значения - все, что происходит в стеке во время вызова функции.

Вот интересный пример:

void f1() 
{ 
    char str[10]; 
    strcpy(str, "hello"); 
} 

int main() 
{ 
    f1(); 
    f1(); 
    return 0; 
} 

Вот что конкретная реализация мощь сделать:

Первый раз f1 называется, локальная переменная str не инициализирован. Затем вызывается strcpy, который копирует строку «привет». Это занимает первые 6 байтов переменной (5 для строки и 1 для нулевого терминатора). Остальные 4 байта все еще мусор. Когда эти функции возвращаются, память, которую имеет переменная str, может использоваться для других целей.

Теперь f1 вызывается снова сразу после первого вызова. Поскольку никакой другой функции не вызывалось, стек для этого вызова f1 оказывается в том же месте, что и последний вызов. Итак, если вы должны были изучить str в это время, вы найдете в нем h, e, l, l, o и нулевым байтом (т. Е. Строка «привет») для первых 6 байтов. Но эта строка мусор. Там он специально не хранился. Если какая-то другая функция была вызвана до вызова f1 во второй раз, скорее всего, эти значения будут не быть там.

Снова, мусор означает, что содержимое не определено. Компилятор явно не помещает в переменные «мусор» (или непечатаемые символы).

Для строки, которая не заканчивается на нуль, будет ли отображаться символ того же самого мусора на каждой ОС? Если да, то какой?

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

void f3() 
{ 
    char str1[5], str2[5]; 

    strcpy(str1, "hello"); 
    strcpy(str2, "test"); 
    printf("str1=%s\n", str1); 
} 

Давайте предположим, что компилятор решает разместить str2 сразу после str1 в памяти (хотя не должен). Первый вызов strcpy будет записывать строку «hello» в str1, но эта переменная не имеет достаточного количества нулевого завершающего байта. Поэтому он записывается в следующий байт в памяти, который, оказывается, является первым байтом str2. Затем, когда запускается следующий вызов strcpy, он помещает строку «test» в str2, но при этом он перезаписывает нулевой завершающий байт, помещенный туда, когда было записано str1.

Тогда, когда printf вызывается, вы получите это как выход:

str1=hellotest 

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

Но опять же, это undefined. По-видимому, незначительное изменение этой функции может привести к появлению в памяти str2. Компилятор может делать все, что пожелает, поэтому нет никакого способа предсказать, что произойдет.

Есть ли одинаковые символы мусора на каждой ОС? Или они разные?

Я считаю, что вы на самом деле со ссылкой на непечатных символов в этом случае. Это действительно зависит от набора символов ОС и/или терминала, о котором идет речь. Например, китайские символы представлены несколькими байтами. Если ваш терминал не может печатать китайские символы, вы увидите какой-то код, похожий на то, что вы видели для каждого из байтов. Но если это возможно, оно будет отображать его в четко определенном виде.

Есть ли способ распечатать эти символы в буфере stdout в C/ C++?

Не как персонажи. Однако вы можете распечатать их числовые представления. Например:

void f4() 
{ 
    char c; 
    printf("c=%02hhX\n", (unsigned char)c); 
} 

Содержимое c не определено, но выше напечатает любое значение, случается, есть в шестнадцатеричном формате.

Если вы видите внимательно символ (изображение), , в нем есть символы и цифры. Представляют ли они что-то?

Некоторые терминалы будут отображать непечатаемые символы, напечатав поле, содержащее символ Unicode codepoint, чтобы читатель мог знать, что это такое.

Юникод - это стандарт для текста, где каждому персонажу присваивается числовое значение код. Помимо типичного набора символов в диапазоне ASCII, Unicode также определяет другие символы, такие как буквы с акцентом, другие алфавиты, такие как греческий, иврит, кириллический, китайский и японский, а также различные символы. Поскольку тысячи символов определены в Unicode, для их представления требуется несколько байтов. Наиболее распространенная кодировка для Unicode - UTF-8, которая позволяет кодировать обычные символы ASCII с одним байтом и другие символы, которые должны быть закодированы с двумя или более байтами по мере необходимости.

В этом случае рассматриваемый код является 007F. Это управляющий символ DELETE, который обычно генерируется при нажатии клавиши Delete. Поскольку это управляющий символ, ваш терминал отображает его как поле с точкой Unicode для символа, а не пытается его «распечатать».

Есть ли список символов мусора, которые могут быть напечатаны в C/ C++?

Опять же, если вы на самом деле означает непечатные символы здесь, что имеет больше общего с терминалом, который отображаются символы, которые с языком. Как правило, управляющие символы непечатаемы, в то время как определенные многобайтовые символы могут отображаться или не отображаться должным образом в зависимости от шрифта/набора символов терминала.

+0

Это хорошо, но в вашей функции 'f3' вы печатаете' printf ("str1 =% s \ n"); 'без передачи какого-либо второго аргумента, а' hellotest' печатается в соответствии с вами? Я думаю, что это опечатка. –

+0

Я также не мог понять второй последний вопрос: «Если вы внимательно посмотрите на персонажа (изображение), в нем есть некоторые символы и цифры. Они что-то представляют?». Что такое _Unicode Codepoint_? Кроме того, что такое _DELETE control character_? –

+0

@AshishAhuja Недопустимый параметр был опечаткой. 'str1' должно быть передано. Это исправлено. Я также добавил описание Unicode, а также ссылки на более подробную информацию и описание символа DELETE. – dbush

0

Для начала функция возвращает неправильное значение len. Предположим, что lim равно 2.

В этом случае в цикле не будет написано ничего в массиве из-за состояния

if (len < (lim -2)) 

Однако после первой итерации цикла len будет увеличена.

for (len = 0; (c = getchar()) != EOF && c != '\n'; ++len) 
                ^^^^^ 

Во второй итерации снова не будет написано ничего в diue массиве в том же состоянии,

if (len < (lim -2)) 

но len будет увеличена.

for (len = 0; (c = getchar()) != EOF && c != '\n'; ++len) 
                ^^^^^ 

Таким образом, ничего не будет записано в массиве, но Len будет увеличен до, например, символ новой строки не будут встречаться.

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

Функция может быть записана следующим образом

int scanline(char str [], int lim) 
{ 
    int len = 0; 
    int c;  

    while (len < lim - 1 && (c = getchar()) != EOF && c != '\n') 
    { 
     str[len++] = c; 
    } 

    if (len < lim - 1 && c == '\n') str[len++] = c; 

    if (len < lim) str[len++] = '\0'; 

    return len; 
} 
Смежные вопросы