Не поможете ли разобраться с ("указатели и адресация")

Модератор: Модераторы разделов

promov
Сообщения: 384
Статус: Участник
ОС: Debian GNU/Linux

Не поможете ли разобраться с

Сообщение promov »

Друзья! Как известно, вещи можно постигать по-разному, в том числе и через отличие от других вещей. Я нашёл, (надеюсь, важное) отличие между указателем на переменую типа int и указателем на нулевой элемент типа int массива. Отличие функциональное. Эти два указателя по-разному себя ведут в одинаковой ситуации, а именно, когда они- аргумент функции sizeof. Действительно, в приведённой ниже пограмме функция sizeof просто возвращает размер переменной типа указатель.

Код: Выделить всё

[/b]#include <stdio.h>
 int main () {
  int * a;
  printf ("%d\n", sizeof a);
   return 0;
 }[b]


Проще говоря, здесь имя переменой типа указатель есть имя переменной типа указатель. И всё. Но! В приведённой ниже функции имя переменной типа указатель есть имя массива. И sizeof возвращает размер имено всего массива, а не указателя на его нулевой элемент.

Код: Выделить всё

[/b]#include <stdio.h>
 int main () {
  int b [3];
  printf ("%d\n", sizeof b);
  return 0;
 }[b]


А теперь вопрос: такое вот отличие в работе функции sizeof обусловлено
1) Особенностямиэти функции sizeof? Т. е. она создана так, чтобы по-разному реагировать на указатели, когда один объявлен именно как указатель, а второй объявлен... ну другим способом. через объявление массива? Или

2) Всё-таки, хоть и там и там указатель, но они конструктивно, что ли, отличаются друг отдруга? А не просто содержанием- один содержит адрес переменной, а другой адрес нулевого элемента массива. И: именно это отличие и даёт о себе знать при вызове функции sizeof. Так?

Спасибо.
Зачем хорёк пошел в ларёк, зачем барсук полез на сук...
Мораль легко уразуметь: зачем на бал пришёл медведь?
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Не поможете ли разобраться с

Сообщение drBatty »

promov писал(а): ↑
26.12.2007 20:25
Всё-таки, хоть и там и там указатель, но они конструктивно, что ли, отличаются друг отдруга?
Ну да. Пиши мне в личку, я тебе K&R пришлю. int b[3] сейчас занимает 12 байт:
XXXXYYYYZZZZ Это массив в стиле Си, двенадцатибайтовая переменная. Указатель - это совсем другое, он сегодня занимает 4 байта. Сложность в том, что массив при передаче в функцию(и присваивании) обычно автоматически преобразуется в указатель.

PS:
int b[3] на самом деле - структура:
struct
{
int __b_part0;
int __b_part1;
int __b_part2;
};
с перезагруженым оператором []. Я не виноват, что в Си так всё сложно. ;)

PPS: Кстати, размер массива можно посчитать так:
sizeof(m)/sizeof(m[0]);
если это массив, а не указатель.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
promov
Сообщения: 384
Статус: Участник
ОС: Debian GNU/Linux

Re: Не поможете ли разобраться с

Сообщение promov »

drBatty писал(а): ↑
26.12.2007 20:41
int b[3] на самом деле - структура:
struct
{
int __b_part0;
int __b_part1;
int __b_part2;
};
с перезагруженым оператором []. Я не виноват, что в Си так всё сложно. ;)
Так, сразу. Я думал, что объявление int b [3] создаёт 4 переменных:
b [0], b [1], b[2], int * b [0]= & b [0].
В Вашем посте я нечто подобное тоже узрел- для первых трёх переменных по крайней мере. А для четвёртой? Не создаётся, что ли указателя на нулевой элемент?
Зачем хорёк пошел в ларёк, зачем барсук полез на сук...
Мораль легко уразуметь: зачем на бал пришёл медведь?
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Не поможете ли разобраться с

Сообщение drBatty »

promov, создаётся одна переменная. Просто одна. b[793] это преобразования b. Указателя на нулевой эл-т тоже не создаётся.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
promov
Сообщения: 384
Статус: Участник
ОС: Debian GNU/Linux

Re: Не поможете ли разобраться с

Сообщение promov »

drBatty писал(а): ↑
26.12.2007 20:41
PPS: Кстати, размер массива можно посчитать так:
sizeof(m)/sizeof(m[0]);
если это массив, а не указатель.
Нет-нет, так подсчитывается количество элементов массива. Маленько не в тему, но всё же, вдруг кому интересно будет... В книге Cтивена Прата такой метод подсчёта элементов массива забракован- там, наверное, в технике (компиляторе) дело было. У меня ничего, получается...

drBatty писал(а): ↑
26.12.2007 20:59
promov, создаётся одна переменная. Просто одна. b[793] это преобразования b. Указателя на нулевой эл-т тоже не создаётся.
Прочёл, спасибо. Буду думать. Такого нигде не прочитаешь... Как тема-то называется в специальной литературе? Я уж в растерянности, не знаю, даже, читать- не читать это... Или дальше изучать непосредственно синтаксис и программирование...
Зачем хорёк пошел в ларёк, зачем барсук полез на сук...
Мораль легко уразуметь: зачем на бал пришёл медведь?
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Не поможете ли разобраться с

Сообщение drBatty »

promov писал(а): ↑
26.12.2007 21:03
Нет-нет, так подсчитывается количество элементов массива. Маленько не в тему, но всё же, вдруг кому интересно будет... В книге Cтивена Прата такой метод подсчёта элементов массива забракован- там, наверное, в технике (компиляторе) дело было. У меня ничего, получается...

ХЗ. Для меня размер и число эл-тов - синонимы для массива. А вот цитатку из Прата соизвольте привести, любопытно. Я ещё не встречал компиляторов и железа где это не работает.



promov писал(а): ↑
26.12.2007 21:03
Буду думать
Ага. Дизассемблер вам в помощь. И дебагер.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
promov
Сообщения: 384
Статус: Участник
ОС: Debian GNU/Linux

Re: Не поможете ли разобраться с

Сообщение promov »

drBatty писал(а): ↑
26.12.2007 21:08
А вот цитатку из Прата соизвольте привести, любопытно. Я ещё не встречал компиляторов и железа где это не работает.

Вот листинг 10.4 из этой книги

Код: Выделить всё

[/b]#include <stdio.h>

 int main (void) {
  const int days []= {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  int index;
  for (index= 0; index< sizeof days/ sizeof days [0]; index++) {
   printf ("Месяц %d имеет %d день (дней).\n", index+ 1, days [index]);
  }
  return 0;
 }[b]


Надо, чтобы программа выводила 12 значений, а у Стивена Прата она выводит 10. Вот цитата:
"Вот как! Вывелось лишь 10 значений, а использованный нами метод, позволяющий программе самостоятельно определить размер массива, не предоставил возможности распечатать массив до конца. Это подчёркивает потенциальный недостаток автоматизированного подсчёта: ошибочное количество элементов может оказаться необнаруженным"
Cтивен Прата, "Язык программирования С. Лекции и упражнения", 5- е издание. Глава 10 "Массивы и указатели". Подглава "Инициализация". Издательский дом "Вильямс", Москва- Санкт- Петербург- Киев, 2006 год.

Зачем хорёк пошел в ларёк, зачем барсук полез на сук...
Мораль легко уразуметь: зачем на бал пришёл медведь?
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Не поможете ли разобраться с

Сообщение drBatty »

promov писал(а): ↑
26.12.2007 21:21
Это подчёркивает потенциальный недостаток

бред какой-то. не понял ничего :( Должно работать и работает. Гуру, объясните, плиз!
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
deninok
Сообщения: 585
Статус: Программист С++
ОС: Debian GNU/Linux

Re: Не поможете ли разобраться с

Сообщение deninok »

Кстати, для справки автору темы: sizeof - это не функция, а оператор...
Спасибо сказали:
promov
Сообщения: 384
Статус: Участник
ОС: Debian GNU/Linux

Re: Не поможете ли разобраться с

Сообщение promov »

Читать отсюда!
Друзья! Дабы не создавать новую тему, решил здесь написать.

Код: Выделить всё

#include <stdio.h>
 int* x (int* a) {
   return y (a);
 }

 int* y (int* b) {
   return b;
 }

 int main () {
   return 0;
 }


Вот... Хоть убей, ничего не пойму. Не компилируется. Всё же правильно!
Зачем хорёк пошел в ларёк, зачем барсук полез на сук...
Мораль легко уразуметь: зачем на бал пришёл медведь?
Спасибо сказали:
Аватара пользователя
dey
Сообщения: 335
ОС: OpenSuse 11.1

Re: Не поможете ли разобраться с

Сообщение dey »

Вообще, надо хотя бы текст ошибки приводить... А так видно что не задан прототип ф-ии y(int) перед ее вызовом
В сознательных действиях должен присутствовать существенный неалгоритмический компонент.
Roger Penrose,The Emperor's New Mind
Спасибо сказали:
promov
Сообщения: 384
Статус: Участник
ОС: Debian GNU/Linux

Re: Не поможете ли разобраться с

Сообщение promov »

Да уж... Я в последнее время так не работаю, вот и отвык. Я функции распихиваю по файлам и файлы подсоединяю. В этом случае необязательно писать прототип фуекции.
Прошу прощения.
Зачем хорёк пошел в ларёк, зачем барсук полез на сук...
Мораль легко уразуметь: зачем на бал пришёл медведь?
Спасибо сказали:
Аватара пользователя
Dudraug
Сообщения: 313
ОС: Debian lenny/sid

Re: Не поможете ли разобраться с

Сообщение Dudraug »

>Я функции распихиваю по файлам и файлы подсоединяю


O_o.

Код: Выделить всё

#include "funct.c"


так что ли??? Так делать не надо. В любом другом случае прототипы писать надо (очень-очень рекомендуется).
P4-3.0, ASUS P5GD1, 1024MB OЗУ, GeForce 6600GT
Спасибо сказали:
Аватара пользователя
Dudraug
Сообщения: 313
ОС: Debian lenny/sid

Re: Не поможете ли разобраться с

Сообщение Dudraug »

пример от меня по сабжу

Код: Выделить всё

#include <stdio.h>
extern void funct(int a[]);
extern void funct1(int* a);


void funct(int a[])
{
   printf("funct - %i\n", sizeof(a));
}

void funct1(int* a)
{
   printf("funct1 - %i\n", sizeof(a));
}

int main(void)
{
    int * a;
    int b[12];

    printf("Массив main - %i\nУказатель main - %i\n", sizeof(b),sizeof(a));
    printf("Массив в функциях\n");
    funct1(b);
    funct(b);
    printf("Указатель в функциях\n");
    funct(a);
    return 0;
}


Вывод

Код: Выделить всё

Массив main - 48
Указатель main - 4
Массив в функциях
funct1 - 4
funct - 4
Указатель в функциях
funct - 4


В общем в main sizeof выдает размер массива в байтах (sizeof(int)*n) где n кол-во элементов. В других случаях он меряет уже указатели типа int* (sizeof(int*))

Это просто особенности sizeof (который и функцией не является).
P4-3.0, ASUS P5GD1, 1024MB OЗУ, GeForce 6600GT
Спасибо сказали:
promov
Сообщения: 384
Статус: Участник
ОС: Debian GNU/Linux

Re: Не поможете ли разобраться с

Сообщение promov »

Dudraug писал(а): ↑
10.04.2008 17:01
>Я функции распихиваю по файлам и файлы подсоединяю


O_o.

Код: Выделить всё

#include "funct.c"


так что ли??? Так делать не надо. В любом другом случае прототипы писать надо (очень-очень рекомендуется).
Да, именно так я и делаю. Почему Вы не советуете так делать? Да и не единственный ли это способ? Альтернатива ему- писать основную программу и функции, которые она вызывает в одном файле.

Принципиально я не против альтернативы... Но просто на вкус и цвет, знаете ли... Или здесь другие соображения?
Зачем хорёк пошел в ларёк, зачем барсук полез на сук...
Мораль легко уразуметь: зачем на бал пришёл медведь?
Спасибо сказали:
Аватара пользователя
Dudraug
Сообщения: 313
ОС: Debian lenny/sid

Re: Не поможете ли разобраться с

Сообщение Dudraug »

ну вообще стоит подключать заголовочные файлы аля

Код: Выделить всё

#include "funct.h"


с объявлениями типо

Код: Выделить всё

extern int a;


Так можно

1) компилить каждый файл независимо от других, а потом просто скомпоновать исполняемый файл из объектных
2) можно сделать так

Код: Выделить всё

gcc main.c funct.c


в любом случае подключение сорцового файла это плохая идея.
P4-3.0, ASUS P5GD1, 1024MB OЗУ, GeForce 6600GT
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Не поможете ли разобраться с

Сообщение v04bvs »

promov писал(а): ↑
07.04.2008 22:24
Читать отсюда!
Друзья! Дабы не создавать новую тему, решил здесь написать.

Код: Выделить всё

#include <stdio.h>
    int* x (int* a) {
      return y (a);
    }

    int* y (int* b) {
      return b;
    }

    int main () {
      return 0;
    }


Вот... Хоть убей, ничего не пойму. Не компилируется. Всё же правильно!


Навскидку, попробуйте поменять функции x и y местами :)

Что касается вашего вопроса.

int *a; — указатель на int.
int a[3]; — массив из 3 int-ов.
В высокоуровневых языках это вещи кардинально различные. В C это очень похожие вещи (т.к. в машине нет массивов, есть только указатели). В частности переменная-массив неявно преобразуется, при необходимости, в указатель на первый элемент.

Одно из отличий вы уже сами нашли — оператор sizeof для массива возвращает его размер. Второе отличие — переменную-указатель можно изменять, переменную-массив изменять нельзя (в этом она похожа на константный указатель).

Если говорить про С++, то там массив и указатель это совсем разные вещи, и это может быть существенным, к примеру, при выборе перегруженной функции. Если вы С++ не учите, можете пока пропустить это предложение :)

Что касается примера из Прата, то я и сам в растерянности. Это должно работать и это работает. Могу только предположить, что переводчик был идиотом и умудрился исказить смысл примера до противоположного.
Спасибо сказали:
Аватара пользователя
Dudraug
Сообщения: 313
ОС: Debian lenny/sid

Re: Не поможете ли разобраться с

Сообщение Dudraug »

Навскидку, попробуйте поменять функции x и y местами smile.gif


А не проще ли их просто объявить?

extern int* y(int*);
extern int x(int*);
P4-3.0, ASUS P5GD1, 1024MB OЗУ, GeForce 6600GT
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Не поможете ли разобраться с

Сообщение v04bvs »

Dudraug писал(а): ↑
10.04.2008 20:36
Навскидку, попробуйте поменять функции x и y местами smile.gif


А не проще ли их просто объявить?

extern int* y(int*);
extern int x(int*);


Не проще. В виме движений меньше :) А зачем extern ?
Спасибо сказали:
Аватара пользователя
Dudraug
Сообщения: 313
ОС: Debian lenny/sid

Re: Не поможете ли разобраться с

Сообщение Dudraug »

Вроде это рекомендуемый способо ОБЪЯВЛЕНИЯ.

Могу объяснить зачем это для переменных, что бы не выделять память при объявление. Могу предположить, что у функций что то тоже в этом роде.
P4-3.0, ASUS P5GD1, 1024MB OЗУ, GeForce 6600GT
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Не поможете ли разобраться с

Сообщение v04bvs »

Dudraug писал(а): ↑
10.04.2008 21:56
Вроде это рекомендуемый способо ОБЪЯВЛЕНИЯ.

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

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

Примерно так.
Спасибо сказали: