Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Си
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2, 3, 4, 5, 6
igorle
Друзья. Эта тема создана Буратиной для Буратино. Он изучает С. Но в результате ветка превратилась в спор о дистнинкциях между несколькими опытными профессионалами. Это то, чего я опасался - вместо обучения получается запугивание.

Давайте вернемся а TC. Если человек пришел с вопросом, то надо отвечать на его языке. Любое знание должно прорасти. И его надо оберегать на начальных периодах. А если начинать тригонометрию не с прямоугольных прямоугольников, а с тригонометрических функций комплексных переменных, то толку не будет.

То что очевидно опытному - не сразу понятно начинающему. Время нужно.

Кстати, никто не ответил ясно на мой вопрос. Повторю. Что будет напечатано на 32 битном процессоре (решить на листочке, без компилятора):
Код
int** my_array=GenerateArray(6, 9);
int  your_array[6][9];

printf("%z %z\n", sizeof(my_array), sizeof(your_array));


К вопросу о споре. Я понимаю обе стороны. Позиция ReAl мне ближе. Просто Буратино жалко. Он уже сбежал из своей ветки.
sasamy
Цитата(igorle @ Mar 2 2013, 18:51) *
Забавно. Никогда так не делал. Первая реакция была - "ерунда".


Причем первая реакция была правильной sm.gif это не массив а мутант

Код
int** GenerateArray(int dim1, int dim2)
{
int** rv=new int*[dim1];
for(int i=0;i<dim1;++i)
  rv[i]=new int[dim2];
return rv;
}


Цитата
An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type.


и даже динамическим мутантом его назвать сложно - нужно еще специальную ф-цию написать чтобы изменить его размерность в динамике.
Tahoe
Цитата(ReAl @ Mar 3 2013, 13:56) *
Ну хорошо.
«is converted to an expression with type ‘‘pointer to type’’»
приводится к выражению типа «указатель на»
Не к «переменной типа „указатель на”». А к выражению. Приводится, а не есть им.

Ну хорошо. (с) Потому что:
Цитата(Tahoe @ Mar 3 2013, 12:53) *
Что там происходит дальше, на что похоже, как оптимизируется и т.п. - дело десятое.


И что бы стало совсем понятно, о чем речь, наглядная демонстрация, что "адрес" != "указатель":
Код
uint8_t    Array[8];
Array++;

на выходе получим:
Цитата
Error[Pe137]: expression must be a modifiable lvalue



Цитата(igorle @ Mar 3 2013, 14:20) *
Друзья. Эта тема создана Буратиной для Буратино. Он изучает С. Но в результате ветка превратилась в спор о дистнинкциях между несколькими опытными профессионалами. Это то, чего я опасался - вместо обучения получается запугивание.

Вот я как раз именно об этом. Да не обидится ReAl, но объяснять, это отдельное искусство. Знаю много грамотных спецов, однако, дай Б-г, если четверть из них в состоянии внятно объяснить то, чем сами отлично владеют.
sasamy
Цитата(Tahoe @ Mar 4 2013, 09:36) *
И что бы стало совсем понятно, о чем речь, наглядная демонстрация, что "адрес" != "указатель":


это не совсем наглядно - с константным указателем тоже ничего хорошего не получим.
Цитата
A pointer type describes an object whose value provides a reference to an entity of the referenced type.


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

Tahoe
Цитата(sasamy @ Mar 4 2013, 10:57) *
это не совсем наглядно - с константным указателем тоже ничего хорошего не получим.

"И о чем нам это должно говорить?" (с) Константный указатель, это по-прежнему указатель, даже если мы сознательно запретили его изменять.
Собсно, зачем я буду пересказывать классиков своими словами... K&R - Язык C - 5.3. Указатели и массивы.


И, на всякий случай повторюсь, что там в итоге наоптимизируется, во что в итоге превратится - дело десятое.


UPD
На данном этапе, новичку надо не про оптимизации рассказывать, а вбить в голову простую мысль, что адрес и указатель, вещи тесно связанные, но это не одно и то же!
sasamy
Цитата(Tahoe @ Mar 4 2013, 12:22) *
"И о чем нам это должно говорить?" (с)


О том что переводы классиков и сферические примеры только путаницу вносят и судя по всему понимание у вас только на уровне мантр, тогда ка загляни новичек в стандарт языка - там все четко и недвусмысленно описано.
XVR
Цитата(Tahoe @ Mar 4 2013, 09:36) *
Да не обидится ReAl, но объяснять, это отдельное искусство. Знаю много грамотных спецов, однако, дай Б-г, если четверть из них в состоянии внятно объяснить то, чем сами отлично владеют.

Увы, не в объяснении дело. Дело в том, что обсуждение перешло на уровень, который явно не по зубам новичку. Плюс к этому еще перемешали понятия (например - динамический массив из моего примера не имеет никакого отношения к понятию многомерный массив языка С, и не надо их сравнивать rolleyes.gif )

