LINUX.ORG.RU

[СИ] структуры, массивы и sizeof().


0

0

[СИ] структуры, массивы и sizeof().

Язык СИ
ОС UNIX

Ниже приведена небольшая тестовая программа
на проверку sizeof().


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

//   cd /usr/home/test3test/njx
//   gcc test_sizeof.c -o test_sizeof.cgi
//   ./test_sizeof.cgi

#define N  6

//--- структура параметров хоста ---
typedef struct  {
    int   port;
    char  host[100];
} _lin;

//-------------- main --------------

int main()

{
    _lin  lin[N];  //--- массив структур ---
    int k;

    k=funk_1(lin);
    printf("k=%d\n",k);
    exit(0);
}

//-------------- funk_1 --------------

int funk_1(_lin lin[]){
    int k;
    k=funk_2(lin);
    return(k);
}

//-------------- funk_2 --------------

int funk_2(_lin lin[]){
    int k;
    k=sizeof(lin[0].host);
    //  k=sizeof(_lin.host);
    //  k=sizeof(_lin);
    return(k);
}


Во вложенные функции передается массив lin[ ],
вернее указатель на него.
Выдача этой программы
k=100
т. е. длина массива host.
Мне как раз и нужно в нижней вложенной
функции funk_2() получить длину этого массива.

Там ещё есть закомментированная строка, которую
я тоже попробовал, но с ней не компилится.

Вопрос.
Случайность ли это или правило?
Не скомпилирует ли другой «правильный» компилятор
по другому?

Кто знает прошу ответить.


>Во вложенные функции передается массив lin[ ],
вернее указатель на него.
Нет. Так было бы:
k=funk_1( &lin );
int funk_1(_lin *lin[]);

anon_666 ()

>Случайность ли это или правило?
Да, правило, это так по стандарту.


anon_666 ()

>закомментированная строка
Конечно не скомпилится, там ты пытаешься получить доступ к элементу типа, а так можно только создав его экземпляр.

anon_666 ()

Вы опасны для окружающих.

Вы не знаете Си.

Пожалуйста прочитайте Кернигана и Ритчи «Язык программирования Си.»

Не пишите больше программ пока не прочитаете. Не надо.

ntp ()
int funk_1(_lin lin[]){ 
    int k; 
    k=funk_2(lin); 
    return(k); 
} 
 
//-------------- funk_2 -------------- 
 
int funk_2(_lin lin[]){ 
    int k; 
    k=sizeof(lin[0].host); 
    //  k=sizeof(_lin.host); 
    //  k=sizeof(_lin); 
    return(k); 
} 

Автор по моему просто издевается :)

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

Спасибо за отклики,

Но не согласен.

Напомню, что программа тестовая.

anon_666 написал
k=funk_1( &lin );
но имя массива (lin) это уже и есть указатель.
далее он же
int funk_1(_lin *lin[]);
это уже получится массив указателей на тип _lin.

Подтверждение в том, что вызов, например, функции

int funk_3(_lin lin[]){
strcpy(lin[0].host, «proba»);
return(0);
}

меняет данные в исходном массиве структур, а не локально.

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

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

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

>Во вложенные функции передается массив lin[ ],

вернее указатель на него.


Указателем на lin[ ] будет int **lin_pointer = &lin[ ];

Что блджад не полнятно?!

Имя - это указатель на первый (нулевой) элемент массива


Но не указатель на массив!

anon_666 ()

Все у тебя верно, что вообще смущает? Что размер массива в 100 символов равен 100? :)

А вот начинать идентификаторы с подчеркивания - плохой тон.

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

Спасибо.

Да, это и смущает.
Не привычно, по сравнению с другими массивами,
например, типа char.

Я не знал, что так можно, и в некоторых программах
зря передавал в функции лишние аргументы, которые можно
было получить прямо там.
А это загромождает программу.

oleg_2 ()

имя массива это вообще абстракция которая в разных контекстах генерирует разные типы и значения во всех контекстах кроме «взятия адреса &(имя массива)» «инкремента ++(имя массива)» «декремента --(имя массива)» «размер выражения sizeof(имя массива)» «левый операнд операции приваивания (имя массива) =» «обращение к члену структуры, массиву .(имя массива)» из имени генерируется указатель на первый элемент массива а в шести выше перечисленных имя массива не генерирует указатель на первый элемент а генерирует тип в выражении «массив» а не «указатель»

K&R

