Перепрограммирование Calloc / Realloc в C с помощью пустых указателей - PullRequest
0 голосов
/ 11 января 2019

Я на самом деле изучаю программирование на С, и моя школа фактически не позволяет нам использовать calloc / realloc без их перепрограммирования. Вот почему я прошу о помощи.

Вот моя проблема: Я хочу использовать void *, чтобы сделать мой код многократно используемым, но я сталкиваюсь с проблемой "разыменование * указателя void *", когда пытаюсь запустить мой массив. Я не могу подобрать тип окончательного указателя.

Вот мои функции:

#include <stdlib.h>

void *my_calloc(size_t size, size_t n)              //n = number of bytes your type : sizeof(<whatever>)
{
    void *ptr = NULL;

    if (size < 1 || n < 1)
        return (NULL);
    ptr = malloc(n * (size + 1));
    if (ptr == NULL)
        return (NULL);
    for (int i = 0; i != (n * (size + 1)); i++) {
        *ptr = NULL;                                //Here is my problem
        ptr++;
    }
    return (ptr);
}

void *my_realloc(void *src, size_t size, size_t n)
{
    void *dst = NULL;
    int dst_len = 0;

    if (src == NULL || size < 0 || n < 1)
        return (NULL);
    dst_len = my_strlen(src) + size;
    if (dst_len == my_strlen(src))
        return (src);
    dst = my_calloc(dst_len, n);
    if (dst == NULL)
        return (NULL);
    for (int i = 0; src[i] != NULL;i++)
        dst[i] = src[i];                        //Here is the same problem...
    free(src);
    return (dst);
}

Я просто нахожу проблему во время написания своего поста, моя my_strlen функция может принимать только символ * ... поэтому мне нужна функция my_strlen, похожая на:

int my_strlen(void *str)
{
    int len = 0;

    while (str[len] != NULL) {                //same problem again...
        len++;
    }
    return (len);
}

Типичная функция, в которой я вызываю calloc / malloc:

int main(void)
{
    char *foo = NULL;
    int size = 0;
    int size_to_add = 0;

    size = <any size>;
    //free(foo);                                //only if foo has been malloc before
    foo = my_calloc(size, typeof(*foo));

    //something

    size_to_add = <any size>;
    foo = my_realloc(foo, size_to_add, sizeof(*foo))

    //something

    free(foo);
    return (0);
}

Спасибо за попытку помочь мне.

Ответы [ 2 ]

0 голосов
/ 11 января 2019

my_calloc() имеет различные проблемы:

Попытка математического указателя на void *

Это неопределенное поведение (UB).
Вместо этого сделайте ptr символьный указатель.

// void *ptr = NULL;
unsigned char *ptr = NULL;
...
ptr++;

Попытка отмены ссылки a void *

Это также UB.
Вместо этого сделайте ptr символьный указатель.

// void *ptr = NULL;
unsigned char *ptr = NULL;
...
// *ptr = NULL;
*ptr = '\0';

my_calloc() выделяет больше памяти, чем calloc()

Чтобы сделать то же самое, что и calloc(), не добавляйте его.

// ptr = malloc(n * (size + 1));
ptr = malloc(n * size);

Без защиты от переполнения

my_calloc() не обнаруживает переполнение с помощью n * (size + 1). Тест

// Note: it is known n > 0 at this point
if (SIZE_MAX/n > size+1) return NULL;
// or if OP drop the + 1  idea, 
if (SIZE_MAX/n > size) return NULL;

my_realloc() имеет различные проблемы:

Другая подпись

Я ожидаю, что цель «школа на самом деле не позволяет нам использовать calloc / realloc без перепрограммирования их» предназначалась для создания realloc() замены, которой my_realloc() не соответствует. Если требуется другая функция, рассмотрите новое имя

void *my_realloc(void *src, size_t size, size_t n)
// does not match
void *realloc(void *ptr, size_t size);

Невозможность обработать сокращающиеся ассигнования

При копировании данных не учитывается, что новое распределение может быть меньше предыдущего. Это приводит к UB.

Ненужный код

size < 0 всегда ложно

Утечка памяти

Приведенный ниже код не освобождает src перед возвратом. Кроме того, он ничего не выделяет, когда n>0. Это отличается от calloc(pit, 0) и calloc(NULL, 42).

// missing free, no allocation 
if (src == NULL || size < 0 || n < 1) {
    return (NULL);
}

Предполагается строка

my_strlen(src) предполагается, что src указывает на допустимую строку. calloc() не предполагает, что.

0 голосов
/ 11 января 2019

void является неполным типом, поэтому вы не можете разыменовать a void *. Однако вы можете преобразовать его в char * или unsigned char * для доступа к отдельным байтам.

Так my_calloc может сделать это:

((char *)ptr)[i] = 0;

И my_realloc может сделать это:

((char *)dst)[i] = ((char *)src)[i]; 
...