Подробно объяснить что к чему сможет либо разработчик компиляторов, либо автор стандарта С. Но понять его сможет только второй такой же специалист laughing.gif
Tahoe
Цитата(XVR @ Mar 4 2013, 13:04) *
обсуждение перешло на уровень, который явно не по зубам новичку

Отнюдь. Как раз понять элементарное, чем отличается адрес от указателя - вполне по силам. И даже необходимо.

Цитата(XVR @ Mar 4 2013, 13:04) *
Подробно объяснить что к чему сможет либо разработчик компиляторов, либо автор стандарта С.

Нет. Объяснить/научить, это совершенно отдельная песня. Мало знать предмет, надо иметь еще навык педагога, если угодно. Одно и то же, можно объяснить разными путями, причем в одном случае, будет сразу все понятно, а в другом - хоть до дыр зачитай, ничего не поймешь.
sasamy
Цитата(XVR @ Mar 4 2013, 13:04) *
например - динамический массив из моего примера не имеет никакого отношения к понятию многомерный массив языка С, и не надо их сравнивать rolleyes.gif )

Подробно объяснить что к чему сможет либо разработчик компиляторов, либо автор стандарта С. Но понять его сможет только второй такой же специалист laughing.gif


Тот пример что вы привели не является массивом - ни динамическим ни многомерным, и не надо тут быть разработчиком компиляторов или автором стандартов. Во первых (и самое главное) несколько подряд new не гарантируют непрерывность, во вторых динамичность подразумевает возможность в любое время изменить размер, в третьих С - это не С++ (malloc/realloc), в четвертых в C99 появились variable-length arrays, в пятых в С++ есть std::vector sm.gif
XVR
Цитата(sasamy @ Mar 4 2013, 16:47) *
Во первых (и самое главное) несколько подряд new не гарантируют непрерывность,
А где там требуется непрерывность?
Цитата
во вторых динамичность подразумевает возможность в любое время изменить размер,
Отнюдь, возможность изенения размера является желательным, а не необходимым свойством.
Цитата
в третьих С - это не С++ (malloc/realloc),
Замените new на malloc, если так будет по феншую rolleyes.gif
Цитата
в четвертых в C99 появились variable-length arrays,
Это есть, признаю.
Цитата
в пятых в С++ есть std::vector sm.gif
Он одномерный. А vector<vector<>> - это вообще монстр (хотя и многомерный laughing.gif )
sasamy
Цитата(XVR @ Mar 4 2013, 21:33) *
А где там требуется непрерывность?


Если говорим о С/C++ непрерывность требуется для доступа к элементам массива, цитату из стандарта я вам уже приводил.
XVR
Цитата(sasamy @ Mar 4 2013, 22:19) *
Если говорим о С/C++ непрерывность требуется для доступа к элементам массива,
Мы не говорим о массиве в понимании С/С++.
Цитата
цитату из стандарта я вам уже приводил.

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


Давайте назовем это (то, что было в моем примере) не массив, а 2х мерная динамическая матрица - теперь все довольны? laughing.gif
sasamy
Цитата(XVR @ Mar 5 2013, 09:58) *
Мы не говорим о массиве в понимании С/С++.


Странно, в каком понимании тогда говорить о массивах в теме с заголовком "Си" sm.gif с вашего позволения напишу в понимании Си
CODE

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void true_arr(int m, int n)
{
int a[m][n];
int *p = &a[0][0];

for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
a[i][j] = i*n + j;
printf("%d\t", p[i*n + j]);
}
puts("");
}

printf("sizeof(a) = %lu\n", sizeof(a));
}

int main(void)
{
srand(time(NULL));
int m = 1 + rand() % 10;
int n = 1 + rand() % 10;

true_arr(m, n);

return 0;
}


результат
CODE

sasa@sasa-laptop:~/tst$ gcc -Wall -std=c99 array.c && ./a.out
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
sizeof(a) = 200
sasa@sasa-laptop:~/tst$ gcc -Wall -std=c99 array.c && ./a.out
0 1 2 3 4 5 6
sizeof(a) = 28
sasa@sasa-laptop:~/tst$ gcc -Wall -std=c99 array.c && ./a.out
0 1 2 3 4 5 6 7 8 9
sizeof(a) = 40
sasa@sasa-laptop:~/tst$ gcc -Wall -std=c99 array.c && ./a.out
0 1 2 3 4 5 6 7
8 9 10 11 12 13 14 15
16 17 18 19 20 21 22 23
sizeof(a) = 96
sasa@sasa-laptop:~/tst$ gcc -Wall -std=c99 array.c && ./a.out
0
1
sizeof(a) = 8
sasa@sasa-laptop:~/tst$ gcc -Wall -std=c99 array.c && ./a.out
0 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
sizeof(a) = 84
XVR
Цитата(sasamy @ Mar 5 2013, 12:47) *
Странно, в каком понимании тогда говорить о массивах в теме с заголовком "Си" sm.gif
Гм, позволю себе напомнить, о чем вообще идет речь. А идет она об ответе на вот эту фразу -
Цитата
Я вот думаю, что указатель на указатель используется только как формальный аргумент функции. А в качестве фактического аргумента используют адрес простого указателя. Не вижу смысла в использовании указателя на указатель где-то еще.
Вот Я привел пример как его (указатель на указатель) еще можно использовать. Назвал это 'Многомерный динамический массив'. С какого перепугу вы решили, что речь шла об массивах в С мне честно говоря не понятно rolleyes.gif
Цитата
с вашего позволения напишу в понимании Си
И какое отношение это имеет к вопросу о 'применении указателя на указатель'?
sasamy
Цитата(XVR @ Mar 5 2013, 13:04) *
Я привел пример как его (указатель на указатель) еще можно использовать. Назвал это 'Многомерный динамический массив'.


