2009-08-29 2 views
31

У меня есть структура следующим образом, с указателем на функцию с названием «длина», которая вернет длину члена символов.Функциональный указатель как член C struct

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

У меня есть функция, чтобы вернуть длину символов из указателя на PString:

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

У меня есть функция initializeString(), которая возвращает указатель на PString:

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

Понятно, что я делаю что-то очень неправильно с моими указателями здесь, потому что строка str->length = &length вызывает в моем отладчике сигнал EXC_BAD_ACCESS, как и `return strlen (self-> char с). У кого-нибудь есть понимание этой проблемы?

Я хочу, чтобы функция initializeString() возвращала указатель на PString и функцию длины, чтобы использовать указатель на PString в качестве входных данных. Это всего лишь эксперимент по реализации элементарной объектно-ориентированной системы на C, но у меня нет большого опыта работы с указателями. Спасибо за любую помощь, которую вы можете мне дать.

+2

Хотя вы говорите, что конкретно хотите вернуть указатель. В этом случае возвращение самой структуры намного лучше. Скорее всего, копировать структуру, и нет необходимости в распределении кучи тяжелого веса. Объекты String основаны на значении: у них нет идентификатора (адреса), но их равенство основано на их содержании. У вас тоже может быть такое чувство в вашей системе ООП. –

ответ

48

Выделить память для хранения символов.

#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; 
} 
+0

Отличный ответ! Вопрос: Мне нужно позвонить бесплатно (p), но мне также нужно освободить символы? –

+0

Полагаю, мне нужно написать деструктор. –

+12

Нет необходимости отбрасывать возвращаемое значение 'malloc' в C. Также вы должны инициализировать' str-> chars' после его выделения (т. Е. 'Str-> chars [0] = '\ 0';') , – caf

4

Указатель str не выделяется. Перед использованием он должен быть malloc 'd.

+0

Замените 'PString * str;' на 'PString * str = (PString *) malloc (sizeof (PString));' И в идеале вызовите 'free' с указателем, когда это будет сделано с его использованием, чтобы избежать утечек памяти. – jgottula

6

Моя догадка заключается в том, что частью вашей проблемы являются списки параметров, не соответствующие.

int (* length)(); 

и

int length(PString * self) 

не то же самое. Он должен быть int (* length)(PString *);.

... woah, это Джон!

Редактировать: и, как указано ниже, указатель на структуру никогда не должен указывать на что-либо. То, как вы это делаете, будет работать, только если вы объявляете простую структуру, а не указатель.

str = (PString *)malloc(sizeof(PString)); 
+0

Большое спасибо, Джейкоб. Я пойду вперед и попробую. –

+0

ОК, 'strlen (self-> chars)' все еще дает мне 'EXC_BAD_ACCESS'. –

4

Возможно, мне что-то не хватает, но выделили ли вы память для этой PString перед тем, как вы ее получили?

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

Вы также можете использовать «void *» (указатель void) для отправки адреса функции.

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; 
} 

Выход:

Length: 5