powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / K&R Многомерные массивы
25 сообщений из 66, страница 1 из 3
K&R Многомерные массивы
    #38551348
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здравствуйте.

Сегодня изучал многомерные массивы. У меня возникла первая часть вопросов связанных с примером приведённым в главе.

Привожу код, несколько изменён в связи с индексацией предложенной в книге
Предварительные комментарии.
Функция day_of_year возвращает порядковый номер дня по номеру месяца и дня.
Функция month_day неявно возвращает день и номер месяца по году и порядковому номеру.

Код: plaintext
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.
#include "stdafx.h"

static int day_tb[2][13] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; /*0*/
int day_of_year(int y, int m, int d)
{
	int i, leap;/*2.2*/
	leap = y % 4 == 0 && y % 100 != 0 || y % 400 == 0;/*1*/
	for (i = 0; i < m-1; ++i)
	{
		d += day_tb[leap][i];// к дате прибавляется количество дней в предыдущих месяцах.
	}
	return d;
}

void month_day(int y, int yd, int* pd, int* pm)
{
	//Ниже мой код, а не K&R
	int i = 0, leap;/*2.1*/
	leap = y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
	while (yd>day_tb[leap][i])/*3.1*/
	{
		//yd = ((yd - day_tb[leap][i]) > day_tb[leap][i + 1] && i <= 10) ? yd - day_tb[leap][i] : yd;/*4*/
		yd -= day_tb[leap][i];/*5.1*/
		i++;/*5.2*/
	}
	*pd = yd;
	*pm = ++i;

	//Код K&R
	/*3.2
	for (i = 0; yd > day_tb[leap][i];i++) 
	{
		...то-же что и у меня
	}
	... */
}

int _tmain(int argc, _TCHAR* argv[])
{
	printf("%i \n", day_of_year(2013, 2, 6));
	int d, m;
	month_day(2013, 37, &d, &m);
	printf("%i %i \n",d,m );
	return 0;
}



0
K&Rмы поместили в начало массива day_tab столбец из нулей для того, чтобы номера месяцев изменялись естественным образом от 1 до 12, а не от 0 до 11. Так как за экономию памяти у нас пока не награждают, такой способ проще чем подгонка индексов.

Мне кажется если человек понял что такое указатель, то математического аппарата для индексации хватит. Это только усложняет, на мой взгляд, нужно изменить этот код в последующих изданиях, я их к сожалению не видел. Может уже изменили. Но больше меня удивила фраза про экономию памяти. Я вообще в шоке от нее. Это сейчас я могу добавить этот вектор-столбец без проблем, но раньше ?Экономия памяти была особенно актуальна. Этот столбец я убрал тут, изменил немного индексацию, и все дела .
Попутно: подскажите пожалуйста, как мне посмотреть все байты онлайн, где хранятся все элементы мои массива и тп. То есть как наблюдать за всей памятью выделенной для программы ОС онлайн. Какое-то средство при дебаге наверняка есть ? использую VS Express 2013 for Desktop

1
Для меня это выглядит как x ^ y v z, где ^ конъюнкция а v дизъюнкция. Но как это будет работать ?? ну я догадываюсь что 0^1v0 вернёт 0 например, и эта схема работает подобным образом. Верно ведь ? но почему способ определения высокосного года не year%4?

2.1-2.2
Лучше вынести в качестве глобальных переменных ? Почему да или нет ?

3.1-3.2
Ну while ведь очевидней, код второй функции я написал не смотря на то, какой код приведён и Ритчи и Кернигана, но когда увидел for, был удивлён, ведь это жутко нелогично делать тут for, очевидно это while ! Хотя for и while это одно и то-же, это я понимаю. Или в этом своя фишка которую я не понимаю ? Как вы бы поступили в таком случае ?

4
Как организовать блок 3.1/3.2 подобным образом ? Ну очень нравятся такие конструкции, жутко красивые :p

5.1-5.2
Мне уже хочется написать yd -= day_tb[leap][i++] , но правильно ли так ? На 100 ли процентов компилятор проведёт инкремент вторым действием ?? на всех машинах ? во всех ос ? Возникнет ли в данном случае неудачный пример побочного эффекта по K&R ?
Да и вообще такой код мне кажется красивым, как while(*a==*b) в коде где идёт лексографическое сравнение строк(именно там, а не где его приводят K&R), но для меня очевидно, что начинающий программист который в дальнейшем будет читать мой код, может это не понять и запутаться. Ответьте на этот вопрос, и скажите как вы сами предпочитаете делать ?

Пример изначально показался скучным( в который раз), но в итоге понравился ( в который раз такое)
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551354
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
0 - хватит. Но это же учебник. Для простоты изложения и чтобы лишний раз напомнить ученику что массивы начинаются с нуля... Ради этого можно и потерпеть разок избыточность. Пусть ученик сам увидит что значит начинать массивы с единицы.

1 - потому что кое-кто не знает как определяется високосный год. Угадай кто этот "кое-кто"?

2 - А зачем эти переменные в виде глобальных? Не, ну можно конечно если так хочется. Вынеси и попытайся теперь запустить любую из этих функций в цикле:
Код: plaintext
1.
2.
 for(i=0; i<10; i++) 
   printf(%d\n", day_of_year(2014, 2, i);



3 - без разницы. for в таких случаях удобен тем, что инициализация и приращение переменной цикла идет рядышком с проверкой условия цикла. while - в какой-то степени чуть более логичен если принять что в for обязательно надо проверять саму переменную а не что-то основанное на ней.
А что выбирать - личные предпочтения.

4 - не понял вопроса. Какой блок ты хочешь так организовать? А вообще строка 4 ужастна. Длинная и закрученная. Чтобы ее понять, ее надо читать. Беглому взгляду не доступна.

5. Читай учебник (тот самый) внимательнее. Постфиксные инкременты описаны в книге.
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551361
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K&RМассив day_tab является первым двухмерным массивом с которым мы имеем дело. По определению в С двухмерный массив по существу является одномерным массивом, каждый элемент которого является массивом. Поэтому индексы записываются как

Код: plaintext
1.
2.
3.
day_tab[i][j]
а не
day_tab[i,j]


По мне так раз по существу n-мерные массивы одномерны, то запись вторая была бы логична. Некоторый аналог сложной индексации внутри массива.
Вопрос: Фраза выделенная красным подразумевает что элементы в памяти расположены друг за другом ? Вот мой тест:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
	for (int i = 0; i <= 1; i++)
	{
		for (int j = 0; j <= 11; j++)
		{
			printf("%i %p \n", day_tb[i][j], &day_tb[i][j]);
		}
		printf("\n");
	}


а что делает мой 060 ? Скрин прикрепил, но не понял отобразится он туту или нет сразу
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551380
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пробую вывести значения двухмерного массива через указатели как будто бы работаю с линейным массивом

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
for (int i = 0; i < 20;i++)
	{	
		if (*(day_tb + i) == '\0')
		{
			break;
		}
		else
		{
			printf("%i \n", *(day_tb + i));
		}
	}



Этот код идёт по подмассивам массива ? и причём он никогда не остановится, потому не while
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551385
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Окей, я понял что не всё так просто как говорят Керниган и Ритчи, и я сделал так
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
	int i = 0;
	int* pday_tb = &day_tb[0][0];
	while (*(pday_tb+i)!='\0')
	{
		printf("%i \n", *(pday_tb+i));
		++i;
	}



Но, почему у меня на экране только один массив ? где весь ?
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551389
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
То есть он нашёл нуль внутреннего подмассива и остановился, вероятно всего так, и на 060 этот нуль как раз и находится, теперь нужно понять почему так, почему для записи с именем массива и в цикле while (*(pday_tb+i)!='\0')
компилятор не понимает где конец именно этого двухмерного массива
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551403
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White Owl, спасибо.

Я прочитал, и в нём расхождение. Потому в мою голову и закрались сомнения. Сначала должно быть использовано значение и потом будет инкремент. Но, на страницах 56-57, где как раз рассказывается про побочный эффект, написано:
K&R...примером типичной неудачной ситуации является оператор
Код: plaintext
1.
A[i]=i++;


Возникает вопрос, старое или новое значение i служит в качестве индекса. Компилятор может поступать разными способами, и в зависимости от своей интерпретации выдавать разные результаты...
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551414
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercuryТо есть он нашёл нуль внутреннего подмассива и остановился, вероятно всего так
это так потому что ты так написал
'\0' значит 1 байт с кодом символа 0. т.е. просто ноль.

SashaMercury компилятор не понимает где конец именно этого двухмерного массива
Компилятор не должен ничего понимать. Ты объявил массив из 2 строк по 13 элементов, а проинициализировал 12 , вот компилятор туда и вставил 0 вместо недостающих. Т.е. реально получилось так:
Код: plaintext
1.
2.
static int day_tb[2][13] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}, 
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0} };



PS у массива нет "конца" как ты ожидаешь, ты должен сам следить в коде чтобы не выйти за пределы массива.
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551425
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А вот я дошёл до самой главной фразы в этой главе, видимо они больше всего относится к описанию 2хмерных массивов:
K&RЕсли двумерный массив передается функции, то описание соответствующего аргумента функции должно содержать количество столбцов; количество строк несущественно, поскольку, как и прежде, фактически передается указатель.


