Форум программистов, компьютерный форум CyberForum.ru

C для начинающих

Войти
Регистрация
Восстановить пароль
 
 
zss
Модератор
Эксперт С++
6242 / 5845 / 1891
Регистрация: 18.12.2011
Сообщений: 14,975
Завершенные тесты: 1
#1

Распространенные ошибки - C (СИ)

02.10.2014, 12:49. Просмотров 35337. Ответов 57
Метки нет (Все метки)

Оглавление

Ошибки этапа компиляции
(В процессе компиляции выдается либо сообщение об ошибке, либо предупреждение)
- Попытка модифицировать константу через указатель
- Лишняя точка с запятой
- Отсутствие возврата значения из функции
- Приведение типа в стиле С++
- Использование = вместо ==


Ошибки этапа исполнения программы
(Во время исполнения программа прерывается с сообщением об ошибке)
- Возврат из функции локальной строки
- Выделение памяти без дальнейшего освобождения
- Использование неинциализированной переменной
- Использование функции strncpy как функции "безопасного" копирования строк
- Использование функций atoi/atof или sscanf для перевода строки в число
- Возврат ссылки/указателя на локальную переменную
- Выход за пределы массива
- Сравнение символьных массивов
- Использование чисел, записанных в других системах счисления.
- Работа с локальной копией объекта, вместо работы с самим объектом


Неправильное поведение программы на этапе исполнения
(Программа работает, но не так, как запланировано)
- Использование типов char, short и float при работе с va_arg
- Определение размера массива, переданного в качестве аргумента функции.
- "Неожиданное" закрытие окна.
- "Неожиданное" целочисленное деление в арифметических выражениях.
- Ошибки в логических выражениях.
- Использование символа цифры вместо числа
- Лишняя точка с запятой
- switch без break
- Сравнение вещественных чисел при вычислениях
- Проверки на принадлежность значения определенному интервалу.
- Неверный аргумент тригонометрических функций.
- Сравнение знаковой переменной с беззнаковой.
- Использование запятой для отделения дробной части
- Забытое выделение тела цикла for, while и операторов if else
- Локальная переменная экранирует переменную с таким же именем из вышестоящей области видимости
- Неправильное использование memset

Алгоритмические ошибки
(Неправильно составлен алгоритм программы)
- Двойная перестановка строк или элементов массива.

Ошибки ввода-вывода
- Ошибки при использовании функции scanf()!
- При работе с fgetc под Windows чтение файла обрывается при достижении буквы 'я'
- Оставление символа '\n' в потоке ввода
- scanf() - ввод текстовых строк

Ошибки, связанные с отклонением от стандарта языка
- Неверный тип функции main()
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
02.10.2014, 12:49     Распространенные ошибки
Посмотрите здесь:

C (СИ) 2 ошибки в программе
Ошибки в курсовой. Си C (СИ)
Странные ошибки C (СИ)
Ошибки в присваивании C (СИ)
C (СИ) В чем ошибки!?
C (СИ) Ошибки IntelliSense
C (СИ) Ошибки в терминале
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
3612 / 1887 / 501
Регистрация: 18.10.2014
Сообщений: 3,449
28.10.2014, 19:55     Распространенные ошибки #21
12. scanf() - ввод текстовых строк
Цитата Сообщение от zss Посмотреть сообщение
C++
1
2
3
char mass[N];
scanf("%s",mass); // так правильно
scanf("%s",&mass); // почему-то тоже срабатывает
А в чем проблема?

Такой вопрос обычно возникает у людей, которые считают, что массив физически представлен неким указателем на некий блок памяти. Соответственно ожидается , что '&mas' даст нам указатель на этот указатель и не будет работать в 'scanf'. Поэтому работоспособность такого 'scanf' зачастую вызывает удивление.

На самом деле массивы в языке С не являются и никогда не являлись указателями. Это очень популярная легенда, которая никак не хочет умирать, несмотря на то, что материалов, объясняющих семантику С массивов написано очень много на всех языках.