Назвать вы про себя можете как угодно, только мысль озвучена неправильно, в контексте Си вы привели пример массива указателей
Цитата
int** rv=new int*[dim1];


Цитата
INT A[10][10];
INT *B[10];

то A и B можно использовать сходным образом в том смысле,
что как A[5][5], так и B[5][5] являются законными ссылками
на отдельное число типа INT. Но A - настоящий массив: под
него отводится 100 ячеек памяти и для нахождения любого ука-
занного элемента проводятся обычные вычисления с прямоуголь-
ными индексами. Для B, однако, описание выделяет только 10
указателей; каждый указатель должен быть установлен так,
чтобы он указывал на массив целых. если предположить, что
каждый из них указывает на массив из 10 элементов, то тогда
где-то будет отведено 100 ячеек памяти плюс еще десять ячеек
для указателей. Таким образом, массив указателей использует
несколько больший объем памяти и может требовать наличие яв-
ного шага инициализации.


заметьте - в K&R нигде не упоминается что это сферический 'Многомерный динамический массив'

Цитата
С какого перепугу вы решили, что речь шла об массивах в С мне честно говоря не понятно rolleyes.gif


в топике прочитал, мысли читать не умею.
XVR
Цитата(sasamy @ Mar 5 2013, 13:33) *
Назвать вы про себя можете как угодно, только мысль озвучена неправильно,
Вы телепат, умеете читать мысли? Конечно, вырвать из контекста одно слово и объявить всем (в том числе и автору), что именно он имел в виду, а потом объяснить, что это не правильно - это самый лучший способ вести спор. 1111493779.gif

Я еще раз заявляю - тот пример, который я приводил, не имеет отношения к массивам в С, и к K&R тоже.

Цитата
в топике прочитал, мысли читать не умею.
А кроме названия топика не пробовали читать то, на что пытаетесь отвечать? Очень помогает, знаете ли.

За сим спор с вами прекращаю, за бесполезностью. Вы сами придумали за меня, что я имел в виду, а теперь это опровергаете, упорно игнорируя любые попытки добиться взаимопонимания. smile3009.gif

Буратино
ну хорошо, а как правильно обращаться к указателю на который указывает указатель, если я получаю указатель на указатель через формальный параметр в функции? Вот например: есть функция BDD, в параметрах у нее указатель на указатель. Внутри функции мне нужно выделить динамически память под некоторый буфер. Мне разыменовывать получается нужно указатель на указатель для того чтоб получить указатель "первого порядка"?

Код
void BDD (char **a) {  
   free (*a);
   *a = malloc(1000);
   ...
}



int main() {
   char *s = NULL;
   BDD(&s);
...
}
SSerge
Цитата(Буратино @ Mar 15 2013, 14:52) *
ну хорошо, а как правильно обращаться к указателю на который указывает указатель,

Да, так. Но можно передавать параметр по ссылке.
В выражениях ссылка разыменовывается автоматически, не надо подсчитывать звёздочки.
Код
void BDDК (char* &ref)
{  
   free (ref);
   ref = malloc(1000);
   ...
}

int main() {
   char *s = NULL;
   BDDR(s);
...
}

andrew_b
Цитата(Буратино @ Mar 15 2013, 11:52) *
Код
void BDD (char **a) {  
    free (*a);
    *a = malloc(1000);
    ...
}
А почему не realloc(*a)?

Цитата(SSerge @ Mar 15 2013, 13:13) *
Да, так. Но можно передавать параметр по ссылке.
В выражениях ссылка разыменовывается автоматически, не надо подсчитывать звёздочки.
Код
void BDDК (char* &ref)
{  
    free (ref);
    ref = malloc(1000);
    ...
}
В Си?
demiurg_spb
Цитата(andrew_b @ Mar 15 2013, 13:19) *
В Си?
Нет конечно.
igorle
Цитата(Буратино @ Mar 15 2013, 10:52) *
ну хорошо, а как правильно обращаться к указателю на который указывает указатель?...

У Вас все правильно.
С остальными ораторами я не согласен.
realloc - не нужен, так как Вам не нужны старые данные, и поведение реаллока отличается при недостатке памяти.
А передача параметров по ссылке к Си отношения не имеет.
Буратино
Спасибо!

Есть вот такой код:
Код
int j;
int j = 400;


Первая строка это так называемое предварительное объявление (tentative definition). Зачам так делают? Для чего это нужно?
igorle
Цитата(Буратино @ Mar 18 2013, 17:21) *
Спасибо!
Есть вот такой код:
Код
int j;
int j = 400;

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

В классическом Си все автоматические переменные должны декларироваться в начале блока. Некоторые диалекты Си и классический С++ позволяют объявлять переменные в любом месте. Но я считаю, что это плохая привычка.
Буратино
На сколько мне известно в Си существует объявление и определение переменной. Инициализирована переменная может быть только в определении. Автоматические переменные это один из классов переменной и я так понимаю определяться и инициализироваться они могут в любой части функции, а существуют они и правда внутри конкретного операторного блока. Так, переменных "i" в одной функции может целая куча..
Код
#include <stdio.h>
#include <stdlib.h>


int main() {
   int i=1;
  
   printf ("%d\n", i);
   if (1) {
      int i=2;
      printf ("%d\n", i);
      if (1) {
         int i=3;
         printf ("%d\n", i);
      }
   }
}
ARV
за наличие в пределах одной функции трех определений одинаковой переменной (типа вашего int i) убивать надо
igorle
Чтобы пример стал более наглядным, я предлагаю переписать его так:
Код
#include <stdio.h>

int main(void)
{
    int i=1;
    {
        int i=2;
        {
            int i=3;
            printf("%d\n", i);
        }
        printf("%d\n", i);
    }
    printf("%d\n", i);
    return 0;    
}



2 ARV - ну это же дается не как рабочий код, а как демонстрация того, как работает язык Си.
toweroff
Согласен с ARV. Отшибить руки за такое, пусть даже и стандартами оно и дозволено help.gif
andrew_b
Цитата(igorle @ Mar 19 2013, 18:24) *
В классическом Си все автоматические переменные должны декларироваться в начале блока. Некоторые диалекты Си и классический С++ позволяют объявлять переменные в любом месте.
Это позволяет уже С99. Самый что ни на есть классический диалект.
demiurg_spb
Цитата(ARV @ Mar 19 2013, 22:02) *
за наличие в пределах одной функции трех определений одинаковой переменной (типа вашего int i) убивать надо
Это три разные переменные.

Цитата(igorle @ Mar 19 2013, 22:09) *
Чтобы пример стал более наглядным, я предлагаю переписать его так:
А я предлагаю такой вариант.
Код
int main(void)
{
    for (int i=0; i<3; i++)
    {
        for (int i=0; i<3; i++)
        {
            printf("%d\t", i);
        }
        puts("");
    }

    return 0;    
}
И это 100% рабочий код, выводящий в консоль:
Код
0 1 2
0 1 2
0 1 2
Я не агитирую никого так писать. Но понимать надо, что так тоже можно и это не криминал.
Просто у переменных разная область видимости и переменные вложенного блока имеют приоритет видимости над внешними.
А вот с глобальными не статическим переменными-тёзками другая песня и они сливаются воедино...
Цитата(andrew_b @ Mar 20 2013, 08:52) *
Это позволяет уже С99. Самый что ни на есть классический диалект.
+1 за максимально отложенное объявление переменных максимально близко к месту их использования. Где родился - там и пригодился:-)
XVR
Цитата(Буратино @ Mar 18 2013, 17:21) *
Спасибо!

Есть вот такой код:
Код
int j;
int j = 400;


Первая строка это так называемое предварительное объявление (tentative definition).
В C++ это ошибка. С это позволит, но делать так не надо!

Цитата
Зачам так делают?
Делают не так, а так:
Код
extern int j;
int j = 400;

Цитата
Для чего это нужно?
Строку с extern помещают в header, что бы не только ваш С файл знал о существовании этой переменной, но и другие модули (читай - С файлы) знали, и могли ею воспользоваться.

NB. Но называться она должна не 'j', а как то более осмысленно
igorle
Цитата(toweroff @ Mar 19 2013, 22:40) *
Согласен с ARV. Отшибить руки за такое, пусть даже и стандартами оно и дозволено help.gif

Господа toweroff и ARV
Вы путаете понимание языка и применение.
Например, вы должны понимать как работает arr[5] должны так писать
Вы должны понимать, как работает *(arr +5), но писать так должны только в некоторых, специальных случаях
Вы никогда не должны писать такой код:
Код
int main(void)
{
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int i;

    for (i = 0; i <10; i++)
        printf("%d ", i[arr]);
    printf("\n%d\n", 5[arr]);
    return 0;
}

Но неплохо бы понимать, как и почему это работает.
Ну а если вы не поволяете людям объяснять как и почему работает 5[arr], мотивируя тем, что так писать нельзя, то я с вами не согласен.
demiurg_spb
Цитата(igorle @ Mar 20 2013, 12:13) *
+100500
Из той-же оперы, но вполне юзабельное:
Код
for (int i=0; i<10; i++)
{
    printf("%c\t", "abcdefghig"[i]);
}
igorle
Цитата(demiurg_spb @ Mar 20 2013, 11:45) *
Из той-же оперы, но вполне юзабельное:

Да, например, можно вызывать эту функцию внутри медленного цикла. Пользователь будет видеть, что процесс идет:
Код
static void fan(void)
{
    static char idx;
    printf("\x1b[1D%c", "|/-\\|/-\\"[++idx & 0x3]);
}

Должно работать на стандартной консоли (не проверял, может быть ошибка в коде сдвига курсора на одну позицю влево)
И это уже не демо, а реальный код.
ARV
Цитата(demiurg_spb @ Mar 20 2013, 09:28) *
Это три разные переменные. Я не агитирую никого так писать. Но понимать надо, что так тоже можно и это не криминал.
разные по сути, но одинаковые внешне. скажите, вам больше делать нечего, кроме как напрягать мозг для разбирательства, кто есть ху в этой программе? лично мне это не нужно, и, уважая читателей моего кода (если таковые найдутся), я никогда не напишу так, чтобы они лишний раз напрягались. для напряжения туалет есть, и там это вполне уместно, но не в остальном.

Цитата(igorle @ Mar 20 2013, 12:13) *
Господа toweroff и ARV
Вы путаете понимание языка и применение.
лчно я не путаю. МОЖНО испражняться, не снимая штанов, но НУЖНО ли?! даже не хочется думать о том, чем может быть мотивировано такое поведение, хотя наверняка бывают случаи, когда это неизбежно. но рассказывать об этом под лозунгом "это МОЖНО", тем более в теме для начинающих (т.е. как бы обучая) я бы никогда не стал. это попросту лишнее.

Си содержит массу вариантов того, что позволяет сделать код нечитаемым. Мне неизвестны мотивы изобретателей этого языка, которые разрешили запись a[5] и 5[a] как эквиваленты, и признаюсь честно - я не в восторге от такого изобилия возможностей. если найдется здесь человек, который неопровержимо докажет исключительную НЕОБХОДИМОСТЬ наличия такой возможности (за исходный вариант примем классику a[5]) - я сожру последние 10 страниц написанных мной исходников sm.gif


Си не станет хуже, если вся эта экзотика останется невостребованной, и о ней будет знать крайне узкий круг гуру. Более того, все остальные не-гуру не пострадают от этого абсолютно!

P.S. как-то вышло так, что в моем посте примеры и аналогии какие-то "неприличные" - извините, но сделал это умышленно, стараясь увязать код на основе "допустимых вариантов записей" с тем, что такой код напоминает.



Цитата(igorle @ Mar 20 2013, 13:17) *
Да, например, можно вызывать эту функцию внутри медленного цикла. Пользователь будет видеть, что процесс идет:
Код
static void fan(void)
{
    static char idx;
    printf("\x1b[1D%c", "|/-\\|/-\\"[++idx&0x3]);
}

Должно работать на стандартной консоли (не проверял, может быть ошибка в коде сдвига курсора на одну позицю влево)
И это уже не демо, а реальный код.
скажите, а пробелы между операторами и операндами вы не ставите умышленно, с целью продемонстрировать, как белиберда внешне может оказаться "реально работающим кодом"? см. выше - попытка возвыситься над толпой за счет использования законно разрешенных "сверх"возможностей Си показывает наличие каких-то комплексов...
igorle
2 ARV
- Пробелы можно добавить вокруг & - [++idx & 0x3] Обычно взгляд автоматически парсит такие строки, но в общем - принимаю. Здесь пробелы не повредят. Сейчас поправлю.
- Не надо жрать исходники. a[5] и 5[a] - не самоцель. Это демонстрация того как работает оператор [ ]. Если Вам это не интересно - то это нормальная позиция для ремесленника, но странная для творческого человека. Хотя знаете, мне сын доказывал, что привычка понимать суть - вредная привычка, так как мешает двигаться вперед быстро. Может быть Вы и правы. Работает - ну и хрен с ним.
- Эта ветка не про то, как решить конкретную проблему, а про то, как работает Си. Поэтому демострации могут и должны быть утрированы. Типа - вложенных блоков с автоматической переменной с тем же именем. Так как наглядно демонстрирует область определения переменной.
- Насчет "попытки возвыситься" - извините что доставил Вам неудобство.
Сергей Борщ
QUOTE (ARV @ Mar 20 2013, 11:38) *
см. выше - попытка возвыситься над толпой за счет использования законно разрешенных "сверх"возможностей Си показывает наличие каких-то комплексов...
Вот это вы какую-то ерунду написали. Вполне нормальный, читабельный и рабочий код. Не надо обзываться, если он для вас непивычен. Также для многих непривычен тернарный оператор A ? B : C; но это не повод требовать его запрета. В некоторых случаях он просто незаменим, а во многих других исключительно удобен. Когда понимаешь. А когда не понимаешь - любой код кажется диким.
ViKo
Если массив задан a[5], то 5[a] выходит за его границы. Удивляюсь, как оно работает (в смысле 4[a] и т.п.). И зачем? sm.gif
mdmitry
Цитата(igorle @ Mar 20 2013, 12:17) *
Код
...
    printf("\x1b[1D%c", "|/-\\|/-\\"[++idx & 0x3]);


Зачем повторения в массиве? А может тогда уж короче:
Код
    printf("\x1b[1D%c", "|/-\\"[++idx & 0x2]);

ViKo
Цитата(mdmitry @ Mar 20 2013, 14:24) *
Зачем повторения в массиве? А может тогда уж короче:

Только оставить & 0x3, ограничиваться двумя младшими битами.
ARV
я прошу всех, высказывающихся против моей точки зрения, привести аргументы ПОЛЕЗНОСТИ всех этих "непривычных" способов записи и т.п. штук, которые ДОПУСТИМЫ синтаксисом языка. только прошу аргументы более существенные, нежели "рабочий код", "короткий вариант записи" и т.п. я готов принять вариант "по-другому невозможно".

по поводу резкости высказывания про "комплексы". я просто очень сильно подозреваю, что в момент разработки языка авторами владела эйфория "сдлать супер-пупер", и они ввели все эти нюансики, смысл которых на практике отсутствует, и, кроме повода некоторым показать свои знания, никакой иной пользы не приносит. поэтому я думаю, что надо потихоньку забывать то, что не является НЕОБХОДИМЫМ, ибо язык программирования - это не способ самовыражения, а инструмент для работы. а инструмент красив своей лаконичностью, а не рюшечками.

извините, что не следую общепринятым догмам. это как раз из-за привычки думать и осмысливать суть. просто единственная возможная для меня оценка существующей реальности - излишество. и я об этом говорю открыто.
igorle
Цитата(mdmitry @ Mar 20 2013, 15:24) *
Зачем повторения в массиве? А может тогда уж короче:
Код
    printf("\x1b[1D%c", "|/-\\"[++idx & 0x2]);

Да, это я сглупил. Дважды. Объявил восемь символов, а использовал только 4 (маска 0x3). Я хотел написать вот так:

printf("\x1b[1D%c", "|/-\\|/-\\"[++idx & 0x7]);

Но следовало так, как Вы говорите:

printf("\x1b[1D%c", "|/-\\"[++idx & 0x3]);

Цитата
Если массив задан a[5], то 5[a] выходит за его границы. Удивляюсь, как оно работает (в смысле 4[a] и т.п.). И зачем?

Массив не задан a[5]. Массив задан, например, a[10]. Здесь демонстрировалось, что a[5] и 5[a] дает одинаковый результат.

Вопрос "зачем" здесь не логичен. Правильнее спрашивать - "почему". Понятно, что Кениган и Ритчи не говорили "а давай мы здесь впиндюрим такую фичу". Нет, но они говорили - смотри как изящно можно реализовать оператор квадратные скобки". И то, что теперь на Си конечный (машинный) код получается гораздо лучше, чем большинство могут написать на Ассемблере - заслуга изящества Си
Сергей Борщ
QUOTE (ARV @ Mar 20 2013, 14:01) *
аргументы ПОЛЕЗНОСТИ всех этих "непривычных" способов записи и т.п. штук, которые ДОПУСТИМЫ синтаксисом языка. только прошу аргументы более существенные, нежели "рабочий код", "короткий вариант записи" и т.п. я готов принять вариант "по-другому невозможно".
Просите аргументы полезности, но готовы принять лишь аргументы необходимости. "рабочий код" и "короткий вариант записи" вместе дают лаконичность записи, а значит упрощают сопровождение. Если вам это не нравится или ваш уровень владения С пока недостаточен - никто не заставляет вас использовать эти приемы. Но и махать шашкой на остальных тоже не нужно. Поверьте, все люди разные и кому-то это действительно удобно именно из-за лаконичности.
mdmitry
Цитата(ViKo @ Mar 20 2013, 14:28) *
Только оставить & 0x3, ограничиваться двумя младшими битами.

Конечно! Немного невниматеьности с моей стороны, увы 01.gif
igorle
Все мы консервативны и держимся за свои привычки. Интересно наблюдать за человеком, который первый раз видит двойной восклицательный знак:
Код
int a, b;
a = 27;
b = !!a;
Многие сначала офигевают, и спорят, что это невозможно понять. А через время смотришь - сами так писать начинают. Привыкли.

