C Array von Pointern - Pointer - Struct

hell-student

Lieutenant
Registriert
Nov. 2007
Beiträge
671
Hallo Zusammen,

Ich blicke es einfach nicht mehr durch. Ich würde das Array jedoch gerne dynamisch gestalten (mittels malloc bzw. calloc). Wie muss ich nun das Array implementieren?:

struct Task {
int id;
int num;
}

max_no_tasks = 10;

// Array mit 10 Pointer auf Tasks
Task **task_array;
task_array = (Task **) calloc(max_no_tasks, sizeof(Task*));
// Fehlerüberprüfung fehlt


Task *task;
task = (Task *) calloc(1, sizeof(Task));

task_array[0] = task;

Hab ich hier irgendein Denkfehler.

Hat jemand ein gutes Beispiel für ein dynamisches Pointerarray? thx
 
Was genau möchtest du erreichen, und was geht nicht? Sieht für mich auf den ersten Blick richtig aus.
 
Hi,

typedef struct {
int id;
int num;
} Task;

um das Struct so zu verwenden wie das tuen tust oder möchtest musst du es so machen und das ";" am schluss nicht vergessen


max_no_tasks = 10;

da gehört innerhalb einer Methode z.B: ein int davor oder außerhalb ein #define


task_array[0] = task;

das ist falsch aber funktioniert dennoch ;) ( richtiger währe "task_array + 0" )

usw.

poste mal bitte den ganzen sourcecode

Gruß
 
Die ersten beiden Fehler hab ich zugegebenermaßen übersehen, aber was ist an "task_array[0] = task;" falsch?
 
Hier mal mein Code.

Hatte den vorhigen Post so aus dem Kopf gemacht. Wie kann ich den 1 bzw. 2 etc Eintrag vom Array ein Task zuweisen?

void allocate_task_area(int id, int no_invade_jobs)
{
int i;
int slot;
Task *task = NULL;
task = (Task *)calloc(1, sizeof(Task));

// if there is no free slot in the task array -> double array size
if (task_counter + 1 > max_no_tasks) {
task_array = (Task **) realloc(task_array, 2 * max_no_tasks * sizeof(Task*));
// ToDo: check error for memory allocation
for(i = max_no_tasks; i < 2 * max_no_tasks; i++) {
(*(task_array + i)) = NULL;
}
max_no_tasks = 2 * max_no_tasks;
}

// search for the first free array slot
for (i = 0; i < max_no_tasks; i++) {
if (task_array != NULL) {
slot = i;
break;
}
}

task->id = id;

// wenn ich hier dem 5ten Eintrag im Array, also den Pointer auf den Task setzen möchte, wie kann ich das machen?
// (*(task_array + 4)) = &task gibt Fehler?
task_array = &task;

printf("%i\n", (*(task_array))->id);

task_counter++;
}


// wenn ich hier dem 5ten Eintrag im Array, also den Pointer auf den Task setzen möchte, wie kann ich das machen?
 
task_array[0] = task;

da behandelst du ein Zeiger auf ein Feld wie ein Array. Das ist zwar falsch. Funktionieren tut es dennoch ;)
Ergänzung ()

task_array = &task;

da müsste

*task_array = task;

"task_array" steht an stelle "0" des Feldes auf das es zeigt und 'task' ist ja schon ein zeiger. Also entfällt das "&". Weil mit '&task' greifst du auf die addresse des Zeigers zu.
Ergänzung ()

// (*(task_array + 4)) = &task; // gibt Fehler?

bist auf das "&task" wo das "&" zu viel ist ;) ist das richtig.
 
Danke für die Hilfe. Hatte es nun selbst erkannt bevor ich noch dein Post las. Ich finds immer wieder nicht so einfach mit Pointern =)
 
mit task_array[0] = task dereferenziert er doch nur das erste Element des Arrays das aus Pointern besteht, kriegt also seinen ersten Pointer aus dem Array.

Was ist denn daran falsch bitte?
Das ist das selbe wie *(task_array + 0), wobei die erste Schreibweise besser zu lesen ist, meiner Meinung nach.
In beiden Fällen bekommt er einen seiner Pointer und kann ihm etwas zuweisen.

Er hätte ja auch Task* task_array[] deklarieren können oder nicht? Ist doch auch das gleiche wie Task** task_array?

Oder stehe ich hier gewaltig auf dem Schlauch?
 
Zuletzt bearbeitet:
Ein Array ist doch nur ein Pointer auf einen Speicherbereich. Ich versteh deshalb nicht wieso das falsch sein soll.


Sorry dass ich den Thread hier mit Offtopic zumülle, aber man will ja was lernen^^
 
;D Streng genommen ist ein Array kein Pointer auf einen Speicherbereich. ich binn mir fast sicher das beides zum gleichen Assembler code führt dennoch ist es falsch! Funktioniert aber trotzdem ;)

und besser lesbar ist es gewiss ;)
Ergänzung ()

wenn überhaupt dann ist


das gleich wie ein Zeiger.
Ergänzung ()

http://openbook.galileocomputing.de/c_von_a_bis_z/012_c_zeiger_007.htm

gleich oben lesen. ;D
 
Danke. Wiedermal was gelernt.
 
Zuletzt bearbeitet:
Genauer ;)

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

void array( int a[] )
{
    int i;

    for( i = 0; i < 5; i++ )
        printf( "%d", a[ i ] );
}

void pointer( int *p )
{
    int i;

    for( i = 0; i < 5; i++ )
        printf( "%d", p[ i ] ) );