Если тип выражения или подвыражения есть «массив из T», где T - некоторый тип, то значением этого выражения является указатель на первый элемент массива, и тип такого выражения заменяется на тип «указатель на T». Такая замена не делается, если выражение является операндом унарного оператора &, или операндом операций ++, --, sizeof, или левым операндом присваивания, или операндом оператора . (точка). Аналогично, выражение типа «функция, возвращающая Т», кроме случая, когда оно является операндом для &, преобразуется в тип «указатель на функцию, возвращающую T».

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

Во вложенные функции передается массив lin[ ],
вернее указатель на него.

Указателем на lin[ ] будет int **lin_pointer = &lin[ ];

Что блджад не полнятно?!

Имя - это указатель на первый (нулевой) элемент массива

Но не указатель на массив!

Указателем на lin[ ] будет int **lin_pointer = &lin[ ];<<

это указатель на первый элемент указателем на lin[ ] будет int (*lin_pointer)[ ] = &lin;

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

> Все у тебя верно, что вообще смущает? Что размер массива в 100 символов равен 100? :)

Меня смущает. Откуда компилятор знает длину? Или это работает только для массивов, для которых известна длина на этапе компиляции?

vladimir-vg ★★ ()
Ответ на: комментарий от osox

В пылу спора я ненароком употребил слово (lin[ ]) вместо (lin),
что бы подчеркнуть, что речь идет о массиве.
В исходной программе нет массива указателей. Там есть простой
массив элементов типа (_lin).
Вот только сами элементы это структуры.
К ним правила специфичные.
Всё работает правильно, не считая sizeof().
Вопрос в том, правильно ли использован sizeof().

Когда мы пишем
int main(int argc, char *argv[], char *envp[])
то вот они - массивы указателей.

oleg_2 ()

#include <facepalm.h>

Топикстартер так плохо знает си, что непонятно что именно ему непонятно.

1. массив в си - последовательность байт в памяти.

2. ряд действий с массивом целиком запрещены специально в давние времена. Сейчас бы можно было бы и разрешить - но обратная совместимость нужна. Во-первых, запрещено присваивание массивов, а во-вторых, передача в функции по значению. Но передавать как-то надо, поэтому ввели третье особое правило: при каждом удобном случае имя массива расценивается как указатель. Но имя массива не является указателем. Вот пример (он на си++, но тут разницы нет):

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

#include<iostream>
#include<iomanip>
#include<string>

template <class T>
std::string typenameof(const T &)
{
  typedef char const * const cc;
  // void prntype(const T&) [with T = int [100]]
  const size_t before = sizeof("std::string typenameof(const T&) [with T = ")-1;
  const size_t after = sizeof("]")-1;
  cc pretty = __PRETTY_FUNCTION__;
  cc begin = pretty + before;
  cc end = pretty + (sizeof(__PRETTY_FUNCTION__)-1) - after;
  return std::string(begin,end);
}
using namespace std;
int a[100];
typedef int A[100];
A b; 
A * c;
int main()
{
  //b = a; //запрещено
  c = &a;
#define MA(x) {cout << \
left << setw(16) << typenameof(x) << '\t' << \
left << setw(4)  << #x << " = " << \
left << setw(16) << x << \
"sizeof(" #x ")="<< sizeof(x) << \
endl;}
  MA(a)
  MA(c)
  MA(*a)
  MA(*c)
  MA(**c)
}

Выхлоп:

int [100]       	a    = 0x804b340       sizeof(a)=400
int (*)[100]    	c    = 0x804b340       sizeof(c)=4
int             	*a   = 0               sizeof(*a)=4
int [100]       	*c   = 0x804b340       sizeof(*c)=400
int             	**c  = 0               sizeof(**c)=4
Т.е. «a» - при попытке его передать в функцию вывода на экран приводится к указателю на первый элемент, но на самом деле указателя нет, есть только область памяти размером в 400 байт. А вот «c» -это уже настоящий указатель на массив. У него и тип «указатель на массив», и размер в машинное слово.

legolegs ★★★★★ ()
Ответ на: комментарий от vladimir-vg

Разумеется,

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

Тип _lin компилятору отлично известен.

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

Спасибо всем, разобрался если не во всём,
то значительно продвинулся вперед.

С ntp всё равно не согласен.
«Не пишите больше программ пока
не прочитаете (Кернигана и Ритчи)»
Читать программирование и при этом
самому не написать ни строчки -
не считаю хорошим советом.

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