2016-03-25 3 views
-5

это мой первый пост, так что извините, если я делаю что-то неправильно.Как вернуть null, если моя строка не имеет нулевого терминатора

У меня есть программа на C, которая выделяет пул, а затем хранит массив символов «Hello World» в памяти и затем извлекает его. Одна из строк коды в моем основном методе читает:

store(pool, 50, sizeof(str) - 1, str); 

(мой магазин переменной методы (бассейн * бассейн, внутр смещения, размер INT, аннулируется * объект)

Если я читаю это правильно, тогда выделение пула на 1 меньше размера строки, поэтому разрезание \ 0, которое было бы на конце.

Как проверить, что символ отсутствует в конце и не принимает значение null из-за этого?

/* _POOL - pool 
* int size - the size of the pool in bytes 
* void* ipPool - pointer to memory malloc'd by the operating system 
*/ 

typedef struct _POOL 
{ 
    int size; 
    void* memory; 
} Pool; 

/* Allocate a memory pool of size n bytes from system memory (i.e., via malloc()) 
* and return a pointer to the filled data Pool structure */ 
Pool* allocatePool(int n) 
{ 
    if(n <= 0) 
    { 
      return NULL; 
    } 

    Pool *pool = malloc(sizeof *pool); 

    if(!pool) 
    { 
      return NULL; 
    } 

    pool->size = n; 

    if(!(pool->memory = malloc(n))) 
    { 
      return NULL; 
    } 

    return pool; 
}; 

/* Free a memory pool allocated through allocatePool(int) */ 
void freePool(Pool *pool) 
{ 
    if(!pool) 
    { 
      return; 
    } 

    if(pool->memory) 
    { 
      free(pool->memory); 
    } 

    free(pool); 
}; 

/* Store an arbitrary object of size n bytes at 
* location offset within the pool */ 
void store(Pool *pool, int offset, int size, void *object) 
{ 
    if(!pool) 
    { 
      return; 
    } 

    if(size + offset > pool->size) 
    { 
      return; 
    } 

    memcpy(pool + offset, object, size); 
}; 

/* Retrieve an arbitrary object of size n bytes 
* from a location offset within the pool */ 
void *retrieve(Pool *pool, int offset, int size) 
{ 
    if(!pool) 
    { 
      return NULL; 
    } 

    void *obj = malloc(size); 

    if(!obj) 
    { 
      return NULL; 
    } 

    if(size + offset > pool->size) 
    { 
      return NULL; 
    } 

    return memcpy(obj, pool + offset, size); 
}; 

void main() 
{ 
    const int poolSize = 500; 
    Pool* pool; 
    int x = 5; 
    char c = 'c'; 
    char str[] = "Hello World"; 

    /* Should retrieve Hello World */ 
    store(pool, 8, sizeof(str), str); 
    printf("Test 4: Store an arbitrary multi-byte value\n"); 
    printf("\tStored: %s\n", str); 
    printf("\tRetrieves: %s\n", (char*)retrieve(pool, 8, sizeof(str))); 

    /* Should retrieve null */ 
    store(pool, 50, sizeof(str) - 1, str); 
    printf("Test 5: Store an arbitrary multi-byte value with no null terminator\n"); 
    printf("\tStored: %s\n", str); 
    printf("\tRetrieves: %s\n", (char*)retrieve(pool, 50, sizeof(str) - 1)); 
}; 

- это весь код, который, как я думаю, задействован. В настоящее время он помещает Hello World и получает Hello World.

Я не могу редактировать ни один из основных методов, только содержимое функций и структуры.

+1

Если вы покажете исходный код, убедитесь, что это простой автономный пример. Ваш пример - это просто oneliner, вызывающий функцию, о которой мы знаем только подпись. Как вы выделили точки пула памяти? – TheBlastOne

+2

Маловероятно, что 'sizeof (str) - 1' полезен, более вероятно, что' strlen (str) + 1' –

+1

Но strlen терпит неудачу, если отсутствует нулевой символ нулевой последовательности. – TheBlastOne

ответ

3

Если вы удалили конечный нулевой символ, вы удалили единственную информацию, которая закодировала длину строки. Невозможно запросить размер выделенного блока.

Это потому, что конечный ноль является способом кодирования длины строки C. Время работы других языков использует разные методы, такие как сохранение длины строки (в виде байта или слова) в самом первом байте, на который указывает переменная привязки строк (например, Delphi).

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

И поскольку этот поиск (или сканирование) для нулевого символа является именно тем, что делает strlen, вы не можете использовать strlen, конечно.

0

Это показывает, как проверить, существует ли ограничитель строки.

В первом случае str автоматически подлежит размеру и включен в комплект поставки терминатор '\0'.

Во втором случае xyz размер массива был определен, поэтому нет места для терминатора.

#include <stdio.h> 

char *pool(char *str, size_t size) 
{ 
    size_t i; 
    for(i=0; i<size; i++) { 
     if(str[i] == '\0') { 
      return str; 
     } 
    } 
    return NULL; 
} 

int main(void) 
{ 
    char str[] = "Hello World"; 
    char xyz[11] = "Hello World"; 

    if(pool(str, sizeof str) == NULL) { 
     printf("No terminator\n"); 
    } 
    else { 
     printf("'%s' is good!\n", str); 
    } 

    if(pool(xyz, sizeof xyz) == NULL) { 
     printf("No terminator\n"); 
    } 
    else { 
     printf("'%s' is good!\n", xyz); 
    } 
    return 0; 
} 

выход программы:

'Hello World' is good! 
No terminator 
+1

@ Dylzan, в чем же смысл спрашивать? Я просто показывал отдельный пример, который проверяет терминатор 'nul'. –

+0

@WeatherVane Похоже, что 'main' - это единичный набор тестов для структуры данных, который, как ожидается, будет реализован. – TheHansinator

0

Поскольку пул памяти является бассейном свободной формы, это своего рода их собственной вина, если они взлетают возвращающийся нулевой символ.Однако, так как вы просто скопировать объект в retrieve, вы можете добавить дополнительный нулевой терминатор себе:

void *obj = malloc(size + 1); 
*((char*)(obj) + size) = 0; // add the null character 

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

+0

Извините, это должно быть разыменованием. Редактирование ответа. – TheHansinator

+0

Исправлено: это был размер бассейна. – TheHansinator

+0

На самом деле я неправильно прочитал ваш вопрос и посмотрел код для 'retrieve', и понял, что дополнительный байт должен быть добавлен туда. – TheHansinator

Смежные вопросы