/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
Test af null-pointere
Fra : Kasper Laudrup


Dato : 28-10-03 23:20

Hejsa,
Et (forhåbentligt) simpelt spørgsmål.

Lad os sige jeg definerer et array af pointere fx.:

struct my_struct* p_array[20];

Og ellers malloc'er når jeg opretter structs i listen, er det så sikkert at
teste for om pladsen er ledig med fx.:

if(p_array[i] == NULL) printf("Plads ledig");

Hvad hvis jeg senere frigør pladsen med free(p_array[i]); ?

I mit "rigtige" program ser det ud til at virke fint, men jeg prøvede at
skrive et lille testprogram hvor overstående test aldrig så ud til at
virke.

På forhånd tak,
Kasper

Ps. Jeg bruger GCC 3.2.3, men jeg får ud fra det handler om standard
C-konventioner.

 
 
Bertel Brander (29-10-2003)
Kommentar
Fra : Bertel Brander


Dato : 29-10-03 00:19

Kasper Laudrup wrote:
> Hejsa,
> Et (forhåbentligt) simpelt spørgsmål.
>
> Lad os sige jeg definerer et array af pointere fx.:
>
> struct my_struct* p_array[20];
>
> Og ellers malloc'er når jeg opretter structs i listen, er det så sikkert at
> teste for om pladsen er ledig med fx.:
>
> if(p_array[i] == NULL) printf("Plads ledig");
>
> Hvad hvis jeg senere frigør pladsen med free(p_array[i]); ?
>
> I mit "rigtige" program ser det ud til at virke fint, men jeg prøvede at
> skrive et lille testprogram hvor overstående test aldrig så ud til at
> virke.
>
Hvis p_array er en global variabel bliver alle pointere i p_array sat
til NULL når programmet starter (medmindre du sætter dem til noget
andet).

Hvis p_array er en lokal variabel i en funktion bliver pointerene i
p_array ikke sat til NULL.

free(p_array[i]) sætter ikke p_array[i] til NULL, det skal du gøre selv,
hvis du vil kunne test for om pladen er ledig med if(p_array[i] ==
NULL).

/b


Igor V. Rafienko (29-10-2003)
Kommentar
Fra : Igor V. Rafienko


Dato : 29-10-03 00:35

[ Bertel Brander ]

[ ... ]

> Hvis p_array er en lokal variabel i en funktion bliver pointerene i
> p_array ikke sat til NULL.


$ cat null.c
void foo()
{
static void *bar;

if ( bar == 0 ) puts( "bar!" );
else puts( "impossible" );
}

int main()
{
foo();
}
$ ./a.out
bar!
$


Er ikke 'bar' en lokal variabel? :)





ivr
--
<html><form><input type crash></form></html>

Bertel Brander (29-10-2003)
Kommentar
Fra : Bertel Brander


Dato : 29-10-03 00:48

Igor V. Rafienko wrote:

> [ Bertel Brander ]
>
> [ ... ]
>
>
>>Hvis p_array er en lokal variabel i en funktion bliver pointerene i
>>p_array ikke sat til NULL.
>
>
>
> $ cat null.c
> void foo()
> {
> static void *bar;
>
> if ( bar == 0 ) puts( "bar!" );
> else puts( "impossible" );
> }
>
> int main()
> {
> foo();
> }
> $ ./a.out
> bar!
> $
>
>
> Er ikke 'bar' en lokal variabel? :)
>
Det afhænger af definitionen af "lokal variabel", jeg vil ikke kalde
det en lokal variabel, men (for nu at citere dig fra et andet indlæg)
en variabel med "static storage duration".

Men du har selvfølgelig ret, variable med "static storage duration"
bliver initialiseret til 0/NULL .

/b


Kasper Laudrup (29-10-2003)
Kommentar
Fra : Kasper Laudrup


Dato : 29-10-03 00:54

Tak, det fandt jeg også ud af ved at lede lidt.

Et par lidt mere generelt spørgsmål, som nok mere handler om hvad der er "pæn"
programmeringsstil:

Hvis jeg gerne vil have et array af structs er det så smartest/pænest at
allokere det statisk fx.:

struct my_struct {
   int p;
};
struct my_struct s[128];

eller (i forbindelse med mit oprindelige spørgsmål) at allokere dem
dynamisk når de skal bruges?

Hvis struct'sene er "meget" store er sidstnævnte vel bedst.

Hvad hvis man ikke er sikker på hvor mange structs man vil bruge, vil et
stort array pointers (så stort at det ikke burde være muligt at "løbe
tør") være bedre, eller skal man ud i noget der kan udvides dynamisk?

Som sagt, dette er nu mere noget jeg har tænkt lidt over, og da det virker
som der sidder nogen virkelig C-hajer herinde ville jeg da gerne lige høre
hvad man "plejer" at gøre.

/Kasper


Bertel Brander (29-10-2003)
Kommentar
Fra : Bertel Brander


Dato : 29-10-03 01:17

Kasper Laudrup wrote:

> Tak, det fandt jeg også ud af ved at lede lidt.
>
> Et par lidt mere generelt spørgsmål, som nok mere handler om hvad der er "pæn"
> programmeringsstil:
>
> Hvis jeg gerne vil have et array af structs er det så smartest/pænest at
> allokere det statisk fx.:
>
> struct my_struct {
>    int p;
> };
> struct my_struct s[128];
>
> eller (i forbindelse med mit oprindelige spørgsmål) at allokere dem
> dynamisk når de skal bruges?
>
> Hvis struct'sene er "meget" store er sidstnævnte vel bedst.
>
> Hvad hvis man ikke er sikker på hvor mange structs man vil bruge, vil et
> stort array pointers (så stort at det ikke burde være muligt at "løbe
> tør") være bedre, eller skal man ud i noget der kan udvides dynamisk?
>
> Som sagt, dette er nu mere noget jeg har tænkt lidt over, og da det virker
> som der sidder nogen virkelig C-hajer herinde ville jeg da gerne lige høre
> hvad man "plejer" at gøre.
>

Der er mange måder at løse problemet på og der er ikke én rigtig
løsning.

I praksis bruger jeg dynamiske arrays, enkelt og dobbelt linkede lister,
arrays med fast størrelse, og binære træer jævnligt.

I C++ kan man så udvide palletten med std::list, std::vector og std::map
osv.

Hvad der passer bedst afhænger meget af hvad man skal kunne med
listen/arryet.

/b


Kasper Laudrup (29-10-2003)
Kommentar
Fra : Kasper Laudrup


Dato : 29-10-03 03:42

Det var faktisk lige det svar jeg havde håbet på.

/Kasper
>
> Hvad der passer bedst afhænger meget af hvad man skal kunne med
> listen/arryet.
>
> /b


Byrial Jensen (29-10-2003)
Kommentar
Fra : Byrial Jensen


Dato : 29-10-03 18:03

Kasper Laudrup wrote:
> Tak, det fandt jeg også ud af ved at lede lidt.
>
> Et par lidt mere generelt spørgsmål, som nok mere handler om hvad der er "pæn"
> programmeringsstil:
>
> Hvis jeg gerne vil have et array af structs er det så smartest/pænest at
> allokere det statisk fx.:
>
> struct my_struct {
>    int p;
> };
> struct my_struct s[128];
>
> eller (i forbindelse med mit oprindelige spørgsmål) at allokere dem
> dynamisk når de skal bruges?

Generelt vil jeg sige at det er pænest at allokere hukommelsen når man
har brug for den, og frigive den igen når man ikke længere har brug den.
Globale og statiske variable bør normalt undgås medmindre man har helt
særlige grunde til at bruge dem alligevel.

Hvis hukommelsen kun skal bruges og kendes en af bestemt funktion (samt
evt. funktioner som denne funktion kalder), er automatiske variable
normalt bedst. I C99 behøves størrelsen af automatiske arrays ikke at
kendes på forhånd sådan som det var tilfældet tidligere.

Kan man ikke bruge automatiske variable, kan man bruge dymanisk
hukommelse allokeret med malloc() m.fl. Det har den ulempe at man selv
skal sørge for eksplicit at frigive hukommelsen igen hvis man vil undgå
at hukommelsen går tabt.

> Hvad hvis man ikke er sikker på hvor mange structs man vil bruge, vil et
> stort array pointers (så stort at det ikke burde være muligt at "løbe
> tør") være bedre, eller skal man ud i noget der kan udvides dynamisk?

"Så stor at det burde være umuligt at løbe tør"-princippet er ikke godt.
Enten løber man alligevel tør på et eller andet tidspunkt, eller også
bruger man urimeligt meget hukommelse, eller også gør man begge dele!
Brug et automatisk array hvis den nødvendige størrelse kendes på
kørselstidspunkter når det skal allokeres, og brug ellers malloc() og
realloc() efterhånden som behovet viser sig.


Soeren Sandmann (29-10-2003)
Kommentar
Fra : Soeren Sandmann


Dato : 29-10-03 00:59

Bertel Brander <bertel@post4.tele.dk> writes:

> Hvis p_array er en global variabel bliver alle pointere i p_array sat
> til NULL når programmet starter (medmindre du sætter dem til noget
> andet).

Strengt taget er det ikke rigtigt. Alle *bits* bliver sat til 0, men
C-standarden udelukker ikke at implementationer repræsenterer
NULL-pointere med noget andet end en samling 0-bits.

Personligt har jeg ikke særlig mange skrupler ved at antage at globale
og statiske pointer-variabler initialiseres til NULL, for i praksis er
det rigtigt[1], men det er godt nok at vide at det faktisk ikke
garanteres.


[1] Hvis nogen kender til en platform hvor det ikke er tilfældet, vil
jeg gerne høre om det.

Bertel Brander (29-10-2003)
Kommentar
Fra : Bertel Brander


Dato : 29-10-03 01:12

Soeren Sandmann wrote:

> Bertel Brander <bertel@post4.tele.dk> writes:
>
>
>>Hvis p_array er en global variabel bliver alle pointere i p_array sat
>>til NULL når programmet starter (medmindre du sætter dem til noget
>>andet).
>
>
> Strengt taget er det ikke rigtigt. Alle *bits* bliver sat til 0, men
> C-standarden udelukker ikke at implementationer repræsenterer
> NULL-pointere med noget andet end en samling 0-bits.
>
> Personligt har jeg ikke særlig mange skrupler ved at antage at globale
> og statiske pointer-variabler initialiseres til NULL, for i praksis er
> det rigtigt[1], men det er godt nok at vide at det faktisk ikke
> garanteres.
>
>

Det er rigtigt at en NULL pointer ikke behøver at være "alle-bit-0"
men globale pointere (og variable med static storage duration) vil
blive initialiseret til NULL.

Problemet kan f.ex opstå hvis man bruger memset (...) til at sætte en
pointer til NULL eller hvis man calloc'er en struktur med en pointer.

/b


Soeren Sandmann (29-10-2003)
Kommentar
Fra : Soeren Sandmann


Dato : 29-10-03 01:41

Bertel Brander <bertel@post4.tele.dk> writes:

> Det er rigtigt at en NULL pointer ikke behøver at være "alle-bit-0"
> men globale pointere (og variable med static storage duration) vil
> blive initialiseret til NULL.

Det har du fuldstændig ret i, i hvert fald hvis man tror på afsnit
6.7.8 i det udkast til C-standarden som man kan hente på

http://std.dkuug.dk/jtc1/sc22/open/n2794/

Hvis nogen (ligesom jeg) skulle være i tvivl, så er reglen for unions
at det er det første navngivne felt der tæller, så

union {
int *x;
int y;
} u;

initialiseres på en sådan måde at u.x == NULL, hvis u har static
storage duration.

Igor V. Rafienko (29-10-2003)
Kommentar
Fra : Igor V. Rafienko


Dato : 29-10-03 00:32

[ Kasper Laudrup ]

[ ... ]

> Lad os sige jeg definerer et array af pointere fx.:
>
> struct my_struct* p_array[20];
>
> Og ellers malloc'er når jeg opretter structs i listen, er det så
> sikkert at teste for om pladsen er ledig med fx.:
>
> if(p_array[i] == NULL) printf("Plads ledig");


Tja, det spørs jo hvor p_array er definert. Visse objekter blir
initialisert automatisk til 0 (der 0 tilpasses typen) ved definisjon.
Det gjelder fx. globale objekter og objekter med "static storage
duration":

$ ./a.out
(nil)
(nil)
(nil)
---------------
0x8048404
0x42130a14
0xbfffdba8
$ cat null.c
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <limits.h>

int* p_array[3];

int
main( int argc, char *argv[] )
{
char a;
int* p_array2[3];
short b;
size_t i;

for ( i = 0U; i != sizeof p_array / sizeof *p_array; ++i )
printf( "%p\n", (void*)p_array[ i ] );

puts( "---------------" );

for ( i = 0U; i != sizeof p_array2 / sizeof *p_array2; ++i )
printf( "%p\n", (void*)p_array2[ i ] );

return 0;
}
$


> Hvad hvis jeg senere frigør pladsen med free(p_array[i]); ?


Da vil p_array[i] høyst sannsynlig inneholde den gamle pekerverdien
(dvs. adressen), som ikke er gyldig lenger (men for all del, dette er
_ikke_ garantert). Vil du "nulle ut" den posisjonen som du nettopp har
free()gjort, må du gjøre det selv. Altså:

$ cat null.c
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <limits.h>

int* p_array[3];

int
main( int argc, char *argv[] )
{
p_array[0] = malloc( 10 * sizeof *p_array[0] );
/* do something exciting with p_array[0] */
printf( "%p\n", (void*)p_array[0] );
free( p_array[0] );
printf( "%p\n", (void*)p_array[0] );

return 0;
}
$ ./a.out
0x8049650
0x8049650
$





ivr
--
<html><form><input type crash></form></html>

Søg
Reklame
Statistik
Spørgsmål : 177558
Tips : 31968
Nyheder : 719565
Indlæg : 6408922
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste