web-dev-qa-db-fra.com

Pointeur de fonction en tant que membre d'une structure C

J'ai une structure comme suit, avec un pointeur sur une fonction appelée "longueur" qui retournera la longueur du membre chars.

typedef struct pstring_t {
    char * chars;
    int (* length)();
} PString;

J'ai une fonction pour retourner la longueur des caractères d'un pointeur à un PString:

int length(PString * self) {
    return strlen(self->chars);
}

J'ai une fonction initializeString () qui renvoie un pointeur sur un PString:

PString * initializeString() {
    PString *str;
    str->length = &length;
    return str;
}

Il est clair que je fais quelque chose de très faux avec mes pointeurs ici, car la ligne str->length = &length provoque un signal EXC_BAD_ACCESS dans mon débogueur, de même que `return strlen (self-> caractères). Est-ce que quelqu'un a un aperçu de ce problème?

Je veux spécifiquement pouvoir faire en sorte que la fonction initializeString () renvoie un pointeur sur un PString, et la fonction length d'utiliser un pointeur sur un PString en tant qu'entrée. Ceci est juste une expérience dans la mise en œuvre d'un système rudimentaire orienté objet en C, mais je n'ai pas beaucoup d'expérience avec les pointeurs. Merci pour toute l'aide que tu peux m'apporter.

40
Jonathan Sterling

Alloue de la mémoire pour contenir des caractères.

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

typedef struct PString {
        char *chars;
        int (*length)();
} PString;

int length(PString *self) {
    return strlen(self->chars);
}

PString *initializeString(int n) {
    PString *str = malloc(sizeof(PString));

    str->chars = malloc(sizeof(char) * n);
    str->length = length;

    str[0] = '\0'; //add a null terminator in case the string is used before any other initialization.

    return str;
}

int main() {
    PString *p = initializeString(30);
    strcpy(p->chars, "Hello");
    printf("\n%d", p->length(p));
    return 0;
}
54
adatapost

À mon avis, le problème réside en partie dans le fait que les listes de paramètres ne correspondent pas.

int (* length)();

et

int length(PString * self)

ne sont pas les mêmes. Ce devrait être int (* length)(PString *);.

... woah, c'est Jon!

Edit : et, comme mentionné ci-dessous, votre pointeur struct n'est jamais configuré pour pointer sur quoi que ce soit. La façon dont vous le faites ne fonctionnerait que si vous déclariez une structure simple, pas un pointeur.

str = (PString *)malloc(sizeof(PString));
6
jtbandes

Le pointeur str n'est jamais attribué. Il devrait être malloc 'd avant utilisation.

4
jgottula

Peut-être me manque quelque chose ici, mais avez-vous alloué de la mémoire pour ce PString avant d'y accéder?

PString * initializeString() {
    PString *str;
    str = (PString *) malloc(sizeof(PString));
    str->length = &length;
    return str;
}
4
EdH

Vous pouvez également utiliser "void *" (pointeur de void) pour envoyer une adresse à la fonction.

typedef struct pstring_t {
    char * chars;
    int(*length)(void*);
} PString;

int length(void* self) {
    return strlen(((PString*)self)->chars);
}

PString initializeString() {
    PString str;
    str.length = &length;
    return str;
}

int main()
{
    PString p = initializeString();

    p.chars = "Hello";

    printf("Length: %i\n", p.length(&p));

    return 0;
}

Sortie:

Length: 5
0
ontech7