Размер оператора и попытка распечатать массив

Рассмотрим эту программу на C

#include <stdio.h>
#define TOTAL_ELEMENTS (sizeof(arr))/sizeof(arr[0])
int arr[] = {23, 34, 12, 17, 204, 99, 16};
int main() {
 int d;
 printf("%zu\n", TOTAL_ELEMENTS);
 for (d = -1; d <= (TOTAL_ELEMENTS - 2); d++) {
  printf("%d ", arr[d + 1]);
 }
 return 0;
}

компиляторы выдают результат как 7 согласно моим пробным прогонам и рассуждениям вывод должен быть
7
23 34 12 17 204 99 16

Теперь, чтобы увидеть, что происходит не так, я применил некоторые вариации. рассмотрите этот код

#include <stdio.h>
#define TOTAL_ELEMENTS (sizeof(arr))/sizeof(arr[0])
int arr[] = {23, 34, 12, 17, 204, 99, 16};
int main() {
 int d;
 printf("%zu\n", TOTAL_ELEMENTS);
 for (d = -1; d <=(int) ((TOTAL_ELEMENTS) - 2); d++) {
  printf("%d ", arr[d + 1]);
 }
 return 0;
}

Обратите внимание: единственное изменение, которое я сделал, — это введение приведения типов с помощью int, и теперь оно дает ожидаемые результаты.

Теперь, насколько я знаю, когда мы сравниваем в программе C, она может правильно выполнять преобразование в больший тип данных, поэтому предположим, что TOTAL_ELEMENT даже имеет больший тип, например long, тогда d должен быть преобразован в long, и программа должна работать нормально, но этого не происходит. Какие моменты мне здесь не хватает?

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

Allan Wind 03.08.2024 07:17

@AllanWind большое спасибо, это проясняет мои сомнения: здесь мы сравниваем беззнаковые числа со знаком, что означает, что знак будет преобразован в огромное число в соответствии с беззнаком, а условие будет ложным, верно?

Bhargav Patil 03.08.2024 07:34

У @chux-ReinstateMonica op было несколько комментариев после того, как я написал ответ, поэтому я хотел перейти к обсуждению ответа. Не беспокойся. Я уже удалил остальные свои комментарии, которые больше не были полезны, так что потерять еще один не проблема. Я тоже удалю этот комментарий, если вы проголосуете за него. Попробуй :-).

Allan Wind 03.08.2024 08:11
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
1
3
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В сравнении d <= (TOTAL_ELEMENTS - 2) ранг d ниже ранга (TOTAL_ELEMENTS - 2), поскольку int имеет меньшую точность, чем size_t на вашей платформе согласно 6.3.1.1:

Ранг целочисленного типа со знаком должен быть выше ранга любого целочисленного типа со знаком меньшей точности.

Компилятор преобразует int d = -1 в size_t, что дает очень большое число (SIZE_MAX из stdint.h), поэтому условие цикла является ложным и тело цикла никогда не выполняется.

  1. Предпочитайте стандартную идиому цикла for. Затем вы можете использовать size_t d, какой тип соответствует типу вашей верхней границы.
  2. Это действительно хорошая идея — использовать () правую часть макроса и каждый аргумент макроса, чтобы избежать сюрпризов.
  3. Избегайте глобальных переменных.
  4. Удалите неиспользуемые переменные.
  5. Минимизируйте объем переменных; в данном случае путем объявления d в цикле for.
  6. Используйте правильную строку формата %zu для size_t.
  7. (необязательно) Вам понадобится {} вокруг тела цикла только в том случае, если в нем больше одного оператора, а return 0 используется по умолчанию, поэтому я исключил оба.
#include <stdio.h>

#define TOTAL_ELEMENTS (sizeof (arr) / sizeof *(arr))

int main() {
    int arr[] = {23, 34, 12, 17, 204, 99, 16};
    printf("%zu\n", TOTAL_ELEMENTS);
    for (size_t d = 0; d < TOTAL_ELEMENTS; d++)
        printf("%d ", arr[d]);
}

и вы получите ожидаемый результат:

7
23 34 12 17 204 99 16 

Мы можем получить ответ, если допустим, поместим d только как int и приведем TOTAL_ELEMENTS к int, верно?

Bhargav Patil 03.08.2024 07:46

@BhargavPatil Использование int только ОК здесь в примере кода, поскольку размер массива небольшой, но в целом положительный диапазон int является подмножеством диапазона size_t, поэтому использование более широкого диапазона size_t предпочтительнее.

chux - Reinstate Monica 03.08.2024 07:59

Да, но это сложно... у вас отсутствует () в правой части макроса TOTAL_ELEMENTS (в отличие от моего), поэтому (int) TOTAL_ELEMENTS - 2 не работает, поэтому вам нужен либо (int) (TOTAL_ELEMENTS) - 2, либо (int) (TOTAL_ELEMENTS - 2). Вы используете макрос дважды, поэтому, вероятно, захотите привести его в оба места и обновить строку формата до %d. Что читабельнее: d < TOTAL_ELEMENTS или d <= (int) (TOTAL_ELEMENTS - 2). Даже если вы предпочитаете последнее, все остальные ожидают первого. sizeof(int), вероятно, меньше, чем sizeof(size_t), поэтому вы рискуете обрезать верхнюю границу.

Allan Wind 03.08.2024 08:07

@chux-ReinstateMonica, Аллан Винд, спасибо, это проясняет многие сомнения.

Bhargav Patil 03.08.2024 08:15

Другие вопросы по теме