те я могу написать на выбор:
Код: plaintext
1.
2.
3.
4.
5.
6.
void smth_func1(int array[2][13])
{}
void smth_func2(int array[][13])
{}
void smth_func3(int(*array)[13])
{}



Судя по тому что я привёл выше из K&R, я понял что в функцию я передаю не двухмерный массив, а блок на 13 элементов(во втором и третьем случае).
Мне хочется передавать только указатель на array, и всё, а дальше вертеть им как хочу. Это возможно ? Правильно ли так рассуждать ? Как делаете вы ?
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551426
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercuryВопрос: Фраза выделенная красным подразумевает что элементы в памяти расположены друг за другом ? Вот мой тест:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
	for (int i = 0; i <= 1; i++)
	{
		for (int j = 0; j <= 11; j++)
		{
			printf("%i %p \n", day_tb[i][j], &day_tb[i][j]);
		}
		printf("\n");
	}


а что делает мой 060 ? Скрин прикрепил, но не понял отобразится он туту или нет сразу
Та же ошибка. 13 элементов а не 12.
Пиши < вместо <=, тогда код понятнее будет
Код: plaintext
1.
2.
3.
for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 13; j++)
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551429
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T, спасибо C:

Заработало, это я исправлял индексацию, убрал лишние нули, и забыл уменьшить размер массива (
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551432
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima_TТа же ошибка. 13 элементов а не 12.
Пиши < вместо <=, тогда код понятнее будет


дада, уже понял ( невнимательно изменил пример из K&R ((
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551436
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima_TТа же ошибка. 13 элементов а не 12.
Пиши < вместо <=, тогда код понятнее будет



Спасибо за совет C:
Индексация мне ясна , что <= что <, все ошибки пошли от размерности массива (
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551449
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercury...
Мне хочется передавать только указатель на array, и всё, а дальше вертеть им как хочу. Это возможно ? Правильно ли так рассуждать ? Как делаете вы ?
Учти что указатель дает только адрес в памяти где массив начинается, а где его конец будет неизвестно.

Массив это просто непрерывный кусок памяти. Адресация в памяти линейна, поэтому любой N-мерный массив хранится как одномерный. Например если ты делаешь массив int[2][13] то выделяется 4*2*13 байт.
Обращение к элементу массива это расчет адреса его хранения относительно начала. Например *a[1][6] это *a[0][0] + 1*13 + 6

Многомерными массивами не пользуюсь (не требуется), а с одномерными обычно практика такая: передается указатель на начало и размер массива (количество элементов, а не байт).
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551451
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Запусти
Код: plaintext
1.
2.
	printf("day_tb[1][3] = %d %p\n", day_tb[1][3], &day_tb[1][3]);
	printf("day_tb[0][16] = %d %p\n", day_tb[0][16], &day_tb[0][16]);


это для массива day_tb[2][13]
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551458
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima_T,
Вывел 16 и 17 элементы массива. Это здорово !)Сплошная индексация, или..мм. какое бы слово подобрать. Сквозная индексация, так лучше ? Или, сквозная относительная индексация. Мне нравится это свойство массивов на С
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38551480
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По сути получение элемента a[i][j] массива a[N][M] сводится к расчету указателя на этот элемент pa = &a[0][0] + i * M + j
Проверок на выход за границы массива не делается.
в твоем примере 1*13 + 3 = 0*13 + 16

Главный минус использования в коде записи типа a[i][j] в потере производительности, т.к. умножение достаточно тяжелая операция для процессора. Быстрее работает если использовать указатели и сложение/вычитание для их изменения.
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38552722
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima_T, спасибо С:
Я понял, в целом.

Про високосные года, нашёл информацию, может быть кому-нибудь пригодится
http://ru.wikipedia.org/
По-прежнему високосным оставался год, номер которого кратен четырём, но исключение делалось для тех, которые были кратны 100. Отныне такие годы были високосными только тогда, когда делились ещё и на 400.

Иными словами, год является високосным в двух случаях: либо он кратен 4, но при этом не кратен 100, либо кратен 400. Год не является високосным, если он не кратен 4, либо он кратен 100, но при этом не кратен 400.
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38552756
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Экспериментировал сегодня. Исходя из того какая логика накладывается на n-мерные массивы f e :day_tb[1][3], day_tb[0][16], ожидал аналогичное на одномерные, но не получил то что хотел.
Два вопроса:
1.
Код: plaintext
1.
2.
	int test[2][13] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 } };
	printf("%i %i", test[16], test[1][3]);


На что указывает test[16]? У меня отобразилось число порядка миллиона, вместо ожидаемой 3.

2. Почему нельзя обратиться к одномерному массиву таким образом : ar[1][2] ? Исходя из общей логики массивов на С это ожидалось
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38552767
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercury1.
Код: plaintext
1.
2.
	int test[2][13] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 } };
	printf("%i %i", test[16], test[1][3]);


На что указывает test[16]? У меня отобразилось число порядка миллиона, вместо ожидаемой 3.
Если у вас test - это двухмерный массив, то test[16] - это одномерный массив, содержащий 16-ю (17-ю по порядку) строку test.
В данном случае - несуществующую строку, т.к. строк всего 2. Т.е. это выход за границы массива :)

Но миллион печатается не поэтому.
Т.к. test[16] - это одномерный массив, а ссылка на массив, при использовании в выражении, преобразуется в указатель 0-го элемента, то это выражение:
Код: plaintext
1.
printf("%i", test[16]);


эквивалентно такому
Код: plaintext
1.
printf("%i", (int)&test[16][0]);


Т.е. у вас печатается адрес приведенный к int.

SashaMercury2. Почему нельзя обратиться к одномерному массиву таким образом : ar[1][2] ? Исходя из общей логики массивов на С это ожидалось
Судя по всему у вас что-то не так с пониманием логики массивов на С :)
Во-первых так обратиться можно, если у вас одномерный массив указателей на что-то.

Во-вторых, если у вас в массиве не указатели, то конечно так обратиться нельзя. Потому что в С, к не-указателю нельзя применить операцию [].
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38552778
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercuryНа что указывает test[16]? У меня отобразилось число порядка миллиона, вместо ожидаемой 3.
Это указатель, вывелся адрес ячейки test[16][0]
т.е. test[16] это не 17й элемент массива, а указатель на начало 17-й строки
Код: plaintext
1.
2.
	printf("day_tb[1][0] = %d %p\n", day_tb[1][0], &day_tb[1][0]);
	printf("day_tb[1] = %d %p\n", *day_tb[1], day_tb[1]);



SashaMercury2. Почему нельзя обратиться к одномерному массиву таким образом : ar[1][2] ? Исходя из общей логики массивов на С это ожидалось
Неверно ты логику понял, нельзя ее трактовать в обратном направлении. Я выше писал
Dima TПо сути получение элемента a[i][j] массива a[N][M] сводится к расчету указателя на этот элемент pa = &a[0][0] + i * M + j
Если ты изначально объявил одномерный массив, то как компилятор узнает чему равно M ? например 12 элементов можно считать как [3][4], [4][3], [1][12] и т.д.

Если ты объявил массив двухмерным, то и работай с ним как с двухмерным. А то что можно указать индексы выходящие за пределы массива или перебрать указателем весь массив - это фича, которую надо знать и самому следить чтобы это случайно не происходило.
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38552780
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovsky,
вы мне что-то не договариваете, или в K&R не договаривают.
я не придавал значения операции []. это ключевая фраза. Нужно сначала понять её. Для меня a[x] это return *(a[0]+x). Но судя по вашим словам я неправильно её понимаю

И сейчас вы связали напрямую указатели и массивы. То о чём я раньше спорил

Anatoly MoskovskyВо-вторых, если у вас в массиве не указатели, то конечно так обратиться нельзя. Потому что в С, к не-указателю нельзя применить операцию [].


Или вы выделили операцию [] отдельно.

В общем я слабо понял Вас. Наверное невнимательно что-то прочитал. Сейчас попробуй найти в книге что делает операция [].
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38552789
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercuryДля меня a[x] это return *(a[0]+x).
Не, это неверно (Либо у вас опечатка)

Вот как компилятор это видит.
Допустим есть выражение
Код: plaintext
1.
a[x]


Так как "a" это ссылка на массив, то в выражении она заменяется на адрес 0-го элемента:
Код: plaintext
1.
(&a[0])[x]


С другой стороны выражение zzz[yyy] - это операция индексации []. Она заменяется на *(zzz + yyy).
Таким образом получаем:
Код: plaintext
1.
*(&a[0] + x)
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38552797
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Невнимательность (
Мне Dima_T объяснял это
...
Рейтинг: 0 / 0
K&R Многомерные массивы
    #38552798
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyТаким образом получаем:
Код: plaintext
1.
*(&a[0] + x)


Да, тут забыл еще одно преобразование, для устранения рекурсии определения [], через самого себя.

Адрес 0-го элемента &a[0] вычисляется так (element_type *)&a
(т.к. адрес массива и 0-го элемента совпадают в физическом представлении)

Т.е. итоговая формула такая:
Код: plaintext
1.
*((element_type *)&a + x)
...
Рейтинг: 0 / 0
25 сообщений из 66, страница 1 из 3
Форумы / C++ [игнор отключен] [закрыт для гостей] / K&R Многомерные массивы
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]