Кстати, я проверял скомпилированный код для трех случаев:
Код
b = !!a;
b = a ? 1 : 0;
if (a)
    b = 1;
else
    b = 0;
Во всех трех случаях gcc дает одинаковый результат.
ARV
Цитата(igorle @ Mar 20 2013, 16:19) *
Понятно, что Кениган и Ритчи не говорили "а давай мы здесь впиндюрим такую фичу". Нет, но они говорили - смотри как изящно можно реализовать оператор квадратные скобки". И то, что теперь на Си конечный (машинный) код получается гораздо лучше, чем большинство могут написать на Ассемблере - заслуга изящества Си
в вашей трактовке слово "изящно" звучит неприкрыто по-гламурному: "смотри, какую изящную сумочку я вчера купила".

обилие НЕНУЖНЫХ вариаций одного и того же я лично не могу назвать изящностью. бОльшую часть своей жизни я писал на паскале, и при знакомстве с Си был неприятно поражен его синтаксисом. однако, со временем я признал плюсы Сишной лаконичности, и теперь паскаль кажется несколько громоздким - но не более! убрать громоздкость записи - это плюс, хотя за счет того, что едва ли не каждый символ имеет массу смыслов в зависимости от местоположения в строке. например, звездочка или амперсенд. по-моему, в этом случае с краткостью Керниган перебрал малёхо.


или способ чтения описания типа переменной. где логика?! если int i вопросов не вызывает (слева направо читаем и смысл понятен), то int (*ptr)(void) уже не так - слева направо не прокатывает, ибо начинать надо с середины и затем читать слева направо с перескоком через середину... почему?! возможно, когда-то это казалось красивым, но красота в логике, а порядок чтения записей на данном примере нелогичен.

мне кажется, все мы знаем русский язык в ПОЛНОМ его объеме, втом числе с матерными идиомами. однако, большинство из нас придерживается правила неиспользования этих слов в своей речи, во всяком случае здесь, на форуме, т.е. публично. никто же не призывает обучать детей русскому языку вместе с матами! я сторонник того, что рассказывать о 5[a] - это что-то из той же оперы: да, есть такая загогулина в Си, но приличные программисты ее не используют и уж тем более новичкам о ней не рассказывают. кому станет хуже от этого подхода? разумеется, можно описать указатель на функцию с тремя параметрами, каждый из которых является указателем на функцию с тремя параметрами, каждый из которых.... (и так далее) в виде одной строки (кстати, уважаемые сторонники изящества Си - сумеете ли вы с первой попытки это изобразить?), но ЗАЧЕМ?!?!?! это МОЖНО, но СОВЕРШНЕННО НЕ НУЖНО делать!!!

разве я не прав?

P.S. встречал извращение из области джавы: оказывается, можно едва ли не любую программу написать без использования цифр и букв, и что-то типа +!![] будет "корректно исполняемым кодом джава" вот статья. встречал аналогичное и из области Си: создаются дефайны, и в итоге программа превращается в такое: давай печатай бля про мир (это для вывода хелловорда) - но разве это имеет отношение к программированию?!



Цитата(Сергей Борщ @ Mar 20 2013, 16:21) *
Просите аргументы полезности, но готовы принять лишь аргументы необходимости. "рабочий код" и "короткий вариант записи" вместе дают лаконичность записи, а значит упрощают сопровождение. Если вам это не нравится или ваш уровень владения С пока недостаточен - никто не заставляет вас использовать эти приемы. Но и махать шашкой на остальных тоже не нужно. Поверьте, все люди разные и кому-то это действительно удобно именно из-за лаконичности.
хотелось бы найти такого челоека, кому запись типа 5[а] на самом деле помогает добиться какого-то положительного результата - о чем я и обращаюсь ко всем апоголетам "лаконичности". по-моему, знания затмили для вас истину sm.gif помните о бритве Оккама? не плоди сущности без необходимости!

Цитата(igorle @ Mar 20 2013, 16:31) *
Все мы консервативны и держимся за свои привычки. Интересно наблюдать за человеком, который первый раз видит двойной восклицательный знак:
Код
int a, b;
a = 27;
b = !!a;
Многие сначала офигевают, и спорят, что это невозможно понять. А через время смотришь - сами так писать начинают. Привыкли.

да, конечно, этот вариант самый короткий. но с моей точки зрения даже рабочая секунда Билла Гейтса не стоит того, чтобы экономить ее на более "спокойной" записи a = b ? 1 : 0;

кстати, вы УВЕРЕНЫ, что результат !0 будет ОБЯЗАТЕЛЬНО 1 ВСЕГДА ? в Си есть ряд вещей, на которые никогда нельзя положиться, например, размерность int или знаковость char... я дословно стандарт не помню - написано там про это?

я уже когда-то говорил, но повторю и теперь.
сравним a = !!b и a = b ? 1 : 0
первая запись многим непонятна - даже автор этого примера сам об этом сказал, это факт. далеко не в каждой книжке по программированию на Си найдешь объяснение этого примера.
вторая запись более проста, и в любой книжке есть подобный пример.
следовательно, первый способ более элитный, доступный более узкому кругу "профессионалов", а второй - всем подряд. и, чтобы подтвержить свой профессионализм, т.е. выделться из серой массы, профессионал использует первую запись. но из приличия мотивирует это лаконичностью или еще чем-то, практическая польза чего столь же туманна.
только этот способ позволяет порой профессионалу поучить новичка - сокровенными знаниями.
таким образом, я прихожу к выводу, что кроме "выпендрежа", нет никаких иных мотивов использовать не совсем привычные конструкции, которые тем не менее допустимы синтаксисом. дело не в Си, дело впсихологии sm.gif
Сергей Борщ
QUOTE (ARV @ Mar 20 2013, 14:53) *
но ЗАЧЕМ?!?!?! это МОЖНО, но СОВЕРШНЕННО НЕ НУЖНО делать!!!

разве я не прав?
Не прав. Вы ведь используете в своей речи деепричастные обороты, хотя вполне можно строить предложения и без них и вообще обходиться словарным запасом людоедки Эллочки.
QUOTE (ARV @ Mar 20 2013, 14:53) *
хотелось бы найти такого челоека, кому запись типа 5[а] на самом деле помогает добиться какого-то положительного результата
Уже две страницы перед вами висит пример igorle, но вы отказываетесь его видеть. Вот вам еще один, аналогичный:
CODE
inline char to_hex(uint8_t tetrade) { return "0123456789ABCDEF"[tetrade & 0x0F]; }
Перепишите его в удобном для вас виде и докажите нам преимущества своего варианта.
igorle
Цитата(ARV @ Mar 20 2013, 16:53) *
да, конечно, этот вариант самый короткий. но с моей точки зрения даже рабочая секунда Билла Гейтса не стоит того, чтобы экономить ее на более "спокойной" записи a = b ? 1 : 0;


Все эти знания важны, чтобы во время программирования думать не о языке, а об алгоритме. Для этого надо говорить на языке свободно, а не со словарем. Тогда не будешь зависать над вопросами - чему равно (-3)%10

Чтобы лучше понять друг друга, попрошу Вас написать несколько строк кода.

Есть три переменны типа int - a,b,c;
В языке Си есть логические И и Или (&& ||), но нет логического XOR. Вам потребовалось сделать так, чтобы "с" была ксором от a и b.
Как вы это напишите в Вашем проекте?
ARV
Цитата(Сергей Борщ @ Mar 20 2013, 17:07) *
Перепишите его в удобном для вас виде и докажите нам преимущества своего варианта.

думаю, нет смысла переписывать sm.gif мой вариант будет просто понятен всем без исключения, в нем не будет изюминки, только и всего. но для вас, как я понимаю, это не аргумент sm.gif
любопытно было бы тем не менее получить ответ, чего достиг автор этого примера, кроме того, что создал небольшое затруднения для восприятия некоторым не очень опытным программистам, а так же установил жесткую привязку длины строки к магическому числу, т.е. сделал код менее универсальным?
Сергей Борщ
QUOTE (ARV @ Mar 20 2013, 15:21) *
мой вариант будет просто понятен всем без исключения
Мой непосредственный начальник не знает языков программирования. Он специалист по радосвязи. Думаю ему будет непонятен. Вот ведь конфуз - какой бы ни был простой код, для его понимания все равно нужны какие-то знания.

QUOTE (ARV @ Mar 20 2013, 15:21) *
кроме того, что создал небольшое затруднения для восприятия некоторым не очень опытным программистам
Он уменьшил свое время на разбор этого куска кода в дальнейшем, в процессе сопровождения проекта. Эта конструкция охватывается взглядом целиком и моментально анализируется. А "некоторых не очень опытных" заставит при встрече с этим кодом пополнить свои знания и стать чуть более опытными.

QUOTE (ARV @ Mar 20 2013, 15:21) *
, а так же установил жесткую привязку длины строки к магическому числу, т.е. сделал код менее универсальным?
Простите, это вы о чем?
ARV
Цитата(igorle @ Mar 20 2013, 17:20) *
Вам потребовалось сделать так, чтобы "с" была ксором от a и b.
Как вы это напишите в Вашем проекте?
разумеется, напишу не так "лаконично", как вы. но в чем я проиграю при этом, и в чем выиграете вы? вряд ли стоит учитывать время, потребное на написание кода или износ клаватуры...

возможно, я ваш код пойму с третьей минуты размышлений, а вы мой - с первой секунды, так чей же код будет лучше по критерию понимания? неужели ваша цель в том и состоит, чтобы таким, как я, осложнить жизнь? wink.gif

уверен, что после компиляции у нас обоих получится одно и то же в машинных кодах sm.gif


Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.