2012-06-02 2 views
2

Я работаю над программой для класса C, и я достиг точки, где я не знаю, что делать. Мы реализуем тип библиотеки String.Непоследовательность c указателей

У меня есть заголовочный файл (MyString.h)

typedef struct { 
    char *buffer; 
    int length; 
    int maxLength; 
} String; 

String *newString(const char *str); 

В файле реализации функций (MyString.c)

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

String *newString(const char *str) { 

// Allocate memory for the String 
String *newStr = (String*)malloc(sizeof(String)); 

if (newStr == NULL) { 
    printf("ERROR: Out of memory\n"); 
    return NULL; 
} 

// Count the number of characters 
int count; 
for (count = 0; *(str + count) != '\0'; count++); 
count++; 

// Allocate memory for the buffer 
newStr->buffer = (char*)malloc(count * sizeof(char)); 

if (newStr->buffer == NULL) { 
    printf("ERROR: Out of memory\n"); 
    return NULL; 
} 

// Copy into the buffer 
while (*str != '\0') 
    *(newStr->buffer++) = *(str++); 
*(++newStr->buffer) = '\0'; 

// Set the length and maximum length 
newStr->length = count; 
newStr->maxLength = count; 

printf("newStr->buffer: %p\n",newStr->buffer); // For testing purposes 

return newStr; 
} 

И тестер (main.c)

#include <stdio.h> 
#include "MyString.h" 

main() { 
char str[] = "Test character array"; 

String *testString = newString(str); 

printf("testString->buffer: %p\n",testString->buffer); // Testing only 
} 

Проблема в том, что, хотя testString указывает на String, созданный в newString(), их буферы указывают на разное запоминание y адресов. Почему это?

Заранее спасибо

ответ

2

Используя *(++newStr->buffer) и *(newStr->buffer++), вы двигаетесь newStr->buffer по существу указывают на конец строки .. Вам нужно изменить свой код, например:

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

String *newString(const char *str) { 
    // Allocate memory for the String 
    String *newStr = (String*)malloc(sizeof(String)); 

    if (newStr == NULL) { 
     printf("ERROR: Out of memory\n"); 
     return NULL; 
    } 

    // Count the number of characters 
    int count; 
    for (count = 0; *(str + count) != '\0'; count++); 
    count++; 

    // Allocate memory for the buffer 
    newStr->buffer = (char*)malloc(count * sizeof(char)); 

    if (newStr->buffer == NULL) { 
     printf("ERROR: Out of memory\n"); 
     return NULL; 
    } 

    char *pBuffer = newStr->buffer; // don't move newStr->buffer, have another pointer for that. 

    // Copy into the buffer 
    while (*str != '\0') 
     *(pBuffer++) = *(str++); 
    *pBuffer = '\0'; 

    // Set the length and maximum length 
    newStr->length = count; 
    newStr->maxLength = count; 

    printf("newStr->buffer: %p\n", newStr->buffer); // For testing purposes 

    return newStr; 
} 
+1

Это подействовало. Большое спасибо! – fpele

+0

Как было предложено другими ответами, я также рассмотрел бы использование strcpy вместо ручного копирования строки тоже :) – Saul

+1

@fpele Кроме того, '* (++ pBuffer) = '\ 0';' должен быть '* pBuffer = '\ 0' ; '. Когда копирование 'while' заканчивается,' pBuffer' уже указывает один за последним написанным символом. С '* (++ pBuffer) = '\ 0';', у вас есть один неуказанный байт между скопированной частью и 0-терминатором, который вы пишете, и, что более важно, ** вы пишете за конец 'malloc' ed memory **. Это неопределенное поведение. –

2

You изменяют указатель буфера внутри вновь созданной структуры String.

Вы должны сделать:

char *newBuffer = newStr->buffer; 
// Copy into the buffer 
while (*str != '\0') 
    *(newBuffer++) = *(str++); 
*(++newBuffer) = '\0'; 
1

Объяснение довольно простое: Вы изменяете указатель буфера в функции newString():

// Copy into the buffer 
while (*str != '\0') 
    *(newStr->buffer++) = *(str++); 
*(++newStr->buffer) = '\0'; 

Вы можете использовать временный указатель здесь (как предложено в другие ответы), но я хотел бы рекомендовать использовать стандартные функции, предусмотренные в пределах string.h:

// Count the number of characters 
int count; 
count = strlen(str) + 1; 

// Copy into the buffer 
memcpy(newString->buffer, str, count) 
2

Как уже указывали другие коллеги, вы изменили указатель на размещение, что нет. Вот ваш пример, но переводится на более «профессиональный» способ.

Я хотел бы изменить свою структуру:

typedef struct { 
    char *buffer; 
    size_t length;  /* strings and allocation in C are of type size_t not int */ 
    size_t alloclength; 
} String; 

String *newString(const char *str); 

И функция будет изменено.

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

String *newString(const char *str) 
{ 
    // Allocate memory for the String 
    String *newStr = malloc(sizeof (String)); /* No typecast of void * in C, it's bad taste. */ 

    if(!newStr) { 
    fprintf(stderr, "ERROR: Out of memory\n");  /* Errors are meant to be printed on stderr, not stdio */ 
    return NULL; 
    } 
    // Count the number of characters 
    newStr->length = strlen(str);   /* Learn to use the stdlib, there are a lot of usefull functions */ 
    newStr->alloclength = newStr->length+1; 
    // Allocate memory for the buffer 
    newStr->buffer = malloc(newStr->alloclength); /* sizeof (char) is by definition always 1 */ 
    if(!newStr->buffer) { 
    fprintf(stderr, "ERROR: Out of memory\n"); 
    return NULL; 
    } 
    // Copy into the buffer 
    strcpy(newStr->buffer, str); /* Because we already scaned the input with strlen, we can use safely the "unsafe" strcpy function. The strcpy will add the trailing 0 */ 
    printf("newStr->buffer: %p\n",newStr->buffer); // For testing purposes 
    return newStr; 
} 
1

вопрос ответ, но я думаю, что есть кусок кода, который вы должны добавить, чтобы избежать тонкий источника утечки памяти:

// Allocate memory for the buffer 
newStr->buffer = (char*)malloc(count * sizeof(char)); 

if (newStr->buffer == NULL) { 
    printf("ERROR: Out of memory\n"); 
    free(newStr); // free the memory allocated for newStr 
    return NULL; 
} 
Смежные вопросы