2016-03-25 10 views
-5

これは私が初めて間違いをしていると申し訳ありません。文字列にヌルターミネーターがない場合はどうすればnullを返しますか

私はプールを割り当て、メモリに "Hello World"という文字配列を格納してからそれを取得するCプログラムを持っています。私のメインメソッドのコードの行の一つは、読み取ります

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

(私の店のメソッド変数は、(プール*プールされている私はこれを読んでいる場合はオフセット、int型のサイズ、void *型のオブジェクト)

をint型正しく割り当てられると、割り当てられるプールは文字列サイズよりも1小さいので、末尾にある\ 0を切り捨てます。

文字が最後になくなっていないことを確認してヌルを返します。

/* _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など)が指す最初のバイトにストリング長(バイトまたはワードとして)を格納するなど、さまざまな方法を使用します。

したがって、末尾のNULLがないかどうかを検出する方法はありません。ある場合は、それを検索することができます。それがなければ、の検索では、文字列の最後のバイトの後ろのメモリ位置に必然的にアクセスし、正常に動作しなくなります。

ヌル文字の検索(またはスキャン)が正確に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 

を所定の位置に、エンドユーザーがヌルターミネータを脱ぐことを決定した場合でも、1は最終的になります通常は正しい場所に表示され、ヌルターミネータがない場合には終わりのないトラバーサルエラーが発生することはありません。

+0

申し訳ありませんが、逆参照である必要があります。答えを編集する。 – TheHansinator

+0

プールのサイズが必要でした。 – TheHansinator

+0

実際に私はあなたの質問を誤読し、 'retrieve'のコードを見て、余分なバイトが実際そこに追加されるべきであることに気付きました。 – TheHansinator

関連する問題