LINUX.ORG.RU

Указатель на указатель массива указателей

 


2

1

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

// Из K&R:
int х = 1, у = 2;
int *ip;    /* ip - указатель на int */
ip = &x;    /* теперь ip указывает на x */
y = *ip;    /* y теперь равен 1 */
*ip = 0;    /* x теперь равен 0 */
В чем смысл указателей, если судя по примеру я могу сделать и y = x с тем же успехом, а дополнительные *ip как посредники лишь уменьшат читаемость?

UPDATE: Самое главное еще забыл добавить - зачем к этой кашке еще и «**»?

UPDATE++: посылаю комментаторам доброе слово, без них вопрос затянулся бы

★★★★★

Последнее исправление: cetjs2 (всего исправлений: 3)

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

BOOST_FOREACH не нужен, есть уже нормальный for по коллекциям.

Но итератор более общая концепция и, на самом деле, крутая.

Есть еще вариант т.н. range, т.е. когда пары итераторов объединяются в одну сущность, а из любого контейнера range получается путем range(c.begin(), c.end()).

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

Не нынешние, закончил уже пару лет как. На самом деле специальность просто не коррелирует с программированием никак. Потом доучились сами по интересам. Я к слову сам научился паять, разводить платы, писать программы под avr, msp430. Вот эти навыки птом и пригодились при трудоустройстве и малый процент того, чему реально учили. Но вы правы, тенденция есть.

nand
()

Вполне возможно, что вся твоя проблема в синтаксисе C, где * используется и для объявления переменной типа «указатель», и для разыменования указателя.

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

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

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

радиофак в екатеринбурге, специальность «Радиоэлектронные системы»

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

BOOST_FOREACH не нужен, есть уже нормальный for по коллекциям.

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

Но итератор более общая концепция и, на самом деле, крутая.

Да крутая, кто спорит, но нафига _заставлять_ ей пользоваться на каждый чих(а в плюсах, особенно до 11, без этого никак)?

lazyklimm ★★★★★
()

В чем смысл указателей, если судя по примеру я могу сделать и y = x с тем же успехом, а дополнительные *ip как посредники лишь уменьшат читаемость?

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

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

Кстати, простенький и красивый пример использования поинтеров в реальной жизни (идиома спёрта мной когда-то из сырцов Plan9):

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

struct list {
        int value;
        struct list *link;
};

int
main()
{
        struct list *head, **headp, *p;
        int i;

        /* инициализируем */
        head = NULL;
        headp = &head;

        /* заполняем */
        for (i = 0; i < 10; i++) {
                *headp = malloc(sizeof(struct list));
                assert(*headp);
                (*headp)->value = i;
                headp = &(*headp)->link;
        }

        /* печатаем */
        for (p = head; p; p = p->link)
                printf("%d\n", p->value);

        /* освобождать память лень, само очистится ☺ */
        return 0;
}


PS: тут кстати и * и ** и &. ☺
beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 2)
Ответ на: комментарий от proud_anon

Так в этом основная фича синтаксиса - синтаксис объявлений совпадает с синтаксисом использования:

int a; /* int */
int b[SIZE]; /* чтобы получить int нужно применить [] */
int *p; /* чтобы получить int нужно применить * */
int f(); /* чтобы получить int нужно применить () */

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

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

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

Или, например, при надобности указать (относительно) произвольный адрес. Исходники strlen, например, посмотри.

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

Написал уже, «Радиоэлектронные системы», программирование прочитали, больше по учебе не понадобилось. Сейчас в магистратуре по направлению «Обработка изображений» доучиваюсь. Вот тут сплошное программирование.

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

Так в этом основная фича синтаксиса - синтаксис объявлений совпадает с синтаксисом использования:

Если так посмотреть, то логика есть, но ведь блин... большинство мыслит так: b — это массив int, а не «такая хрень, что при применении [] получится int».

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

Специальность такая, говорю не коррелирует с программированием. Были рассчеты усилителей, лабы по антеннам и фидерам, основы обработки радиосигналов. По этой специальности Matlab/MathCAD покрывает все потребности. Не актуально просто писать свои костыли было. Зато на работе сейчас 80% времени отнимает программирование.

nand
()

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

Мы можем поучить область памяти точки входа функции из библиотеки.

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

Мы можем изменять не изменяемое то-есть const.

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

Твой вопрос про ** мне лень жевать http://ermak.cs.nstu.ru/cprog/html/062.htm http://netlib.narod.ru/library/book0003/ch05_06.htm

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

А ну вот спасибо, напомнили. По «ЦУиМП» делал платку и писал прошивку. Но это было на 3м курсе и меня ничему не учили, всему уже на тот момент сам обучился. Это не могу назвать полноценным использованием знаний по программированию. Вот в магистратуре другое дело.

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

По этой специальности Matlab/MathCAD покрывает все потребности.

у нас сами писали, правда это было лет 10 назад :)

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

Да там проще вручную посчитать, чем писать и баги отлавливать. Чтобы элементарно MicroCAP выкинуть сколько понаписать надо? А моделирование излучения антенны базовой станции на районе? Задачи другие сейчас, корректируют как могут программу обучения. Но не покидает чувство того, что не во время я в институт пошел, в перестройку какую-то попал.

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

Вот магистратуру закончу, буду считать, что доучился. Работа больно мешает.

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

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

Приз — сегфолт?

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

Это не приз, а суперприз для буратин, что не инициализируют указатели и не проверяют их на NULL.

nand
()

можно и без указателей обойтись если вся память представима как массив и любой элемент доступен по индексу .

т.е это одно и тоже что индекс что указатель содержащий адресс.

указатели нужны для косвенности .

и для поддержки рекурсивных типов данных когда синтаксис языка их напрямую не поддерживает.

в с указатели используются для работы с последовательностями заканчивающимися терминатором ( обычно \0)

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

тем более что имена после компиляции(без дебуг инфы) вообще изчезают и остаются теже индексы в памяти т.е теже указатели но в самом коде без косвенности.

тс: представь масив индексов содержащий те или иные индексы другого массива так вот первый массив состоит из указателей на элементы второго  — по сути.

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

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

массив индексов - переписывае некоторые ячейка в таком массиве мы можем ваять развесистые структыры данных.

так вот вся память это и есть такой массив.

qulinxao ★★☆
()

** например может быть удобно при обращение ко второго элементу списка(циклического) имея его голову и ссылку на следующий элемент по нулевому смещению в узле списка.

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

необязательно и не только

индексируемая память вот и все указатели

если тебя смущают указатели почему тебя не смущает возможность обратится к a - т.е ячейка возможно не известной на помент написания программы ( в простейшем случае пусть i вводится scanf)

можно и без указателей творить тоже самое через индексируемый доступ по базе a - чем в фортране до сих пор и развлекаются .

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

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

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

код gcc как и gnu libс настолько «оптимизирован» что их не стоит брать за пример.

почти все задания в K&R есть реализация того или иного куска компилятора.

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

А оптимизацию сделать? Да один только препроцессор писать — помрешь.

Кстати, мне тут вот на stackoverflow советовали бустовский препроцессор использовать. И действительно: он значительно «веселее». А то вот сейчас сидел, ломал голову, как на препроцессоре gcc сделать контроль утечек памяти. Фигвам: единственный итератор препроцессора умеет только инкремент… А в бусте разбираться что-то не хочется. Но чую: надо. Написать один раз — и забыть, просто использовать везде.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Dron

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

на самом деле переменная указывает на область памяти. А вот указатель указывает на переменную (которая указывает на область памяти).

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

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

Ты гонишь. Переменная вообще ни на что не указывает - это просто имя/тэг/метка для обозначения области памяти, где будут храниться данные. Указатель указывает не на метку а на область память.

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

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

int main()
{


    int *point=0;

    void *point_two=0;

    int val=5555;

    int val_two=1000;

    point=&val;

    point_two=&point;


return 0;
};

А вот и самое интересное опровергающее то что ты сказал

	.file	"main.c"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movq	$0, -24(%rbp)
	movq	$0, -8(%rbp)
	movl	$5555, -28(%rbp)
	movl	$1000, -12(%rbp)
	leaq	-28(%rbp), %rax
	movq	%rax, -24(%rbp)
	leaq	-24(%rbp), %rax
	movq	%rax, -8(%rbp)
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Debian 4.7.2-5) 4.7.2"
	.section	.note.GNU-stack,"",@progbits

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

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

твой код мало что доказывает, ибо в нём нет никаких «переменных». Есть только адреса памяти. Например адрес rbp-28 называется в программе val. Таким образом, val указывает на rbp-28. Потом компилятор загружает в память по этому адресу 5555, затем этот адрес загружается в rax. Сейчас rax указывает на ту-же память, на которую указывает val (там 5555). Ну а теперь мы загружаем rax в point(rbp-24). Теперь мы можем менять point(перенаправить его на другую переменную), а можем менять данные, на которые указывает содержимое этой переменной.

	*point = 0x12345;
  4005ea:       48 8b 45 e8             mov    rax,QWORD PTR [rbp-0x18]
  4005ee:       c7 00 45 23 01 00       mov    DWORD PTR [rax],0x12345
как видишь, мы сначала получили из point(тут rbp-0x18) адрес (в программе он называется val), а в след. строке по этому адресу записываем константу 0x12345.

Т.о. переменные, это действительно всего-лишь метки, и в программе они видятся как АДРЕСА памяти. Т.е. переменные в C это указатели в коде(адреса). А вот указатели, это тоже адреса, в которых лежат другие адреса. Если указатель на int, то это адрес памяти, в которой лежит адрес этого int`а.

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

переменные, это действительно всего-лишь метки, и в программе они >видятся как АДРЕСА Т.е. переменные в C это указатели в >коде(адреса).

А никто и не спорит, так и есть.

А вот указатели, это тоже адреса, в которых лежат другие адреса. >Если указатель на int, то это адрес памяти, в которой лежит адрес >этого int`а.

А никто и не спорит, разница в содержимом и операциях над ними.

Опять же переменная это абстрактное понятие их нет, есть адреса и только адреса.О чём спор?

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

Т.е. про цифровую схемотехнику благополучно забыли

Хватит троллить. Тут речь идёт о российском образовании. Слава богу, что хоть после него человек работу ещё смог найти. И то чудо.

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

Тут речь идёт о российском образовании

Да я понял уже, что человек учился в сильно хреновом месте.

Eddy_Em ☆☆☆☆☆
()

Как ты три звезды смог нафлудить?

В функцию в сях аргументы можно передать двумя способами. По значению и по ссылке. Если передаём по значению, то внутри функции создаётся копия аргумента, которая удаляется после выхода из функции. Если передаётся указатель, то ничего не копируется, и значения аргумента можно менять внутри функции.

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

переменная это типизированный адрес по которому есть значение.

тем и отличается именнованый массив от указателя на него - и компилятор знает что a и p ( при p содержащем a) отно и тоже ибо в этом случае a константа , а p получение значение

т.е в этом и затруднение

что обычные переменые по разному обрабатываются когда л-вэлью (замена имени на адресс местоположения) и когда р-вэлью ( замена имени на содержимое по этому адрессу)

в одном из языков предшественников С было прикручивание обязательного ручного разименования(без автоматического по контексту) - оказалось для конечного пользователя не удобно .

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

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

обычно компиляторы для локальных автоматических переменых и для аргументов функции используют стек(раннее чаще говорили автоматическую / магазиную память) .

в обоих случаях передаёте ли вы int или указатель на int значение (обычно) помещается на стеке , а затем убирается вызывающей(тем с был и замечателен) стороной.

- а то, что вы процитировали это маркер безграмотных ретрансляторов — при том, что я уверен , что вы умеете сними(указателями обращатся) - но сопутстующие молитвы были вдолблены от непонимающего ситуацию препода и необходимо их было знать(эти молитвы) для получения зачёта/экзамена.

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