2013-07-06 5 views
2

Так что я довольно новичок в программировании, и я начал C около 3 дней назад. Я создавал эту короткую программу, чтобы проверить себя. Это просто базовая программа на языке C, требующая вашего имени и фамилии. Вот код:Понимание scanf в C

#include <stdio.h> 

int main() 
{ 

    char first[20]; 

    char last[20]; 

    printf("Please enter your first name:"); 
    scanf("%s",&first); 
    printf("\nand Please enter your last name:"); 
    scanf("%s",&last); 
    printf("Greetings fellow %s %s!\n",first,last); 
    return(0); 
} 

Но когда я иду к компиляции я получаю эту ошибку каждый раз, когда:

checkname.c:9: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char (*)[20]’ checkname.c:11: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char (*)[20]’

Я знаю, что я могу использовать gets() кроме, по-видимому, это плохо, и я не должен Не используйте его. Что не так с этим кодом? Я не понимаю, в чем проблема.

+0

Я оставил бы эти пробелы в квадратных скобках. – chris

+0

Не забудьте новую строку '\ n' в конце каждой строки формата' printf' или, по крайней мере, называть 'fflush'! –

+0

Да, извините, когда я отправляю код, который он сделал, файлы заголовков исчезают с помощью brakcets. Возможно, для html5 или что-то еще. –

ответ

7

Я знаю, что могу использовать gets() за исключением, по-видимому, это плохо, и я не должен его использовать.

Точно, точно - он подвержен ошибкам переполнения буфера. И scanf() в равной степени злой (частично по той же причине - это не тривиально, чтобы указать длину буфера, и в любом случае это сложнее, чем необходимо, это сложно сделать правильно, и это слишком дорого для простого сырого ввода-вывода), не используйте его. Используйте fgets() для получения пользовательского ввода, это экономит ваше от расстрела в ноге, позволяя передать его длину буфера записываются в:

char buf[0x40]; 
fgets(buf, sizeof(buf), stdin); 

Теперь, когда вы знаете, «как», Я объясню вам «почему».

Массивы, переданные в функции, сообщаются Распад в указатели. Если вы передадите функции char [], она увидит, что в качестве char *, которая указывает на первый элемент массива. Вот почему вам не нужно явно использовать оператор «addressof» (&) для массива (char) (который концептуально является строкой на C).

Если вы используете его, вы не получите указатель на первый элемент массива, а указатель на сам массив, и это не то, что вы хотите.

(В общем, она могла бы работать, так как он, по-видимому сделал для вас, но в теории это вызывает undefined behavior потому что фактический тип выражения прошедшего в и типа ожидаемого спецификатором %s преобразования не совпадают.)

This document хорошо читает о массивах и указателях, обязательно прочитайте и поймите это.

+0

По ошибкам переполнения буфера вы говорите, что я прошу кого-то ввести там первое и фамильное имя, но вместо этого они вводят огромные строки строки, например, 1 миллион символов, что приводит к сбою или поломке программы. –

+0

@ JustinLeung Да, я делаю. Этого можно предотвратить, используя функции, которые связывают длину прочитанной строки. –

2

Вы используете массив. Не используйте & с scanf во время ввода в массив

например: scanf("%s",first);

Массивы уже передаются по ссылке. Вам не нужно ставить &, как массив уже передается как указатель на первый элемент в C

+1

Я понимаю, что знаю спасибо! –

+0

Добро пожаловать. Пожалуйста, примите ответ, нажав «Отметьте». Знак, оставшийся от моего ответа по голосам. @JustinLeung –

+0

Несомненно, извините, это мой первый раз на этом сайте. –

1

scanf("%s",&first); Попробуйте изменить к scanf("%s",first); (и подобие для last).

В нормальных условиях (включая их) имя массива оценивается по адресу первого элемента массива. В этом случае это указатель на char, который является типом scanf, ожидающим преобразования %s.

С & на начало, вы получите такое же значение указателя (то есть, тот же адрес), но как указатель на массив вместо указателя на элемент массива. Поскольку это не соответствует ожидаемому типу %s, результатом является неопределенное поведение (хотя, поскольку это правильный адрес, это обычно работает с большинством типичных компиляторов/процессоров).

+0

Есть ли причина, по которой вы избавиться от & for scanf ("% s", & first); Потому что я делаю это с тех пор, как начал программировать, и это сработало для меня. –

+0

Возможно, объяснение причины было бы хорошим. –

+0

@JustinLeung Да, есть. Массивы, когда они передаются в функции, распадаются на указатели. Если вы передадите 'char []' функции, он увидит это как символ 'char *', который указывает на первый элемент массива. Вот почему вам не нужно явно использовать оператор «addressof» ('&') для массива char (который концептуально является строкой на C).Если вы его используете, вы не получите указатель на первый элемент массива, а указатель на массив, и это не то, что вы хотите. (В общем, он может работать, но теоретически он вызывает неопределенное поведение, потому что фактический и указанные типы не совпадают.) –

0

зсапЕ нужен адрес, однако массив символов [] уже адрес и зсапЕ оленья кожа нужна ссылочный знак & потому, что само имя является адресом

1

Удалите & из scanf заявлений.

scanf("%s", first); // first is pointer to start of first 
scanf("%s", last); // last is pointer to start of last 

В C имя массива является указателем к началу массива.

После параметра формата scanf требует: указатель аргумент или аргументы.

scanf( "%s", first ); 
scanf format-arg input-args 

Например, если параметр целое число, были использованы для scanf, то & (взять адрес) необходимо будет оператором.

int n; 
scanf("%d", &n); // &n is pointer to n