Più tipi di dati per singola variabile in C

1

Sto cercando di implementare i cons di base, car e cdr di SCHEME in C. Ho creato un semplice programma che mi permette di gestire due interi come mostrato nel programma principale. Tuttavia, desidero che il mio programma sia in grado di utilizzare un oggetto "consed" con una cifra oltre che un "oggetto condiviso" con un altro "oggetto condiviso" come mostrato di seguito:

  • (contro 2 3)
  • (contro 2 (contro 2 3))
  • (cons (contro 2 3) (contro 2 3))

Poiché la limitazione deriva dal fatto che i dati nella struct sono di tipo int, è possibile che una variabile accetti più tipi di dati in C? Se sì, come? In caso contrario, c'è un altro modo per affrontare questo problema? Ecco il mio codice:

#include <stdio.h>
#include <string.h>

typedef struct cons_object {
int data;
struct node* next;
} cons_object;

cons_object* cons(int x, int y )
{
cons_object* car = NULL;
cons_object* cdr = NULL;
car = malloc(sizeof(struct cons_object));
cdr = malloc(sizeof(struct cons_object));
car->data = x;
car->next = cdr;
cdr->data = y;
cdr->next = NULL;
return car; /*returns the pointer car*/
}

int car(cons_object* list) /*takes in a consed object*/
{
cons_object* car = list;
int y;
y = car->data;
return y;
}

int cdr(cons_object* list)
{
cons_object* cdr = list;
cdr = cdr->next;
int z;
z= cdr->data;
return z;

}

int main ()
{
int y = car (cons(33,42));
printf("%d\n",y);
int z = cdr (cons(3,4));
printf("%d\n",z);
return 0;

}
    
posta Avian78 17.07.2013 - 17:08
fonte

2 risposte

7

Oltre al commento di ratchet freak, cerca unione discriminata o unione taggata .

Puoi rendere il tuo tipo di dati un void * , ma anche devi tenere traccia di ciò che realmente punta. Cioè, a un certo punto devi capire se si tratta di un intero o di un doppio o di un altro elenco.

La stessa etichetta taggata potrebbe essere simile a questa:

#include <stdlib.h>
#include <assert.h>

enum TypeTag { NoType, CharType, IntType, DoubleType, ConsType };
union Value {
    char c;
    int i;
    double d;
    void *p;
};
struct TaggedType {
    enum TypeTag type;
    union Value value;
};

e il codice cons può utilizzarlo, senza preoccuparsi di quale tipo si trovi realmente all'interno della struttura TaggedType , come in questo caso:

struct ConsNode {
    struct TaggedType value;
    struct ConsNode *next;
};

struct ConsNode *cons(struct TaggedType value, struct ConsNode *next) {
    struct ConsNode *head = malloc(sizeof *head);
    head->value = value;
    head->next = next;
    return head;
}
struct TaggedType *car(struct ConsNode *head) {
    return &head->value;
}
struct ConsNode *cdr(struct ConsNode *head) {
    return head->next;
}

Quindi tutto ciò di cui hai bisogno è il codice box / unboxing per lavorare con i tipi concreti effettivi:

struct TaggedType mkint(int i) {
    struct TaggedType value = { IntType, {.i=i} };
    return value;
}
struct TaggedType mkdbl(double d) {
    struct TaggedType value = { DoubleType, {.d=d} };
    return value;
}

int toint(struct TaggedType *data) {
    assert(data->type == IntType);
    return data->value.i;
}
double todbl(struct TaggedType *data) {
    assert(data->type == DoubleType);
    return data->value.d;
}

int main () {
    struct ConsNode *list = cons(mkint(33), cons(mkint(42), NULL));
    int y = toint(car(list));
    assert(y == 33);
    assert(toint(car(cdr(list))) == 42);
    return y;
}

Si noti che la maggior parte delle operazioni di elenco non conoscono o si preoccupano del tipo memorizzato in ogni nodo - questo diventa importante solo quando si fa qualcosa con esso.

    
risposta data 17.07.2013 - 17:50
fonte
2

Rendilo un void * . Quindi può indicare qualsiasi cosa. La gestione della memoria dipende da te.

Ciò non comporterà alcun tipo di controllo. Se segui questo percorso, vedi link per ciò che è possibile. (Ma se vuoi seguire questa strada, perché stai scrivendo in C?)

    
risposta data 17.07.2013 - 17:14
fonte

Leggi altre domande sui tag