//        printf( "%d", *(  p + i ) );    // beides führt zum gleichen Ergebniss.
}


int main()
{
    int i;

    int _array[] = { 0, 1, 2, 3, 4 };
    int *_pointer = malloc( sizeof( int ) * 5 );

    for( i = 0; i < 5; i++ )
        *( _pointer + i ) = ( i + 5 );


    array( _array );
    printf("\n" );
    pointer( _pointer );
    printf("\n" );
}

das übersetzt du mit z.B:

gcc Pointer.c -S -masm=intel

schaust dir die


.file "Pointer.c"
.intel_syntax noprefix
.section .rdata,"dr"
LC0:
.ascii "%d\0"
.text
.globl _array
.def _array; .scl 2; .type 32; .endef
_array:
push ebp
mov ebp, esp
sub esp, 40
mov DWORD PTR [ebp-12], 0
jmp L2
L3:
mov eax, DWORD PTR [ebp-12]
sal eax, 2
add eax, DWORD PTR [ebp+8]
mov eax, DWORD PTR [eax]
mov DWORD PTR [esp+4], eax
mov DWORD PTR [esp], OFFSET FLAT:LC0
call _printf
add DWORD PTR [ebp-12], 1
L2:
cmp DWORD PTR [ebp-12], 4
jle L3
leave
ret

.globl _pointer
.def _pointer; .scl 2; .type 32; .endef
_pointer:
push ebp
mov ebp, esp
sub esp, 40
mov DWORD PTR [ebp-12], 0
jmp L5
L6:
mov eax, DWORD PTR [ebp-12]
sal eax, 2
add eax, DWORD PTR [ebp+8]
mov eax, DWORD PTR [eax]
mov DWORD PTR [esp+4], eax
mov DWORD PTR [esp], OFFSET FLAT:LC0
call _printf
add DWORD PTR [ebp-12], 1
L5:
cmp DWORD PTR [ebp-12], 4
jle L6
leave
ret

.def ___main; .scl 2; .type 32; .endef
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
push ebp
mov ebp, esp
and esp, -16
sub esp, 48
call ___main
mov DWORD PTR [esp+20], 0
mov DWORD PTR [esp+24], 1
mov DWORD PTR [esp+28], 2
mov DWORD PTR [esp+32], 3
mov DWORD PTR [esp+36], 4
mov DWORD PTR [esp], 20
call _malloc
mov DWORD PTR [esp+40], eax
mov DWORD PTR [esp+44], 0
jmp L8
L9:
mov eax, DWORD PTR [esp+44]
sal eax, 2
add eax, DWORD PTR [esp+40]
mov edx, DWORD PTR [esp+44]
add edx, 5
mov DWORD PTR [eax], edx
add DWORD PTR [esp+44], 1
L8:
cmp DWORD PTR [esp+44], 4
jle L9
lea eax, [esp+20]
mov DWORD PTR [esp], eax
call _array
mov DWORD PTR [esp], 10
call _putchar
mov eax, DWORD PTR [esp+40]
mov DWORD PTR [esp], eax
call _pointer
mov DWORD PTR [esp], 10
call _putchar
leave
ret
.def _printf; .scl 2; .type 32; .endef
.def _putchar; .scl 2; .type 32; .endef
.def _malloc; .scl 2; .type 32; .endef

an und stellst fest das wie ich sagte es zwischen beiden eigentlich keinen Unterschied gibt.

und der Satzt:

"It is useful to realize that a reference like x[3] generates different code depending on whether x is an array or a pointer."

nicht viel her gibt.

Das was die Sache falsch macht ist nicht das es Falsch ist! Sondern weil der C Standart/Compiler und evtl. die OS Speicherverwalltung das so möchten! :D
 
Zuletzt bearbeitet:
ich sehe noch nicht so recht, was das problem an x im gegensatz zu *(x+i) sein soll?

der C-standard sagt mir:

The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))).
 
Schrieb ich ja schon weiter oben, aber die Herren hier hängen sich ja eher daran auf, dass es intern nicht gänzlich das Gleiche ist oder nicht so gedacht ist.

Für den Programmierer ist es aber letztendlich egal und welche der beiden Varianten er nutzt ist unerheblich für das was man zurückbekommt.
 
ich sehe noch keinerlei unterschied, selbst was die interne darstellung oder sonst was angeht.
der standard definiert die beiden varianten als äquivalent.
 
Um nochmal zusammenzufassen, was ich aus den verlinkten Artikeln mitgenommen hab:
  • Ein Array bezeichnet einen Bereich von Elementen
  • Ein Pointer kann nur auf einen Element zeigen (z.B. das erste in einem Feld)
Soweit sind wir uns sicher alle noch einig.

In den meisten Fällen wird ein Array vom Compiler auch nur als ein Pointer auf ein Element angesehen wodurch sich die gleiche Benutzung und der gleiche Binärcode ergeben. Der Unterschied ist allerdings, dass der Compiler stets weiß ob es sich um eine Array oder um einen Pointer handelt. Das wird beispielsweise beim Aufruf von sizeof deutlich, da hier entweder die Größe des gesamten Arrays zurückgegeben wird oder eben nur die Größe eines Pointers.
Ich würde deshalb trotzdem nicht soweit gehen und sagen die [] Notation falsch ist, da sie wie maxwell anmerkte nur syntaktischer Zucker für (*((E1)+(E2))) ist. Wichtig finde ich jedoch, dass man weiß was im Hintergrund gespielt wird und man so eventuelle Fehler vermeiden oder zumindest erkennen kann.
 

Ähnliche Themen

Zurück
Oben