C++ масив

15 отговора 961 прегледа
#1

C++ масив

Досега не зе бях замислял за това, но случайно се сблъсках с този въпрос:
един масив ( от char ) . Масива се дефинира в някакъв метод, в същия метод резултата от sizeof за този масив връща броя на байтовете заделени за масива. Подаден като параметър на някакъв метод, резултата sizeof за този масив връща размера на указатея, който е с коректната стойност 4 байта, но не и размера на масива.
Имате ли обяснение за това ?

// code
void fun1();
void fun2(char a[]);


int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
fun1();
return 0;
}

void fun1()
{
char a[] = "Hello Africa";
printf("sizeof a = %d\tstrlen a = %d\n", sizeof(a), strlen(a));
fun2(a);
}

void fun2(char a[])
{
printf("sizeof a = %d\tstrlen a = %d\n", sizeof(a), strlen(a));
}
// end code

result:
-----------------------------
sizeof a = 13 strlen a = 12
sizeof a = 4 strlen a = 12
Press any key to continue

Отговор
в отговор на eek #2

Re: C++ масив

"Обяснение" не е нужно, това е поведението, което стандартът специфицира.

Ето един цитат от MSDN: "When the sizeof operator is applied to an array, it yields the total number of bytes in that array, not the size of the pointer represented by the array identifier. To obtain the size of the pointer represented by the array identifier, pass it as a parameter to a function that uses sizeof.".

В твоя случай, тази декларация: "char a[] = "Hello Africa";" е еквивалентна на " char a[13] = "Hello Africa";". Затова и получаваш sizeof 13. От друга страна, декларацията "void fun2(char a[])" е еквивалентна на "void fun2(char *a)". Това мисля изяснява нещата.

Отговор
в отговор на eek #3

Re: C++ масив

наскоро някой ми беше разправял за предаване на масив във стека нещо, как по рано го имало после било премахнато щото много неразумно го ползвали. работата е там че при предаване на масив би трябвало да се копира целия в стека. поради това че много от програмистите не го съзнават това, то е направено отстъпление от принципа, и ако се декларира void func(char a[200]) то компилатора предава само указателя. това донякъде ме дразни, защото изразява една по-глобална тенденция да се усложнява живота на квалифицираните, в полза на неквалифицираните. верно е че в почти всички случаи да се предава по стойност масив е чиста лудост, но все пак принципа си е принцип. ако исках само указател, щях да напиша char *a. поне да го даваше като грешка, а то си трае. в края на краищата който иска да пише без да се интересува какво става отдолу, има си java i VB.

Отговор
в отговор на zaphod #4

Re: C++ масив

Imash predvid kato w Turbo/Borland Pascal-a? (Delphi-to)? Ne znam dali e standartno tova i za ostanalite Pascali-i de...

No pri tjah se podawashe w steka masiva, dokolkoto si spomnjam.

Naistina izglezhda razumno ako e napisano

char func( int a[100] ) - da se podadat neshta w steka....

Problema, obache e sus tova KOJ OSVOBOZHDAWA steka:

Pri Pascal (Borland/Turbo), ili wuobshte pri __pascal, ili __stdcall callovete- tam steka se osvobozhdawa ot funckiata - tja si popwa i restorwa ebp/esp.

Pri C, ili po-tochno pri _cdecl call-a - tam tozi kojto izwikwa opravja steka - funckiata ne se grizhi za tova.

Mozhe bi e svurzano s poslednite dve neshta, no ne mi e mnogo jasno - ne wizhdam direktna vruzka... Njakoi ako se seshta neshto po-tochno...

Отговор
в отговор на malkia #5

Re: C++ масив

Мисля, че няма такава връзка.
А в C/C++, който иска да предава масиви по стойност, да ги вкара в struct-ура.

Отговор
в отговор на Pesho® #6

абе то начини има

може и да си го копираш, ама мен ме дразни че се нарушава правило.

Отговор
в отговор на eek #7

Re: C++ масив

не се излагай, достатъчно е само да се спомене, че sizeof се смята по време на компилация, а не по време на изпълнение.

Отговор
в отговор на eek #8

Re: C++ масив

вярно, бре
то сичко идва от това: char* и char [13] ....
т.е. ако декларираш ф-ята така: void fun(char a[13]); sizeof ще върне 13 ...

Отговор
в отговор на eek #9

аха, как пък не

пробва ли го? не е нещо дълго, пробвай и ще видим дали ще даде 13.

Отговор
в отговор на zaphod #10

Re: аха, как пък не

не дава, аз снощи го пробвах
Все си е 4.

Мечтата е мисъл, мисълта е идея, всяка идея се реализира. Аз не мечтая, а реализирам идеите си.
Отговор
в отговор на eek #11

Re: C++ масив

Ako imash slednia kod:

void fcall1()
{
char aaa[10] = "string";
fun(aaa);
}
void fcall2()
{
char bbb[15] = "drug string";
fun(bbb);
}
void fun(char a[])
{
printf("sizeof a = %d\tstrlen a = %d\n", sizeof(a), strlen(a));
}

w compile time kompilatora kak da zamesti sizeof(a) wuw fun(char a[]) ednowremenno s 10 i 15

Отговор
в отговор на joker #12

Re: C++ масив

Много просто - големината на far pointer е 4 байта, независимо към какво сочи. Ти другите мнения не чете ли?

Както се оказва sizeof() наистина се изчислява при компилацията. Има обаче нещо гнило в Дания. Аз се чудех как ще се определи големината на обект при полиморфизъм. Затова написах следното тестче:

//***********************************************
// Trial.cpp : Defines the entry point for the console application.
//


#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <assert.h>

//===================================================================

class base {
double dBase;

public:
base(double Base) { dBase = Base; }
};

//===================================================================

class child1:public base {
int i1;

public:
child1(double Dbl,int Int1):base(Dbl) { i1 = Int1; }
};

//===================================================================

class child2:public base {
double d1;

public:
child2(double Dbl,double Dbl1):base(Dbl) { d1 = Dbl1; }

};


//===================================================================

int main(int argc, char* argv[])
{

base Bs(42);
child1 Ch1(42,42);
child2 Ch2(42,42);
base *pBs = new base(42);
base *pCh1 = new child1(42,42);
base *pCh2 = new child2(42,42);

printf("Non-referenced sizes: B = %d, Ch1 = %d, Ch2 = %d\n",sizeof(Bs),sizeof(Ch1),sizeof(Ch2));
printf("Referenced sizes: B = %d, Ch1 = %d, Ch2 = %d\n",sizeof(*pBs),sizeof(*pCh1),sizeof(*pCh2));

while(!kbhit());

delete pBs; delete pCh1; delete pCh2;

return 0;
}

//***********************************************

Та, резултатът е следния:

Non-referenced sizes: B = 8, Ch1 = 16, Ch2 = 16
Referenced sizes: B = 8, Ch1 = 8, Ch2 = 8

Асемблерният код преди извикване на printf е съответно:

push 10h
push 10h
push 8

push 8
push 8
push 8

и това за Debug mode, не за Release. От това следват две неща:

1. sizeof() наистина се изчислява при компилацията
2. sizeof() бърка когато става дума за полиморфизъм, като ти връща големината на класа за които е обявен поинтера. а не на обекта към който сочи в действителност. Следователно ако ти трябва големината на обекта в run-time трябва да ползваш друга технология.

Със здраве!

Мечтата е мисъл, мисълта е идея, всяка идея се реализира. Аз не мечтая, а реализирам идеите си.
Отговор
#13

Re: C++ масив

Абе аре са, ем цветен телевизор, ем па и да работи...

Мечтата е мисъл, мисълта е идея, всяка идея се реализира. Аз не мечтая, а реализирам идеите си.
Отговор
в отговор на Duncan Griffin #14

Re: C++ масив

да, sizeof дава големината според декларацията на указателя. иначе не можеш да му хванеш края. а да кажеш че бърка е малко пресилено. в края на краищата ако направиш
int *ip;
char c;
ip=(int*)&c;
printf("%d",sizeof(*ip));
нали не очакваш да ти напише 1...
а и като се замисли човек, то не е функция. ако беше, какъв тип е аргумента и? никакъв, може да сложиш име на клас, може да сложиш инстанция, може да сложиш всичко.

Отговор
в отговор на zaphod #15

Re: C++ масив

Ммм прав си за бъркането, не е коректно изказването... Аз досега изобщо не бях се замислял за тия неща, sizeof го ползвам изключително за structs и unions.

Мечтата е мисъл, мисълта е идея, всяка идея се реализира. Аз не мечтая, а реализирам идеите си.
Отговор
в отговор на zaphod #16

Re: C++ масив

he, mi mnogo qsno che ne e funkciq sizeof e klyuchova duma(sintaktichna edinica v ezila, bla-bla...), sushto kato if, for, struct i t.n.

Отговор