如果我的字符串没有空终止符,如何返回null

时间:2016-03-25 20:19:29

标签: c

这是我第一次在这里发帖,很抱歉,如果我做错了什么。

我有一个C程序,它分配一个池,然后在内存中存储一​​个char数组" Hello World"然后检索它。我的main方法中的代码行之一是:

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

(我的商店方法变量是(Pool * pool,int offset,int size,void * object)

如果我正确读取这个,那么正在分配的池比字符串大小小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。

我无法编辑任何主要方法,只能编辑函数和结构的内容。

3 个答案:

答案 0 :(得分:3)

如果删除了尾随空字符,则会删除编码字符串长度的唯一信息。 无法查询已分配的块的大小。

这是因为终止零是C编码字符串长度的方式。其他语言的运行时使用不同的方法,比如将字符串长度(作为字节或单词)存储在字符串引用变量(例如Delphi)指向的第一个字节中。

因此无法检测是否缺少尾随空值。如果存在,则可以搜索它。如果不存在,您的搜索将不可避免地访问字符串的最后一个字节后面的内存位置,并且无法正常工作。

因为这个空字符的搜索(或扫描)正是strlen正在做的事情,所以当然不能使用strlen

答案 1 :(得分: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

答案 2 :(得分:0)

由于内存池是一个自由形式的池,如果它们取消返回的null字符,那就是它们自己的错误。但是,由于您只是在retrieve中复制对象,因此您可以自己添加一个额外的空终止符:

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

有了这个,即使你的最终用户决定取消一个空终止符,最终会出现一个,它通常会出现在正确的位置,因此永远不会导致无法存在的遍历错误,否则如果没有null终止符。