Почему этот код не может печатать символы в массиве?

Я скомпилировал этот код с помощью gcc (tdm-1) 5.1.0 и, пожалуйста, скажите мне, почему вывод не содержит "привет"

#include<stdio.h>
void main()
{
    int i;
    char st[20];
    printf("Enter a string ");
    scanf("%s",st);
    for(i=0;i<20;i++)
{
    printf("%c",st[i]);
}

}

Input:hello Output: @ @

из-за мусора в конце концов

Jean-François Fabre 10.09.2018 09:52

Используйте "%s" для печати всей строки сразу. Как бы то ни было, впоследствии вы могли печатать какие-то необычные специальные символы, которые могли бы заставить ваш терминал / cmd переписать строку.

Qubit 10.09.2018 09:52

вы читаете строку за пределами допустимого диапазона, следовательно, поведение не определено. Возможно, произошел сбой scanf, возможно, был напечатан ascii 13 - возврат каретки, и ваш привет был перезаписан мусором.

Antti Haapala 10.09.2018 09:53

это означает, что мой ввод хранится в массиве, но не может отображаться на консоли из-за некоторых других случайных символов?

skayp 10.09.2018 10:05

@pmg хорошо, плохо.

KaiserKatze 10.09.2018 10:29

Два решения: (1) char st[20] = { 0 }; (2) memset(st, 0, sizeof(st));

KaiserKatze 10.09.2018 10:30
1
6
85
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

Помните, что строки char в C на самом деле называются байтовыми строками оканчивающийся нулем. Этот бит оканчивающийся нулем важен и означает, что вы можете легко найти конец строки, проверив текущий символ против '\0' (который является символом терминатора).

Или вы можете просто использовать функцию strlen, чтобы вместо этого получить длину строки:

for(i=0;i<strlen(st);i++) { ... }

Или используйте формат "%s" для печати строки:

printf("%s", st);

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

scanf("%19s",st);  // Write at most 19 character (*plus* terminator) to the string

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

Что происходит с наверное, так это то, что некоторая часть «случайного» неопределенного содержимого оказывается возвратом каретки '\r', который перемещает курсор в начало строки, и уже записанный вывод будет перезаписан неинициализированными элементами в вашем массиве.

«Они будут неопределенными и кажущимися случайными», - скажут они на консоли?

skayp 10.09.2018 10:08

этот общий ответ не объясняет, почему начало строки не печатается для OP

Jean-François Fabre 10.09.2018 10:12

Ага. И было бы неплохо указать это в своем ответе.

Jean-François Fabre 10.09.2018 10:34

Вот небольшой пример, как уже объяснил Кубит:

#include <stdio.h>

void main () {
   char str1[20];

   printf("Enter name: ");
   scanf("%s", str1);

   printf("Entered Name: %s", str1);   
}

Здесь

char st[20];

st - это локальная переменная и содержимое массива по умолчанию stмусор не равно нулю. Таким образом, если вы сканируете менее чем 20 символов в st, в этом случае оставшееся местоположение массива st содержит мусор, следовательно, он печатает некоторые ненужные данные, такие как @ @, в случае

char st[20];
printf("Enter a string ");
scanf("%s",st);
for(i=0;i<20;i++) {
    printf("%c",st[i]);
}

И это плохая практика, как если бы пользователь ввел несколько символов, скажем, 5 символов, тогда ваш цикл вращается 20 раз, внутренне он будет выполнять больше операций или потреблять больше цикла ЦП.

Поэтому, если вы хотите распечатать char массив char по char, вам следует вращать цикл до тех пор, пока не встретится символ \0, например

for(i=0;st[i];i++) { /* this fails when \0 encounters */
    printf("%c",st[i]);
}

Или

как предлагали другие, вы можете распечатать массив символов st, используя один printf, используя спецификатор формата %s, например

printf("%s\n",st); /*here printf starts printing from base address of st 
                    and prints until \0 */

Также лучше инициализировать массив символов st при объявлении самого себя. например, для

char st[20] ="";

Другие вопросы по теме