2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу 1, 2  След.
 
 Массив строк в С
Сообщение16.07.2012, 21:22 
Аватара пользователя
Продолжаю изучение си. Вот написал простенькую прогу, чтобы убедиться, что форматом %s можно вывести целый массив символов.
код: [ скачать ] [ спрятать ]
Используется синтаксис C
#include <stdio.h>
#include <conio.h>
 
#define MAXLINE 10 /*длина строки*/

int main()
{
    char line[MAXLINE];
    int i;
   
    i = 0;
   
    while ((line[i] = getchar()) != EOF)
          ++i;
    if (i < 10)
        printf("%s", line);
         
    getch();
    return 0;
}

Объявил значит небольшой массив из 10 символов, вроде ввел как надо, но когда работаешь с программой, нужно два раза вводить EOF, в конце строки, потом Enter, потом снова EOF(Сtrl-z). При этом выводится строка со стрелочкой вправо в конце. Почему так?

 
 
 
 Re: Массив строк в С
Сообщение16.07.2012, 21:44 
Аватара пользователя
Потому что Сtrl-z это не EOF, а стрелочка.

 
 
 
 Re: Массив строк в С
Сообщение16.07.2012, 21:47 
Судя по всему, неправильный конец строки. Так работает:
Используется синтаксис C
    char line[10];


         int i = 0;

         while ((line[i] = getchar()) != '\n')
               ++i;
         if (i < 10)
             printf("%s", line);

         getchar();
         return 0;
 

Выдаёт результат после нажатия Enter. Так и привычней, и в конце массива переход на следующую строку.

 
 
 
 Re: Массив строк в С
Сообщение16.07.2012, 21:49 
Аватара пользователя
Pavia в сообщении #595955 писал(а):
Потому что Сtrl-z это не EOF, а стрелочка.

Joker_vD в сообщении #595331 писал(а):
Вообще-то EOF вводится по Ctrl+D (UNIX) / Ctrl+Z (Win). Ctrl+C — это прерывание работы программы.

Получается это неверно?

 
 
 
 Re: Массив строк в С
Сообщение16.07.2012, 22:06 
Кстати, если ввести строку, потом нажать Enter, потом Ctrl+Z, потом опять Enter, то можно увидеть правильный результат и в начальном варианте программы :-)

 
 
 
 Re: Массив строк в С
Сообщение16.07.2012, 23:02 
Аватара пользователя
Цитата:
Получается это неверно?


Это вопрос передачи информации. Человеческий язык очень неточен. И проблема формулировки терминов в программирование стоит очень остро.
Мне не хватает терминов чтобы это всё сформулировать кратко, но я могу описать как это всё происходит.

Условимся называть вашу программу как test.exe.

getchar() возвращает число.
Далее встаёт вопрос как интерпретировать это число. А делать это мы можем по разному.

Так вот число "-1"=EOF согласно стандарту С++ следует понимать как булевую константу false.
А вот всё остальное следует понимать как символ*.


Что касается CTRL+Z это клавиши. Стандарт С++ не говорит как следует интерпретировать нажатые клавиш. Это дело компьютера, ОС, консоли.


Нажатие клавише посылает сигнал. Клавиатура обрабатывает этот сигнал** преобразовывает в скан-код отправляет в компьютер, а тот в ОС. ОС преобразовывает этот код в свой код. Посылая сигнал программе.
Какой программе? Да той которая обрабатывает эти клавиши в данный момент. В WinXP, Win7 есть такая программа как cmd.exe в простонародье известная как консоль.
Так вот эта cmd.exe получив сообщения что были нажаты CTRL+Z интерпретирует их по своему.

ДОПУСТИМ мы не знаем как работает консоль, а просто по рассуждаем.
Когда мы запускаем test.exe в ОС Win XP. ОС выяснив что это консольное приложение запустила cmd.exe передав в качестве параметра "test.exe". А cmd.exe уже запустила программу test.exe.
Как консоль cmd.exe интерпретирует CTRL+Z? Да так, как захочет.
1) Консоль может преобразовать в ASCII символ и передать его в test.exe.
2) Консоль может интерпритировать комбинацию как команду на закрытие файла***. Это файл который используется для ввода символов*** в программу test.exe.
3) Она может отреагировать и подругому к примеру поменять цвет шрифта.

Это все было 3 предположения так как же на самом деле действует консоль cmd.exe?
На это ответит эксперемент и документация по конкретной ОС и её консоли.
Эксперимент показал что консоль Win Vista интерпретирует нажатие клавиш CTRL+Z, корректнее сказать их коды, как символ. И преобразовывает их скан-коды в код символа который передается в нашу программу. Символ этот имеет код который соотвествует в таблице ASCII стрелочке.
CTL+Z не вызывает генерацию EOF.

Возможно в Windows98 CTRL+Z выполнял функцию EOF, а возможно и нет.

----------------------------------------------------------
* Нет точных рекомендаций что понимать под символом. И тем более понимать EOF как символ или нет?
Лучше EOF не называть символом. Хотя не всегда это возможно.

**Сигнал - посмотрите определение в словаре. В контексте слово использовалось как нечто интуитивно понятное.
***Файл - в данном случае под файлом понимается набор данных,структур используемые ОС, для ввода и вывода данных с использованием так называемых файловых функций.

Символ - данные воспринимаемые и интерпретируемые одновременно ОС, программой, человеком,
компьютером - как число из ASCII таблице.

Есть такая вещь. Как ASCII таблица. Эта таблица описывает правило которое принято для интерпретации данных в виде символов выводимых на экран монитора или печать.
Таблица ASCII была разработана в Америке в последствие была расширена. По настоящее время применяется хотя почти и вытеснена UNICODE.
В ASCII символ имеет номера от 0 до 255. Для хранения одного символа ASCII достаточно байта.

Тип Char в Cи не имеет определённого размера. А размер зависит от платформы. Но чаще всего равен байту.

 
 
 
 Re: Массив строк в С
Сообщение16.07.2012, 23:10 
Dosaev в сообщении #595944 писал(а):
Объявил значит небольшой массив из 10 символов, вроде ввел как надо, но когда работаешь с программой, нужно два раза вводить EOF, в конце строки, потом Enter, потом снова EOF(Сtrl-z). При этом выводится строка со стрелочкой вправо в конце. Почему так?
Проблем несколько.
Первая:
venco в сообщении #595578 писал(а):
EOF - не символ, а число (-1), не пересекающееся с реально прочитанными символами, возвращаемыми из getchar() (0...255). Одна из распространённых ошибок - сохранять результат getchar() в переменную типа char. В результате, если char - signed, то чтение остановится и на символе с кодом 255 (буква 'я' в виндовой кодировке), а если unsigned, то получится бесконечный цикл.
Т.е. после сохранения результата getchar() в массив char, символ с кодом 255 ('я') будет трактоваться как EOF.

Вторая:
После чтения надо закончить массив нулевым символом, причём без EOF.

А что до двойного Ctrl-Z, то это особенность терминала - он не закрывается после передачи EOF, а остаётся открытым, и последующий getch() опять ждёт ввода. В принципе не обязательно жать Ctrl-Z, достаточно и Enter.

 
 
 
 Re: Массив строк в С
Сообщение16.07.2012, 23:21 
Аватара пользователя
Спасибо за столь обширный ответ. Что такое EOF вроде бы как понятно, но вы меня еще больше запутали в его предназначении. Хорошо, тогда такой прямой вопрос: в каком случае функция getchar примет это значение? Иными словами можно ли с клавиатуры ввести это значение, для того чтобы показать что входной поток (строка) закончился? Я ведь его и использую в качестве "конца" строки.

 
 
 
 Re: Массив строк в С
Сообщение16.07.2012, 23:27 
Аватара пользователя
Dosaev
Немного поэкспериментировал с CTRL+Z оказывается если нажать
CTRL+Z затем enter то он интерпитируется как EOF
А если вначале ввести символ потом CTRL+Z, а затем Enther то уже CTRL+Z интерпретируется как стрелка

 
 
 
 Re: Массив строк в С
Сообщение16.07.2012, 23:32 
Dosaev в сообщении #596007 писал(а):
Спасибо за столь обширный ответ. Что такое EOF вроде бы как понятно, но вы меня еще больше запутали в его предназначении. Хорошо, тогда такой прямой вопрос: в каком случае функция getchar примет это значение? Иными словами можно ли с клавиатуры ввести это значение, для того чтобы показать что входной поток (строка) закончился? Я ведь его и использую в качестве "конца" строки.
Это зависит от операционной системы. В Windows надо нажать Ctrl-Z. В Unix - Ctrl-D (причём это по умолчанию, командой stty можно изменить эту комбинацию, например, на Ctrl-Z). На Маке, может быть что-то ещё. В Windows символ Ctrl-Z обрабатывается в библиотеке stdio, не только для консоли, но и для любого файла открытого в текстовом режиме. В Unix этот символ обрабатывается где-то в драйвере консоли, и до программы сам символ Ctrl-D не уже доходит (в Unix нет различия между текстовым и бинарным режимом ввода).

 
 
 
 Re: Массив строк в С
Сообщение16.07.2012, 23:35 
Аватара пользователя
Цитата:
Спасибо за столь обширный ответ. Что такое EOF вроде бы как понятно, но вы меня еще больше запутали в его предназначении. Хорошо, тогда такой прямой вопрос: в каком случае функция getchar примет это значение? Иными словами можно ли с клавиатуры ввести это значение, для того чтобы показать что входной поток (строка) закончился? Я ведь его и использую в качестве "конца" строки.

EOF следует применять когда вы пишите консольную утилиту и она должна обрабатывать файлы поданные на вход. К примеру так test.exe <1.txt
А для ручного в вода лучше обрабатывать нажатие клавиши Enter.
lim(f(x)) уже привел пример.

 
 
 
 Re: Массив строк в С
Сообщение16.07.2012, 23:36 
Дополнительная путанице с EOF в C ещё в том, что кроме символа ASCII, неформально называемом EOF (тот же Ctrl-Z), есть ещё символическая константа EOF равная -1. Вам важна именно эта константа, а каким именно символом конец ввода обозначается в консоли, изнутри программы, в коде на C - это не важно.

 
 
 
 Re: Массив строк в С
Сообщение16.07.2012, 23:42 
Аватара пользователя
Pavia, спасибо.
venco,
venco в сообщении #596003 писал(а):
Проблем несколько.
Первая:
venco в сообщении #595578 писал(а):
EOF - не символ, а число (-1), не пересекающееся с реально прочитанными символами, возвращаемыми из getchar() (0...255). Одна из распространённых ошибок - сохранять результат getchar() в переменную типа char. В результате, если char - signed, то чтение остановится и на символе с кодом 255 (буква 'я' в виндовой кодировке), а если unsigned, то получится бесконечный цикл.
Т.е. после сохранения результата getchar() в массив char, символ с кодом 255 ('я') будет трактоваться как EOF.

Ответ на первую проблему:
код: [ скачать ] [ спрятать ]
Используется синтаксис C
#include <stdio.h>
#include <conio.h>
 
#define MAXLINE 10

int main()
{
    char line[MAXLINE];
    int i, c;
   
    i = 0;
   
    while ((c = getchar()) != EOF) {
          line[i] = c;
          ++i;
    }
    if (i < 10 && c == '\n') {
          line[i] = '\0';
        printf("%s", line);
    }
         
    getch();
    return 0;
}

Что здесь не так? :-(

 
 
 
 Re: Массив строк в С
Сообщение16.07.2012, 23:51 

(Оффтоп)

Pavia в сообщении #595955 писал(а):
Потому что Сtrl-z это не EOF, а стрелочка.

Прошу прощения за оффтопик. Почему у меня, в тупом Паскале, никогда не возникает проблем со срабатыванием eof?... ни в какой системе?... -- может, потому, что он настолько туп, что даже и не подозревает, что тут, по правилам пр иличия, следовало бы хоть сколько-то, но подгадить?...

 
 
 
 Re: Массив строк в С
Сообщение17.07.2012, 00:06 
Аватара пользователя
Цитата:
Что здесь не так?

В цикле произойдёт переполнение массива раньше чем дайдёт до условия проверки переполнения.

 
 
 [ Сообщений: 18 ]  На страницу 1, 2  След.


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group