LINUX.ORG.RU

Вышел первый том книги А. В. Столярова «Программирование: введение в профессию»

 , ,


24

11

На официальном сайте А. В. Столярова объявлено о выходе первого тома книги «Программирование: введение в профессию». Первый том, озаглавленный «Азы программирования», включает две части: «Введение» и «Язык Паскаль и начала программирования». Обе части, как и вся книга в целом, ориентированы на использование ОС Unix (в основном Linux); в предисловии автор, обращаясь к «коллегам-преподавателям», заявляет, что книга вряд ли будет им полезна, если командная строка ОС Unix не станет их основным инструментом для повседневной работы с компьютером.

Электронная версия первого тома (PDF) доступна на сайте в открытом доступе.

Книга «Программирование: введение в профессию» примечательна тем, что средства на её написание и издание были собраны через краудфандинговую кампанию. По словам автора, это был единственный вариант, позволяющий написать книгу и предоставить открытый доступ к её электронной версии. Приём пожертвований на сайте А. В. Столярова продолжается, поскольку средств для издания последующих томов к настоящему моменту недостаточно.

Как сообщалось ранее в новостной ленте сайта, второй том книги, который выйдет под заголовком «Низкоуровневое программирование», уже практически готов к печати. В него войдут часть о программировании на языке ассемблера NASM для ОС Unix, а также часть, посвящённая языку Си. Пока неясно, войдёт ли в этот же том часть, рассказывающая о принципах построения операционных систем и о возможностях, доступных на уровне системных вызовов ОС Unix, или же эта часть будет оформлена как отдельный том. Сроки издания второго тома также пока неизвестны, поскольку зависят от дальнейшего хода краудфандинговой кампании.

>>> Подробности

★★★

Проверено: anonymous_incognito ()
Последнее исправление: CYB3R (всего исправлений: 5)

Ответ на: комментарий от Croco

На хаскеле тоже ничего не получится, не волнуйтесь.

Лично знаю человека, который сделал докторат в области автоматического доказательства termination программ на Прологе, например.

Inb4 доказательство спецификации — принципиально другая задача.

liberte
()
Ответ на: комментарий от liberte

Лично знаю человека, который сделал докторат в области автоматического доказательства termination программ на Прологе, например.

А, ну не, диссер-то сделать на этом можно, их уже и сделано, и не одна сотня, даже не одна тысяча, наверное. Я вон на своём InteLib'е тоже диссер сделал. Дык это, по-моему даже у InteLib есть призрачный шанс принести практическую пользу, а вот у доказательного программирования таких шансов нуль.

Кстати, Пролог того, Тьюринг-полный. То есть на нём можно сделать интерпретатор машин Тьюринга. Проблема останова машины Тьюринга алгоритмически неразрешима.

в области автоматического доказательства termination программ на Прологе

«Мы сами знаем, что она не имеет решения! Нас интересует, КАК её решать!»

Croco ★★★
() автор топика
Ответ на: комментарий от Croco

Ага. В том числе будет тупо генерация цепочек значений той же длины, состоящих из произвольно выбранных элементов (например, только из элементов, равных первому в исходной цепочке, и так далее), с последующей проверкой каждого из наложенных условий (сначала условия на совпадение количество, потом условия на отсортированность) с возвратом к началу и генерацией следующего варианта цепочки каждый раз, когда условие не выполнено. Это будет как раз программа, _в точности_ повторяющая вашу спецификацию, то есть полученная из неё тупо, цинично и без всякого искусственного интеллекта.

Да, согласен. Это напоминает bogosort. Можно еще попробовать последовательно перебирать все возможные перестановки из элементов несортированного массива, и после каждой подобной перестановки проверять, сортирован ли наш массив. Или можно взять случайных значений по размеру сортируемого массива из /dev/random и тупо проверить, что в нем есть те же числа в том же количестве, что и в том, которое надо сортировать, и кроме того там все упорядочено по возрастанию. Это будет работать, но это будет ЧУДОВИЩНО ДОЛГО.

Теперь такой вопрос: а чем ваша спецификация _лучше_, чем просто написанная подпрограмма для сортировки? По своему объёму она больше, то есть ошибиться при её составлении проще, особенно если её делать именно как формальную спецификацию, то есть записывать не на естественном языке, а на каком-то из существующий языков спецификаций. Никакой эффективности она не предполагает, в отличие, например, от написанного на любом ЯП quick sort'а. Вот уже два недостатка.

Ну если у меня есть одна какая-то гарантированно правильная(настолько гарантированная, что «голову даю на отсечение, что ошибки тут нет») сортировка, то я могу использовать ее для доказательства какой-угодно другой сортировки. Просто переведя первую и вторую сортировку в язык для STM-солвера используя нечто вроде Frama-C и доказав эквивалентность через какие-нибудь солверы или Coq.

А достоинства где? Профит-то где, профит?

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

А с STM-солверами конечно хватает проблем https://lists.gforge.inria.fr/pipermail/frama-c-discuss/2016-March/005064.html https://lists.gforge.inria.fr/pipermail/frama-c-discuss/2016-March/005066.html вот например мне пришлось добавить аксиом чтобы можно было доказать простой код вида

/* ALWAYS TRUE */
/*@ ensures \result == 1;
*/
uint8_t test_uint8_cast_mod256_eq (uint64_t a)
{
  return ((a)%256 == (uint8_t)(a));
}

SZT ★★★★★
()
Ответ на: комментарий от SZT

Ну если у меня есть одна какая-то гарантированно правильная(настолько гарантированная, что «голову даю на отсечение, что ошибки тут нет») сортировка, то я могу использовать ее для доказательства какой-угодно другой сортировки.

А может, её не надо использовать для доказательства? Может, её проще использовать для сортировки?

Хотя вообще-то тут что-то не так. Проблема эквивалентности двух алгоритмов, ээ... таки да, алгоритмически неразрешима.

Croco ★★★
() автор топика
Ответ на: комментарий от unlog1c

Нужны еще дополнительные условия чтобы сортировка была стабильной.

А какая разница? У меня сортируются числа. Мне абсолютно не важны особенности реализации сортировки, мне важно что вот на выходе чтобы были те же числа в таком же количестве что и во входе, но поставленные по возрастанию.

SZT ★★★★★
()
Ответ на: комментарий от Croco

А может, её не надо использовать для доказательства? Может, её проще использовать для сортировки?

Ну, может оказаться, что я написал сортировку пузырьком, а доказывать я буду квиксорт, который явно быстрее

Хотя вообще-то тут что-то не так. Проблема эквивалентности двух алгоритмов, ээ... таки да, алгоритмически неразрешима

Ну, в общем случае неразрешима, а вообще она бывает вполне разрешимой.

SZT ★★★★★
()
Ответ на: комментарий от SZT

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

Не понимаю зачем это нужно, можете объяснить?

anonymous
()
Ответ на: комментарий от Croco

Ай-вей, а вы в курсе различий между

char *s = "Hello";

и

char s[] = "Hello";

?

Первое это на строковый литерал в сегменте данных программы, вроде как.

Доступный только для на чтение.

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

Хотя да, с типами я что-то поторопился, исправлюсь ;-)

Twissel ★★★★★
()
Ответ на: комментарий от anonymous

Описание свойства сортированности через готовый алгоритм, вида «вот этот входной массив из у нас несортированный, а вот мы сделаем вот то-то и то-то (описание того, как сортировать пузырьком) то тогда выходной массив у нас отсортирован» окажется длиннее и труднее для понимания SMT-солверу, чем описание «вот этот входной массив у нас несортированный, а если надо чтобы он стал сортированный, надо чтобы каждый элемент массива больше предыдущего, и при этом сами элементы должны быть в том же количестве что в несортированном(столько же пятерок, столько же троек, итд)»

SZT ★★★★★
()
Ответ на: комментарий от anonymous

Иными словами, если солверу описывать сортированность через готовый сортирующий код, и мы будем об этот код доказывать другую сортировку, которая кардинально отличается по способу(например сортировка пузырьком, сортировка подсчетом) то солверу придется очень долго думать, чтобы понять, что у них там вообще общего. С другой стороны, если попробовать доказать из сортировки пузырьком какую-нибудь другую похожую сортировку (можно немного повысить эффективность пузырьковой сортировки, да) то это может оказаться наоборот проще, чем доказывать через некий «общий вид»

SZT ★★★★★
()
Ответ на: комментарий от SZT

Ну, может оказаться, что я написал сортировку пузырьком, а доказывать я буду квиксорт, который явно быстрее

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

Croco ★★★
() автор топика
Ответ на: комментарий от Twissel

Первое это на строковый литерал