Массив - это просто непрерывный блок памяти, содержащий элементы массива. Т.е. например 'int a[20]' - это блок памяти из 20 объектов типа 'int'. И все. Имя 'a', как объект - это объект типа 'int [20]', который соответствует именно и только этому блок памяти. Никакого указателя там нигде нет.

Иллюзия того, что массив "является указателем" возникает из-за того, что когда вы используете имя массива в выражениях, то почти всегда к массиву применяется неявное преобразование типа, которое автоматически "на лету" преобразует объект типа "массив" к временному значению "указатель на элемент". Этот указатель является rvalue и нигде не хранится в памяти. Он существует только концептуально - как результат вышеупомянутого неявного преобразования. Это чисто воображаемый указатель.

По-английски явление "превращения" массива в указатель известно под устойчивым названием "array type decay". В стандарте языка С++ (где ситуация с массивами точно такая же) это неявное преобразование официально называется "array-to-pointer conversion".

Но это неявное преобразование применяется не всегда. В языке С существует три контекста-исключения, в которых это неявное преобразование не делается:

1) Оператор 'sizeof'. Как известно 'sizeof(array)' возвращает размер всего массива, а не размер указателя на элемент.
2) Унарный оператор '&'. Возвращает указатель типа "указатель-на-весь-массив", а не "указатель-на-указатель"
3) Инициализация массива строковым литералом - 'char a[] = "Hello";'. Литерал '"Hello"' является массивом , но не деградирует до указателя в данном контексте.

Таким образом, применение оператора '&' к объект типа "массив" дает вам указатель "на весь массив" (с точки зрения типа указателя). Т.е. для 'int a[20]' выражение '&a' имеет тип 'int (*)[20]'. В памяти адрес "всего массива" - это адрес того самого непрерывного блока, о котором я говорил выше. Т.е. численно этот адрес совпадает с адресом нулевого элемента массива. Именно поэтому выражения '&a', '&a[0]' и просто 'a' численно дают один и тот же адрес.

Именно поэтому, к примеру, в функцию 'memcpy' для двух массивов (т.е. именно объектов типа "массив", а не "указатель") можно вызывать и как 'memcpy(dst, src, sizeof src)', и как 'memcpy(&dst, &src, sizeof src) и как 'memcpy(&dst[0], &src[0], sizeof src). Результат будет один и тот же во всех случаях.

Именно поэтому правильно работает 'scanf' при использовании 'mass' или '&mass', ибо оба выражения дают одно и то же физическое численное значение. (Второй вариант формально не верен, т.к. формат '%s' требует указателя именно типа 'char *', а не 'char (*)[N]', но на практике это не важно.)

Кстати, Денис Ритчи в своей статье об истории происхождения С (http://cm.bell-labs.com/who/dmr/chist.html) пишет, что изначально он собирался реализовать массивы в С точно так же, как они были реализованы в языках B и BCPL. В B и BCPL массивы были реализованы именно как самостоятельные указатели, указывающие на отдельные посторонние блоки памяти. Но Ритчи также хотел ввести в язык такой новый тип, как структуры. И тут сразу возникла проблема: если массив будет реализован через указатель, то структуру, содержащую в себе массивы, невозможно будет тривиально копировать. Т.е. обычный 'memcpy' будет тупо копировать указатели из одной структуры в другую. А это, разумеется, неприемлемо. По этой причине он отказался от идеи реализовывать массивы через физические указатели. Массивы в С стали просто блоками памяти. Никаких указателей. Но для сохранения похожей на B и BCPL семантики в язык С было введено неявное преобразование из типа "массив" в тип "указатель". Большинство операций с массивами работает именно через это преобразование, т.е. через временный указатель. Но физически этого указателя не существует.
zss
Модератор
Эксперт С++
6242 / 5845 / 1891
Регистрация: 18.12.2011
Сообщений: 14,975
Завершенные тесты: 1
06.01.2015, 13:26  [ТС]     Распространенные ошибки #22
Приведение типа в стиле С++
Язык С++ позволяет использовать приведение типа как в виде
(int)x, так и int(x)
Для С допустим только первый (int)x вариант!
HighPredator
5454 / 1820 / 335
Регистрация: 10.12.2010
Сообщений: 5,381
Записей в блоге: 3
03.03.2015, 10:33     Распространенные ошибки #23
Вставлю все-же свои 5 копеек.
TheCalligrapher, вы в своем изложении не учли одно важное обстоятельство, которое подвело вас, а может и читателей, к опасному выводу. А именно:
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Именно поэтому правильно работает 'scanf' при использовании 'mass' или '&mass', ибо оба выражения дают одно и то же физическое численное значение. (Второй вариант формально не верен, т.к. формат '%s' требует указателя именно типа 'char *', а не 'char (*)[N]', но на практике это не важно.)
Здесь неопределенное поведение (см. раздел стандарта посвященный форматным функциям -- если ожидаемый формат не совпадает с фактически посланным, то UB автоматом). В принципе на этом можно поставить точку, но лучше помыслить шире, чтобы дальше не напарываться.
Почему же оба кейса отрабатывают верно? Тут, в моем понимании, дело в следующем. Оба примера внутри работают с объектами в памяти через char* (в scanf посредством кастинга va_arg, и в memcpy работы с char буферами). И работает сие счастье только потому, что char* именно для этих целей (работы с памятью) был сделан универсальным type-aliasом. В контексте сказанного, ошибочно полагать, что
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Именно поэтому, к примеру, в функцию 'memcpy' для двух массивов (т.е. именно объектов типа "массив", а не "указатель") можно вызывать и как 'memcpy(dst, src, sizeof src)', и как 'memcpy(&dst, &src, sizeof src) и как 'memcpy(&dst[0], &src[0], sizeof src). Результат будет один и тот же во всех случаях.
Синтетический пример, который работает вопреки логике TheCalligrapher (выдрано из сети):
C
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <stdio.h>
#include <stdint.h>
 
int enqueue_into_buf(char *buf, size_t buf_pos, const uint32_t param_len, const void *param) {
 
    /* If param_len is NULL, then change opcode */
    if(param_len == 0) {
        memcpy( buf, param, 1 );
        if(buf_pos == 0)
            buf_pos++;
        return buf_pos;
    }
 
    memcpy( buf + buf_pos, &param_len, sizeof(param_len) );
    buf_pos += sizeof(param_len);
 
    memcpy( buf + buf_pos, param, param_len );
    buf_pos += param_len;
 
    return buf_pos;
}
 
int main(int argc, char *argv[])
{
    char opcode;
    uint32_t param_len, num_params, buf_size, buf_pos = 0, received_num;
    char *buf, *temp;
 
    char *input_string = "file01"; /* example string to use as parameter */
    size_t input_size = 4, received_size; /* example variable to also use as a parameter */
 
    opcode = '1'; /* opcode equals function 1 */
    num_params = 2; /* number of parameters */
 
    /* setting the size of the buffer that will be sent over the network */
    buf_size = sizeof(opcode) + ( num_params * sizeof(uint32_t) ) + (strlen(input_string) * sizeof(char)) + sizeof(input_size);
    buf = malloc( buf_size );
 
    /* Notice the ampersand! */
    buf_pos = enqueue_into_buf(buf, buf_pos, 0, &opcode);
    buf_pos = enqueue_into_buf(buf, buf_pos, strlen(input_string), &input_string);
    buf_pos = enqueue_into_buf(buf, buf_pos, sizeof(input_size), &input_size);
 
    /* At this point, since we inserted everything into the buffer, 
    the buffer size and current buffer position should be equal */ 
    if(buf_pos == buf_size)
        printf("Calculated buffer size correctly and inserted everything correctly as well. Buffer size = %d\n", buf_size);
 
    /** Extract from buffer **/
    buf_pos = 0;
 
    printf("Opcode: %c\n", buf[buf_pos]);
    buf_pos++;
 
    memcpy(&received_num, buf + buf_pos, sizeof(uint32_t));
    printf("Size of parameter 1: %d\n", received_num);
    buf_pos += sizeof(uint32_t);
 
    temp = malloc(received_num + 1);
    memcpy(temp, buf + buf_pos, received_num);
    temp[received_num] = '\0';
    printf("Parameter 1: %s\n", temp);
    buf_pos += received_num;
 
    memcpy(&received_num, buf + buf_pos, sizeof(uint32_t));
    printf("Size of parameter 2: %d\n", received_num);
    buf_pos += sizeof(uint32_t);
 
    memcpy(&received_size, buf + buf_pos, sizeof(size_t));
    printf("Parameter 2: %d\n", received_size);
    buf_pos += sizeof(size_t);
 
    return 0;
}
В качестве дз изучать строку:
C
1
buf_pos = enqueue_into_buf(buf, buf_pos, strlen(input_string), &input_string);
Как-то так...
Evg
Эксперт CАвтор FAQ
17386 / 5624 / 351
Регистрация: 30.03.2009
Сообщений: 15,402
Записей в блоге: 26
03.03.2015, 14:04     Распространенные ошибки #24
Цитата Сообщение от HighPredator Посмотреть сообщение
Синтетический пример
Пример вообще не об этом. TheCalligrapher объяснял, почему при передаче в scanf не будет принципиальной разницы между "char*" и "char (*)[]", а в твоём примере на выделенной тобой строке используется "char**", что вообще из другой оперы (а в сам пример вникать ломает)
HighPredator
5454 / 1820 / 335
Регистрация: 10.12.2010
Сообщений: 5,381
Записей в блоге: 3
03.03.2015, 14:44     Распространенные ошибки #25

Не по теме:

Да ради бога.



Добавлено через 17 минут

Не по теме:

@Модераторам просьба: обрежьте пост Распространенные ошибки после предложения

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

Evg
03.03.2015, 15:17
  #26

Не по теме:

До фразы "на этом можно поставить точку" кроме мысли о формальном UB (да и то я на 100% не уверен, что приведение указателя на массив к указателю на элемент массива приводит к UB) всё остальное тоже можно удалять. Имеется в виду про "не учли одно важное обстоятельство, которое подвело вас, а может и читателей, к опасному выводу", потому что в том описании всё разжёвано предельно ясно, а потому как-то тут не понятно, какие опасные выводы кто-то мог бы вывести

easybudda
Эксперт С++
9439 / 5462 / 925
Регистрация: 25.07.2009
Сообщений: 10,481
03.03.2015, 15:23     Распространенные ошибки #27
Цитата Сообщение от HighPredator Посмотреть сообщение
Модераторам просьба: обрежьте пост
2.3 Сообщения и темы, а также другой контент, размещаемый на форуме, по просьбам пользователей не удаляется и не закрывается.
Если принципиально - обращайтесь к администрации.
HighPredator
5454 / 1820 / 335
Регистрация: 10.12.2010
Сообщений: 5,381
Записей в блоге: 3
04.03.2015, 10:25     Распространенные ошибки #28
Поскольку я упертый как 100 баранов, то все-же попытаюсь опровергнуть мысль, а именно выделенные тезисы:
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Именно поэтому, к примеру, в функцию 'memcpy' для двух массивов (т.е. именно объектов типа "массив", а не "указатель") можно вызывать и как 'memcpy(dst, src, sizeof src)', и как 'memcpy(&dst, &src, sizeof src) и как 'memcpy(&dst[0], &src[0], sizeof src). Результат будет один и тот же во всех случаях.
Именно поэтому правильно работает 'scanf' при использовании 'mass' или '&mass', ибо оба выражения дают одно и то же физическое численное значение. (Второй вариант формально не верен, т.к. формат '%s' требует указателя именно типа 'char *', а не 'char (*)[N]', но на практике это не важно.)
Итак, еще раз. Для случая с printf.
Первое. C89 п.7.19.6.1/8 для формата %s:
If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type.
Второе. C89 п.7.19.6.1/9
If any argument is
not the correct type for the corresponding conversion specification, the behavior is undefined.
Смотрим, какому типу соответствует &str, где char str[32]. Нам известно, что амперсанд подавляет array-decay во всех случаях, в т.ч. и при передаче в функцию. Значит, тип указателя при передаче в printf будет (char*)[32] (если кто не верит, легко можно убедиться при дебаге). Поскольку на входе в printf с заданным спецификатором ожидается char* а не (char*)[32], по вышеуказанным пунктам стандарта имеем неопределенное поведение. End of story.

Теперь к с случаю с memcpy.
Рассмотрим пример:
C
1
2
3
4
5
6
7
8
9
10
  char source[N];
  char dest[N];
 
  strcpy(source, "This is no test");
 
  memcpy(dest, source, N);
  printf("'%s'\n", dest);
 
  memcpy(&dest, &source, N);
  printf("'%s'\n", dest);
Вроде все нормально, все записалось. Теперь давайте попробуем сделать следующее: скопировать N-1 элемент начиная с 1, а не с 0. Ок, смотрим:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define N 16
 
int main(void)
{
  char source[N];
  char dest[N];
 
  strcpy(source, "This is no test");
 
  memcpy(dest, source, N);
  printf("'%s'\n", dest);
 
  memcpy(&dest, &source, N);
  printf("'%s'\n", dest);
 
  memcpy(&dest, &source+1, N-1);
  printf("'%s'\n", dest);
 
  return 0;
}
И косяк (см. скрин)... Давайте разбираться почему. Как уже было сказано для случая с printf, с помощью амперсанда мы по факту передали указатель типа (char*)[16]. То есть указатель на массив. А вот теперь важный вывод: инкремент такого указателя на 1 будет по факту инкрементом на длину массива, а не на один элемент как хотели. В этом легко убедиться:
C
1
printf("source = %p, (&source+1) = %p\n", &source, &source+1);
Код
source = 003BF9A0, (&source+1) = 003BF9B0
Как видно разница ровно 16. Ну не надо так делать в принципе. И на практике это ой-как важно.

Надеюсь теперь мысль более доступно изложена.
Миниатюры
Распространенные ошибки  
Evg
Эксперт CАвтор FAQ
17386 / 5624 / 351
Регистрация: 30.03.2009
Сообщений: 15,402
Записей в блоге: 26
04.03.2015, 12:30     Распространенные ошибки #29
Цитата Сообщение от HighPredator Посмотреть сообщение
If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type
В стандарте надо искать про то, что указатель указатель на массив по значению эквивалентен указателю на первый элемент массива или что-то типа того. Мне неохота сейчас ковыряться в стандарте, но в своё время видел в стандарте требование, что указатель на структуру должен быть по значению эквивалентен указателю на первое поле структуры. Наверняка что-то подобное есть и про массив

Цитата Сообщение от HighPredator Посмотреть сообщение
If any argument is
not the correct type for the corresponding conversion specification, the behavior is undefined.
Цитата Сообщение от HighPredator Посмотреть сообщение
Поскольку на входе в printf с заданным спецификатором ожидается char* а не (char*)[32], по вышеуказанным пунктам стандарта имеем неопределенное поведение
Если ожидается char*, а подан const char* то это тоже неопределённое поведение?
HighPredator
5454 / 1820 / 335
Регистрация: 10.12.2010
Сообщений: 5,381
Записей в блоге: 3
04.03.2015, 14:42     Распространенные ошибки #30
Цитата Сообщение от Evg Посмотреть сообщение
Если ожидается char*, а подан const char* то это тоже неопределённое поведение?
Я похоже тут неточно выразился. В контексте конкретно printf-а, скорее всего ожидается const char*.

Добавлено через 21 минуту

Не по теме:

Цитата Сообщение от HighPredator Посмотреть сообщение
Я похоже тут неточно выразился. В контексте конкретно printf-а, скорее всего ожидается const char*.
Уже не могу выпилить В общем как с мыслями соберусь, вменяемый ответ постараюсь дать.

Evg
Эксперт CАвтор FAQ
17386 / 5624 / 351
Регистрация: 30.03.2009
Сообщений: 15,402
Записей в блоге: 26
04.03.2015, 14:42     Распространенные ошибки #31
Цитата Сообщение от HighPredator Посмотреть сообщение
В контексте конкретно printf-а, скорее всего ожидается const char*
Хорошо, тогда есть подать char* или volatile char*, то будет неопределённое поведение?

В твоей цитате сказано "the argument shall be a pointer to the initial element of an array of character type". Под такую формулировку попадают и char*, и volatile char*, и char(*)[], а так же всякие int*, которые указывают на первый элемент массива char'ов
HighPredator
5454 / 1820 / 335
Регистрация: 10.12.2010
Сообщений: 5,381
Записей в блоге: 3
04.03.2015, 16:30     Распространенные ошибки #32
Цитата Сообщение от Evg Посмотреть сообщение
есть подать char*
Все будет ок, т.к. const-correctness позволяет T* -> const T*, но не наоборот.
Цитата Сообщение от Evg Посмотреть сообщение
volatile char*
Про volatile ничего не могу сказать. Думаю, лично мое видение данного вас не сильно интересует.

В сорцах glibc (2.21 -- /libc/stdio-common/printf-parse.h) нашел список форматов для парсера этой группы функций:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* The various kinds off arguments that can be passed to printf.  */
union printf_arg
  {
    wchar_t pa_wchar;
    int pa_int;
    long int pa_long_int;
    long long int pa_long_long_int;
    unsigned int pa_u_int;
    unsigned long int pa_u_long_int;
    unsigned long long int pa_u_long_long_int;
    double pa_double;
    long double pa_long_double;
    const char *pa_string;
    const wchar_t *pa_wstring;
    void *pa_pointer;
    void *pa_user;
  };
Evg
Эксперт CАвтор FAQ
17386 / 5624 / 351
Регистрация: 30.03.2009
Сообщений: 15,402
Записей в блоге: 26
04.03.2015, 16:40     Распространенные ошибки #33
Цитата Сообщение от HighPredator Посмотреть сообщение
се будет ок, т.к. const-correctness позволяет T* -> const T*, но не наоборот
Т.е. здесь ты обратился к каким-то пунктам, которые описаны вне описания printf'а. Вот и я предлагал точно так же обратиться к прочим пунктам, описанным вне printf'а, в которых должно быть написано про то, что адрес на массив и адрес на первый элемент массива имеют одно и то же значение
HighPredator
5454 / 1820 / 335
Регистрация: 10.12.2010
Сообщений: 5,381
Записей в блоге: 3
04.03.2015, 16:55     Распространенные ошибки #34
Evg, не совсем понял ход вашей мысли. Пусть адреса совпадают. Что это нам дает в контексте обсуждения?
Evg
Эксперт CАвтор FAQ
17386 / 5624 / 351
Регистрация: 30.03.2009
Сообщений: 15,402
Записей в блоге: 26
04.03.2015, 17:54     Распространенные ошибки #35
Цитата Сообщение от HighPredator Посмотреть сообщение
Пусть адреса совпадают. Что это нам дает в контексте обсуждения?
Откуда вытекает, что это UB? Когда вместо "const char*" подсовывается "char*", то у тебя нашёлся пункт стандарта, согласно которому такое поведение является корректным. Я предполагаю, что есть другой пункт стандарта, согласно которому подсовывание "char(*)[]" вместо "char*" является допустимым
HighPredator
5454 / 1820 / 335
Регистрация: 10.12.2010
Сообщений: 5,381
Записей в блоге: 3
04.03.2015, 19:04     Распространенные ошибки #36
Evg, теперь я вашу мысль понял. Если сможете найти такой, то я, да и огромная часть SO-коммьюнити будет в неоплатном долгу.
Evg
Эксперт CАвтор FAQ
17386 / 5624 / 351
Регистрация: 30.03.2009
Сообщений: 15,402
Записей в блоге: 26
04.03.2015, 21:35     Распространенные ошибки #37
Цитата Сообщение от HighPredator Посмотреть сообщение
Если сможете найти такой
Я думал ты найдёшь Мне лениво, потому что не совсем понятно, что конкретно надо искать. Всё-таки я не читаю стандарт перед сном и кроме как поиском там фиг что могу найти
HighPredator
5454 / 1820 / 335
Регистрация: 10.12.2010
Сообщений: 5,381
Записей в блоге: 3
05.03.2015, 08:23     Распространенные ошибки #38
Evg, поищу конечно, но 50/50, т.к. если не найду, это не будет значить, что его там нет. Это будет лишь значить, что я не нашел и только. В таком контексте я вроде уже сразу на проигравшей стороне
Цитата Сообщение от Evg Посмотреть сообщение
Я предполагаю, что есть другой пункт стандарта, согласно которому подсовывание "char(*)[]" вместо "char*" является допустимым
Чисто из любопытства: почему вам кажется, что такое может быть? Это же напрочь разные типы указателей.
Evg
Эксперт CАвтор FAQ
17386 / 5624 / 351
Регистрация: 30.03.2009
Сообщений: 15,402
Записей в блоге: 26
05.03.2015, 12:03     Распространенные ошибки #39
Цитата Сообщение от HighPredator Посмотреть сообщение
В таком контексте я вроде уже сразу на проигравшей стороне
Я не ставлю себе целью выиграть спор. Просто интересно, как обстоит дело с формальной точки зрения на самом деле. Постфактум-то и так понятно, что оно будет работать

Цитата Сообщение от HighPredator Посмотреть сообщение
Чисто из любопытства: почему вам кажется, что такое может быть?
Я уже выше писал, что в своё время что-то приходилось читать в стандарте на предмет того, что указатель на структуру должен преобразовываться к указателю на первое поле и обратно (что их адреса должны совпадать или что-то типа того). Т.е. там, где ожидается, грубо говоря, указатель на int, допустимо подсовывать указатель на всю структуру с соответствующим преобразованием, что гарантирует корректность работы кода. Правда в данном случае нету явного преобразования, так что начинаю подозревать, что даже если в стандарте найдётся что-то подобное для массивов, то это вовсе не будет означать формальную корректность подачи &array в printf/scanf
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.03.2015, 12:32     Распространенные ошибки
Еще ссылки по теме:

C (СИ) Найти ошибки
Непонятные ошибки C (СИ)
C (СИ) Смешные ошибки
C (СИ) Поиск ошибки

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
HighPredator
5454 / 1820 / 335
Регистрация: 10.12.2010
Сообщений: 5,381
Записей в блоге: 3
05.03.2015, 12:32     Распространенные ошибки #40
Цитата Сообщение от Evg Посмотреть сообщение
Правда в данном случае нету явного преобразования, так что начинаю подозревать, что даже если в стандарте найдётся что-то подобное для массивов, то это вовсе не будет означать формальную корректность подачи &array в printf/scanf
Собственно я того же мнения. Поэтому так уперся
Yandex
Объявления
05.03.2015, 12:32     Распространенные ошибки
Ответ Создать тему
Опции темы

Текущее время: 15:02. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru