58

この些細な問題を C で解決する方法を、最もクリーンで安全な方法で理解しようとしています。これが私の例です:

#include <stdio.h>

int main(int argc, char *argv[])
{
    typedef struct
    {
        char name[20];
        char surname[20];
        int unsigned age;
    } person;

    // Here I can pass strings as values...how does it work?
    person p = {"John", "Doe", 30};

    printf("Name: %s; Age: %d\n", p.name, p.age);

    // This works as expected...
    p.age = 25;

    //...but the same approach doesn't work with a string
    p.name = "Jane";

    printf("Name: %s; Age: %d\n", p.name, p.age);

    return 1;
}

コンパイラのエラーは次のとおりです。

main.c: 関数 'main' 内: main.c:18: エラー: 型 'char *' から型 'char[20]' に代入するときに互換性のない型です</p>

C (C++ ではない) には String 型がなく、代わりに s の配列を使用することを理解しています。そのため、これを行う別の方法は、例の構造体をs のcharポインターを保持するように変更することでした。char

#include <stdio.h>

int main(int argc, char *argv[])
{
    typedef struct
    {
        char *name;
        char *surname;
        int unsigned age;
    } person;

    person p = {"John", "Doe", 30};

    printf("Name: %s; Age: %d\n", p.name, p.age);

    p.age = 25;

    p.name = "Jane";

    printf("Name: %s; Age: %d\n", p.name, p.age);

    return 1;
}

これは期待どおりに機能しますが、これを行うより良い方法があるかどうか疑問に思います。

4

3 に答える 3

58

最初の例は、配列に値を割り当てることができないため機能しません。配列は、この点で const ポインターのように (一種の) 機能します。ただし、できることは、新しい値を配列にコピーすることです。

strcpy(p.name, "Jane");

char 配列は、文字列の最大サイズが事前にわかっている場合に問題なく使用できます。たとえば、最初の例では、名前が 19 文字に収まることが 100% 確実です (20 文字ではなく、終端のゼロを格納するために常に 1 文字が必要なため)。価値)。

逆に、文字列の可能な最大サイズがわからない場合、および/またはメモリ使用量を最適化したい場合、たとえば「John」という名前に 512 文字を予約しないようにする場合は、ポインターの方が適しています。ただし、ポインターを使用すると、ポインターが指すバッファーを動的に割り当て、不要になったときに解放して、メモリ リークを回避する必要があります。

更新:動的に割り当てられたバッファーの例 (2 番目の例で構造体定義を使用):

char* firstName = "Johnnie";
char* surname = "B. Goode";
person p;

p.name = malloc(strlen(firstName) + 1);
p.surname = malloc(strlen(surname) + 1);

p.age = 25;
strcpy(p.name, firstName);
strcpy(p.surname, surname);

printf("Name: %s; Age: %d\n",p.name,p.age);

free(p.surname);
free(p.name);
于 2010-06-28T09:41:48.297 に答える
11

文字列は抽象オブジェクト、char 配列はコンテナーと考え​​てください。文字列は任意のサイズにすることができますが、コンテナーは文字列の長さより少なくとも 1 長くする必要があります (null ターミネーターを保持するため)。

C では、文字列の構文サポートはほとんどありません。文字列演算子はありません (char-array および char-pointer 演算子のみ)。文字列を割り当てることはできません。

ただし、目的を達成するために関数を呼び出すことができます。

strncpy()関数はここで使用できます。安全性を最大限に高めるために、次のパターンに従うことをお勧めします。

strncpy(p.name, "Jane", 19);
p.name[19] = '\0'; //add null terminator just in case

strncat()および関数も参照してくださいmemcpy()

于 2010-06-28T09:45:14.293 に答える
6

2 つの構造体は異なります。最初の構造体を初期化すると、約 40 バイトのメモリが割り当てられます。2 番目の構造体を初期化すると、約 10 バイトのメモリが割り当てられます。(実際の量はアーキテクチャに依存します)

文字列リテラル (文字列定数) を使用して、文字配列を初期化できます。これが理由です

person p = {"John", "Doe",30};

最初の例で動作します。

C では (従来の意味で) 文字列を割り当てることはできません。

コードの実行時に、文字列リテラル ("John") がメモリに読み込まれます。これらのリテラルのいずれかで配列を初期化すると、文字列が新しいメモリ ロケーションにコピーされます。2 番目の例では、ポインターを文字列リテラル (の場所) にコピーしているだけです。次のようなことをします:

char* string = "Hello";
*string = 'C'

コンパイル エラーまたは実行時エラーが発生する可能性があります (よくわかりません)。たとえば、マイクロコントローラーでは、読み取り専用メモリに配置されている可能性があるリテラル文字列 "Hello" を変更しているため、これは悪い考えです。

于 2010-06-28T09:50:21.527 に答える