Ну и это тоже, но есть же более очевидные различия. В первом случае s — леводопустимое, то есть это переменная, которой можно что-то присваивать. Во втором случае это имя массива, а именам массивов ничего присваивать нельзя. В первом случае sizeof(s) есть размер указателя (зависит от платформы, на i386 будет 4, на x86-64 будет 8), тогда как sizeof(s) во втором случае будет шесть (пять буковок и нолик в конце) вне всякой зависимости от платформы (ибо sizeof(char) есть по определению единица).

Возвращаясь к типам, &s в первом случае будет иметь тип char**, а во втором... во втором... А ВОТ ДОГАДАЙТЕСЬ!!! :-D

Croco ★★★
() автор топика
Ответ на: комментарий от Twissel

Croco (при всей его категоричности), просто хотел показать многословность стандарта.

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

Я очень удивлен, что мне приходится всё это разжевывать.

И, напоследок
C89 Standart

Собственно он явно дал понять, что читать это не нужно. Зачем вы это цитируете?

ASM ★★
()
Ответ на: комментарий от Croco

а во втором...

По логике вещей

#include <stdio.h>

int main(void) { 
  char(*p)[];
  char s[] = "Hello, World!";
  p = &s;
  printf("%c\n", (*p)[10]);
return 0;
}

Отсюда и тип соответствующий ;-)

Ну и для полноты картина, раз уж пошла такая пьянка,

вариант похуже

#include <stdio.h>

int main(void) { 
  
  char* c;
  char s[] = "Hello, World!";
  c = &s[0];
  printf("%c\n", *(c+10));

return 0;
}
Twissel ★★★★★
()
Ответ на: комментарий от ASM

Вышел первый том книги А. В. Столярова «Программирование: введение в профессию» (комментарий)

p=&f; /*вы копируете указатель на указатель, что противоречит логике*/

Так что давайте не увиливать от темы, я на протяжении треда всего лишь хочу показать,

то что изложено по ссылке и с чего началось наше общение тут.

Вышел первый том книги А. В. Столярова «Программирование: введение в профессию» (комментарий)

Twissel ★★★★★
()
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от Croco

То, что у вас написано, к K&R никакого отношения не имеет.

В КР сказано, что если имя функции входит не в позиции имени функции, то генерируется указатель на эту функцию. Второй абзац раздела 22.2.

Единственное, что я могу предположить, что перевод КР этого абзаца был выполнен неверно. Честно сказать, проверять мне это лень.

ASM ★★
()
Ответ на: комментарий от Twissel

Croco сказал
Я ничего никому не обязан. Используя инструмент, желательно знать, как он устроен; для этого есть, например, книга Кернигана и Ритчи, на которой пишут «ANSI C», что не соответствует действительности: ANSI предполагает использование const, авторы языка с этим так и не смирились.

и далее

С другой стороны, ANSI разрешает сделать вот так:
int f(int x) { /* ... */ } int (*p)(int); /* ... */ p = f; > p(13);
тогда как авторы языка такое никогда не считали приемлемым и всегда в такой ситуации делали

Я открыл книгу, прочитал раздел 22.2 и сделал выводы по второму абзацу, что f это ни что иное, как указатель на функцию. Ну и следовательно делая p=&f вы записываете в p указатель на f который указывает на функцию f. Т.е. «p» это указатель на указатель. КР конкретно в этом вопросе можно понять двояко. Собственно, что должно доказывать, что читать надо стандарты, вместе или без книги КР которая описывает «общие» идеи.

Если я не ответил на ваш вопрос, прошу сформулировать его более чётко, я не пойму что вы хотите выяснить.

ASM ★★
()
Последнее исправление: ASM (всего исправлений: 2)
Ответ на: комментарий от ASM

Тьфу ты, ну ты! :-)

Да, как раз таки создается указатель на функцию.

Но объявления вида

int f(int x);  
inf (*p)(int);

p = f;

/* и внимание */

p = &f

АБСОЛЮТНО ЭКВИВАЛЕНТНЫ и этот синтаксис стандартом не регламентирован.

А главное во втором случае никакого указателя на указатель на функцию не будет.

Twissel ★★★★★
()
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от ASM

Ну и следовательно делая p=&f вы записываете в p указатель на f который указывает на функцию f. Т.е. «p» это указатель на указатель.

Вот именно это и есть Ваш домысел, а не действительное положение вещей.

Брать адрес от адреса rvalue-параметра более, чем бессмысленно, что и приведено по ссылке на StackOverflow.

Следовательно, как ни напиши, туда все равно запишется адрес функции, т.е. указатель. ЧТД.

Twissel ★★★★★
()
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от Twissel

Да, как раз таки создается указатель на функцию.

Спасибо КЭП.

А главное во втором случае никакого указателя на указатель на функцию не будет.

И ещё раз читаем: КР «Если имя функции входит в выражение не в позиции имени функции, соответствующей обращению к ней, то генерируется указатель на эту функцию.»

Я как читатель понимаю это так. Есть функция f, если я напишу p=&f, то сгеренируется указатель на функцию f, и адрес (за счёт &) этого указателя будет помешена в p.

Не с точки зрения стандарта, а с точки зрения конкретного текста в КР в чём я не прав?

ASM ★★
()
Ответ на: комментарий от ASM

Ну если так хотите

Тоже из K&R 5.11 Указатели на функции

В обращениях к функциям qsort, strcmp и numcmp их имена трактуются как адреса этих функций, поэтому оператор & перед ними не нужен, как он не был нужен и перед именем массива.

И, по правде говоря, не знаю, где Вы там нашли 22.2?

Можно скрин?

Twissel ★★★★★
()
Ответ на: комментарий от ASM

Я открыл книгу, прочитал раздел 22.2

В K&R восемь глав и три приложения (второе издание).

В КР сказано, что если имя функции входит не в позиции имени функции, то генерируется указатель на эту функцию, иными словами f является указателем на функцию с аналогичным именем

f это ни что иное, как указатель на функцию

Это не верно. K&R:

5.11 Pointers to Functions In C, a function itself is not a variable, but it is possible to define pointers to functions, ...
...

qsort((void**) lineptr, 0, nlines-1,
             (int (*)(void*,void*))(numeric ? numcmp : strcmp));
... In the call to qsort, strcmp and numcmp are addresses of functions. Since they are known to be functions, the & is not necessary, in the same way that it is not needed before an array name.

При этом:

A.7.4.2 Address Operator The unary operator & takes the address of its operand. The operand must be an lvalue referring neither to a bit-field nor to an object declared as register, or must be of function type. The result is a pointer to the object or function referred to by the lvalue. If the type of the operand is T, the type of the result is ``pointer to T."

LamerOk ★★★★★
()
Ответ на: комментарий от ASM

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

Вы просто не знаете предмета, о котором рассуждаете, и как следствие — не поняли, о чём шла речь. Какой-то указатель на указатель откуда-то выкопали, например. А между тем, там всё проще: K&R считали, что с семантической точки зрения функция есть самостоятельный объект, и имя функции обозначает (в отличие, кстати, от массива) саму функцию, а не её адрес. Соответственно, авторы языка исходно считали единственным допустимым вариантом следующий:

    int f(int x) { ... }
    int (*p)(int);
    p = &f;     /* взятие адреса в явном виде */
    (*p)(13);   /* разыменование необходимо в явном виде */

Кто-то из создателей компиляторов обнаружил, что в принципе, компилятор не развалится, если допустить наряду с такой трактовкой ещё и другую — что функции как самостоятельного объекта в природе не существует, а есть только её адрес. То есть наряду с исходной семантикой допустили также следующее:

    p = f;      /* считаем, что функция и её адрес -- одно и то же */
    p(13);  /* считаем, что адрес функции и есть сама функция */

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

С тем, что взятие адреса функции «не обязательно», товарищи Керниган и Ритчи более-менее смирились, во всяком случае в имеющемся у меня издании K&R (Вильямс, 2006) (параграф 5.11) они амперсанд уже не используют, делая при этом оговорку, что-де «его можно не использовать». Но вот вызывают они функцию через указатель на неё — только с разыменованием. О том, что новый стандарт разрешает делать иначе, они упоминают только в «сводке изменений» в конце книги, где, судя по всему, с трудом нашли в себе силы не высказать всё, что думают по поводу пресловутого стандарта.

Croco ★★★
() автор топика
Ответ на: комментарий от Croco

Ай-вей, а вы в курсе различий между

char *s = "Hello";
и
char s[] = "Hello";
?

Второе создаёт переменную типа массив (имеющую соответствующий размер, возможно очень большой), а первое — переменную типа указатель (4 байта).

Фактически, между этими случаями ничего общего нет. Считаю «фичу» языка C синтаксически интерпретировать массивы как указатели большой ошибкой. Не раз в связи с этим приходилось на 1-м курсе объяснять студентам непонятки.

Сорри, что влез в дискуссию.

sasha1024
()
Ответ на: комментарий от Twissel

По логике вещей

Ну почти правильно, хотя совсем формально это должно быть

   char (*p)[14];

Чистый Си жрёт и так (gcc даже предупреждения не выдаёт), а вот если попробовать C++, то будет вот что:

bydlo.cpp:6: error: cannot convert 'char (*)[14]' to 'char (*)[]' in assignment

Croco ★★★
() автор топика
Ответ на: комментарий от sasha1024

Второе создаёт переменную типа массив (имеющую соответствующий размер, возможно очень большой), а первое — переменную типа указатель (4 байта).

Да, так оно и есть.

Фактически, между этими случаями ничего общего нет.

Ну как «ничего», если операция индексирования считается синонимом сложения с разыменованием, то кое-что общее всё-таки есть: к обоим объектам можно применять квадратные скобки, и результатом будет char.

Считаю «фичу» языка C синтаксически интерпретировать массивы как указатели большой ошибкой. Не раз в связи с этим приходилось на 1-м курсе объяснять студентам непонятки.

+1. Одна из причин, по которым я считаю C на первом курсе недопустимым. Сам преподаю Си на втором курсе студентам, которые уже знают Паскаль — этим нет никаких проблем объяснить, что за зверь «указатель на массив» (который int (*p)[15]), да и вообще никаких проблем нет, мозги уже окрепли, об сишные семантические кривости не сломаются.

Croco ★★★
() автор топика
Ответ на: комментарий от SZT

А что в этом плохого? (Нет, я не знаю этот вуз и этих людей, может, там действительно всё ужасно, но из методички этого мне не видно.)

У нас тоже в рамках курса «Архитектуры ЭВМ» изучали ассемблер PDP-11. Это для понимания каких-то базовых вещей (типа регистры, машинные коды, способы адресации и т.п.). Просто в современных процессорах много костылей, поэтому лучше начать разбирать с древних, но простых процессоров — и потом перейти к современным. Естественно, это только короткий кусок курса (условно, пару недель); если не ошибаюсь, у нас было PDP-11 -> что-то посвежее, но тоже древнее -> i386.

Псевдографика в ворде — Вы не поверите, ОЧЕНЬ удобно. Я сам к этому пришёл, когда писал лабы: да, tables, shapes и пр. гораздо красивее (и в серьёзном документе будешь использовать их), но псевдографика банально быстрее (и, когда тебе нужно быстро сдать N лаб M преподам, это решает).

sasha1024
()
Ответ на: комментарий от sasha1024

Считаю «фичу» языка C синтаксически интерпретировать массивы как указатели большой ошибкой. Не раз в связи с этим приходилось на 1-м курсе объяснять студентам непонятки.

+100500.

liberte
()
Ответ на: комментарий от Croco

если попробовать C++, то будет вот что

Это потому что от возможности достать размер в явном порядке уже не отвертеться, например:

template <typename array, unsigned size>
struct s<array[size]> { ... }

liberte
()
Последнее исправление: liberte (всего исправлений: 1)
Ответ на: комментарий от sasha1024

А что в этом плохого?

Знаете, кое-что в этом плохое есть, хотя и совсем не там, где это ищут участники дискуссии.

Изучение асма на эмуляторах плохо тем, что подспудно студенты получают подсознательную уверенность, что это только с эмулятором всё так гладко проходит, а с настоящим процом бы не прошло. А ещё есть вторая причина: я неоднократно видел, как наиболее сильные студенты начинают писать на асме не то, что им задали, а то, что им кажется прикольным — игрушки, например. Это если на живом асме. Если используется эмулятор (включая, например, MS-DOS, пусть даже под Win* это не совсем эмулятор), таких «приколов» можно не ожидать. Эмулятор программировани попросту не интересно. Ну не прикольно, ну вот так вот жизнь устроена. Настоящий проц «приручить» прикольно, хотя и не всем, а только самым продвинутым, а вот эмулятор не прикалывает никого, на нём сделал, что препод задал, и всё, пошёл в варкрафта гонять.

Croco ★★★
() автор топика
Ответ на: комментарий от Croco

Сам преподаю Си на втором курсе студентам, которые уже знают Паскаль — этим нет никаких проблем объяснить, что за зверь «указатель на массив» (который int (*p)[15])

Тут еще проблема в дурацком синтаксисе. Ну посудите сами:

uint8_t n1[][2] = {{1,2}, {3,4}, {5,6}, {99,88}};
uint8_t n2[][2] = {{7,8}, {9,10}, {11,12}, {99,88}};
uint8_t n3[][2] = {{13,14}, {15,16}, {17,18}, {99,88}};
    
// Надо сделать массив из указателей на двумерные массивы    
uint8_t (*ars[3])[2] = { n1, n2, n3}; // полная ерунда, нечитаемо. Как этот синтаксис объяснять студентам?
    
typeof( typeof(uint8_t [2]) *) ars2[3] = {n1, n2, n3}; // можно так
    
typeof( typeof(uint8_t [2]) *[3]) ars3 = {n1, n2, n3}; // можно еще так
    
typeof(uint8_t (*)[2]) ars4[3] = {n1, n2, n3}; // во, теперь норм!
этот метод через typeof(который является нестандартным расширением gcc) позволяет на мой взгляд сделать все значительно понятней, только с -ansi -pedantic он естественно не заработает. Можно можно делать через typedef-ы чтоб по-стандарту.

typedef uint8_t u8pair_t[2]
u8pair_t n1[] = {{1,2}, {3,4}, {5,6}, {99,88}};
u8pair_t n2[] = {{7,8}, {9,10}, {11,12}, {99,88}};
u8pair_t n3[] = {{13,14}, {15,16}, {17,18}, {99,88}};
u8pair_t *(ars[]) = {n1, n2, n3};

А, еще можно через структурки

typedef struct { uint8_t ar[4][2];} arr;
arr n1 = {{{1,2}, {3,4}, {5,6}, {99,88}}};
arr n2 = {{{7,8}, {9,10}, {11,12}, {99,88}}};
arr n3 = {{{13,14}, {15,16}, {17,18}, {99,88}}};
arr ars[] = {n1, n2, n3}; 

SZT ★★★★★
()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от sasha1024

У нас тоже в рамках курса «Архитектуры ЭВМ» изучали ассемблер PDP-11. Это для понимания каких-то базовых вещей (типа регистры, машинные коды, способы адресации и т.п.).

Зачем это изучать на каких-то архаичных неиспользуемых архитектурах? Какой в этом смысл? Если писать например в защищенным режимом на асме в среде GNU/Linux, что именно вы упускаете? Работу с прерываниями и запись в порты? Так для этого можно взять какой-нибудь ИСПОЛЬЗУЕМЫЙ в современном мире микроконтроллер и писать под него.

SZT ★★★★★
()
Ответ на: комментарий от liberte

Это потому что от возможности достать размер в явном порядке уже не отвертеться, например:

От «возможности достать размер» и в чистом Си не отвертеться. Указатель на массив используется, чтобы сделать семантически корректной первую индексацию в двумерном массиве. Вот есть массив вроде

   int m[10][20];

Надо, чтобы выражение m[5] (т.е. *(m+5) ) было таково, что к нему можно применить ещё одну индексацию, а её результатом будет соответствующий элемент строки матрицы. То есть m[5] должно быть адресом первого элемента пятой строки, то есть оно должно иметь тип int*, а указывать на начало пятой строки. Это, в свою очередь, значит, что прибавление единицы к m должно сдвигать адрес НА РАЗМЕР СТРОКИ.

Вот тут-то и возникает этот монстрик int (*p)[20] — «указатель на массив из 20 элементов типа int» (при том что самого массива вообще-то нет, ну то есть он есть, но как мёд из мультика про виннипуха — если он есть, то его сразу нет). Очевидно, если p указывает на начало матрицы, то p+1 должно быть адресом второй строки, и так далее. Так что размер обязан быть фиксированным и даже константой времени компиляции. Следовательно, и sizeof(*p) работает корректно, и арифметика.

Просто Си++ более строг — там, где чистый Си даже предупреждения не выдаёт, Си++ фиксирует фатальную ошибку.

Croco ★★★
() автор топика
Ответ на: комментарий от sasha1024

У нас тоже в рамках курса «Архитектуры ЭВМ» изучали ассемблер PDP-11.

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

SZT ★★★★★
()
Ответ на: комментарий от Croco

int m[10][20];

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

Все эти пляски вокруг «ай-ай-ай, в сях всё плохо с массивами» — такая хрень. Я уже плохо помню, как было с динамическими двумерными массивами в Паскале, но, кажется, приходилось делать y * N + x.

i-rinat ★★★★★
()
Ответ на: комментарий от suiseiseki_desu

Но тогда почему именно Паскаль, а не, скажем, Питон?

В Питоне сложная модель окружения (lexical scope), и нет статической типизации.
Паскаль мертв, студентам неинтересно. Тратить семестр на непрактичный язык это непозволительная роскошь.
Java с самого начала требует понимания OOP.
Си слишком низкоуровневой, и имеет путаную грамматику.

Нет сейчас нормального языка для вводного курса, это всегда дилемма. После вводного курса нет проблем — Си/Си++ для системного программирования и ОС, Java для OOP и сетевого программирования, Питон для SICP, ассемблер для архитектуры.

Студентов инженерных факультетов иногда учат Фортрану, но обычно Си.

liberte
()
Ответ на: комментарий от liberte

Нет сейчас нормального языка для вводного курса

Бред какой-то. Чем вас не устраивает C или C++ для вводного курса? В чём вообще проблема сначала давать студентам простейшее на C или C++ и постепенно переходить к сложному?

anonymous
()

Какой же хороший вброс, господа. Андрей Викторович зацарил просто.

crutch_master ★★★★★
()

Nim, например, просто идеальная замена C для новичков. Синтаксис как у Питона, при этом статическая типизация и работа с указателями.

anonymous
()
Ответ на: комментарий от SZT

Раз уж речь зашла о ВУЗах и тому, чему там учат. В одном питерском вузе учат писать под VAX в машинных кодах

ну а чем хуже MMIXа? Непрактично, да, но на машкодах PDP/VAX действительно можно было писать вручную. За ARM не скажу, а Intel этим точно не отличается (точнее отличается не, в смысле на уровне машкодов там ужас-ужас)

be_nt_all ★★
()
Ответ на: комментарий от anonymous

Бред какой-то. Чем вас не устраивает C или C++ для вводного курса? В чём вообще проблема сначала давать студентам простейшее на C или C++ и постепенно переходить к сложному?

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

be_nt_all ★★
()
Ответ на: комментарий от anonymous

Nim, например, просто идеальная замена C для новичков. Синтаксис как у Питона, при этом статическая типизация и работа с указателями.

Да, очень неплох, но только использовать для преподования в ВУЗе язык с версией 0.13 это немного сильно авангардно

be_nt_all ★★
()
Ответ на: комментарий от SZT

Просто переведя первую и вторую сортировку в язык для STM-солвера

А кто докажет, что нет ошибки в переводе?

Deleted
()
Ответ на: комментарий от be_nt_all

У него сборщик мусора. Это не устраивает Столярова. Тогда можно и D использовать, он ближе к Си-подобным и для него полно библиотек уже. При этом проблемы с массивами и стандартною библиотекою не возникнут.

Vudod ★★★★★
()
Ответ на: комментарий от Croco

Ну и это тоже, но есть же более очевидные различия. В первом случае s — леводопустимое, то есть это переменная, которой можно что-то присваивать. Во втором случае это имя массива, а именам массивов ничего присваивать нельзя. В первом случае sizeof(s) есть размер указателя (зависит от платформы, на i386 будет 4, на x86-64 будет 8), тогда как sizeof(s) во втором случае будет шесть (пять буковок и нолик в конце) вне всякой зависимости от платформы (ибо sizeof(char) есть по определению единица).

Возвращаясь к типам, &s в первом случае будет иметь тип char**, а во втором... во втором... А ВОТ ДОГАДАЙТЕСЬ!!! :-D

Жесть, я в шоке. Это же всё очевидно должно быть для любого программёра на Си. А люди путаются.

Deleted
()
Ответ на: комментарий от Croco

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

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

«Варвары-стандартизаторы» скорее всего пошли по пути «стандартизации существующей практики».

Deleted
()

Ёжкин компот! Две свежие страницы треда снова доставляют.

Люди путаются между массивами и указателями, не могут взять указатель на функцию, и при этом учат действующего преподавателя, как ему учить студентов!

Как бы ни был плох или хорош преподаватель, об этом несподручно судить человеку, который не осилил основы Си.

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.