web-dev-qa-db-ja.com

Cで文字列の配列を作成する方法

Cで文字列の配列を作成しようとしています。このコードを使用すると、

char (*a[2])[14];
a[0]="blah";
a[1]="hmm";

gccは私に "警告:互換性のないポインタ型からの代入"を与えます。これを行う正しい方法は何ですか?

編集:私はprintf(a[1]);を行う場合、それは正しく "hmm"を出力するので、これはなぜコンパイラの警告を与える必要があるのか​​興味があります。

225
Charles

文字列を変更したくない場合は、単純に変更できます。

const char *a[2];
a[0] = "blah";
a[1] = "hmm";

このようにすると、2つのポインタの配列がconst charに割り当てられます。これらのポインタは静的文字列"blah""hmm"のアドレスに設定されます。

実際の文字列の内容を変更したい場合は、次のようにする必要があります。

char a[2][14];
strcpy(a[0], "blah");
strcpy(a[1], "hmm");

これにより、それぞれ14個のcharの連続した2つの配列が割り当てられ、その後静的文字列の内容がそれらにコピーされます。

204
Mikael Auno

Cで文字列の配列を作成するにはいくつかの方法があります。すべての文字列が同じ長さになる(または少なくとも同じ最大長になる)場合は、2次元のchar配列を宣言し、必要に応じて割り当てます。

char strs[NUMBER_OF_STRINGS][STRING_LENGTH+1];
...
strcpy(strs[0], aString); // where aString is either an array or pointer to char
strcpy(strs[1], "foo");

初期化子のリストも追加できます。

char strs[NUMBER_OF_STRINGS][STRING_LENGTH+1] = {"foo", "bar", "bletch", ...};

これは、イニシャライザの文字列のサイズと数が配列の次元と一致すると仮定しています。この場合、各文字列リテラルの内容(それ自体がゼロで終了するcharの配列)は、strsに割り当てられたメモリにコピーされます。このアプローチの問題点は内部断片化の可能性です。 5文字以下の99個の文字列が20文字の1個の文字列の場合、99個の文字列は少なくとも15個の未使用文字を持ちます。それはスペースの無駄です。

2次元配列のcharを使用する代わりに、1次元配列のcharへのポインタを格納できます。

char *strs[NUMBER_OF_STRINGS];

この場合、文字列へのポインタを保持するためにメモリを割り当てただけであることに注意してください。文字列自身のためのメモリは、他の場所に(静的配列として、またはmalloc()またはcalloc()を使用して)割り当てられなければなりません。前の例のように初期化子リストを使うことができます。

char *strs[NUMBER_OF_STRINGS] = {"foo", "bar", "bletch", ...};

文字列定数の内容をコピーする代わりに、単にそれらへのポインタを格納するだけです。文字列定数は書き込み可能ではないかもしれないことに注意してください。次のようにポインタを再割り当てすることができます。

strs[i] = "bar";
strs[i] = "foo"; 

しかし、文字列の内容を変更できないかもしれません。すなわち

strs[i] = "bar";
strcpy(strs[i], "foo");

許可されていない可能性があります。

Malloc()を使用して、各文字列にバッファを動的に割り当て、そのバッファにコピーすることができます。

strs[i] = malloc(strlen("foo") + 1);
strcpy(strs[i], "foo");

ところで、

char (*a[2])[14];

Aをcharの14要素の配列へのポインタの2要素の配列として宣言します。

157
John Bode

ああ!定数文字列:

const char *strings[] = {"one","two","three"};

私が正しく覚えていれば。

ああ、あなたは代入に=演算子ではなく strcpy を使いたいのです。 strcpy_s は安全ですが、C89規格でもC99規格でもありません。

char arr[MAX_NUMBER_STRINGS][MAX_STRING_SIZE]; 
strcpy(arr[0], "blah");

更新: Thomasstrlcpyが行くべき道だと言っています。

82
mpen

これがあなたの選択肢のいくつかです:

char a1[][14] = { "blah", "hmm" };
char* a2[] = { "blah", "hmm" };
char (*a3[])[] = { &"blah", &"hmm" };  // only since you brought up the syntax -

printf(a1[0]); // prints blah
printf(a2[0]); // prints blah
printf(*a3[0]); // prints blah

A2の利点は、文字列リテラルを使って次のことができることです。

a2[0] = "hmm";
a2[1] = "blah";

そしてa3のためにあなたは以下をするかもしれません:

a3[0] = &"hmm";
a3[1] = &"blah";

A1では、文字列リテラルを代入するときでもstrcpyを使わなければなりません。その理由は、a2とa3はポインタの配列であり、それらの要素(つまりポインタ)が任意の記憶領域を指すようにすることができるのに対して、a1は「文字の配列」の配列であるため各要素はその配列を「所有」する配列です。自分の記憶域(範囲外になると破壊されることを意味します) - あなたはその記憶域にものをコピーすることしかできません。

文字列以外のリテラルを割り当てたい場合は、内容が確実に変更できない(文字列リテラルが格納されている)静的記憶域を指すので(つまり、未定義の動作)、a2とa3を使用する欠点もあります。 a2またはa3の要素に - 最初に十分なメモリを動的に割り当て、次にそれらの要素にこのメモリをポイントさせ、それからその中に文字をコピーする必要があります - そしてあなたはそれが終わったらメモリの割り当てを解除する必要があります。

Bah - もうC++が恋しい

pS例が必要かどうか教えてください。

12
Faisal Vali

ANSI Cでは:

char* strings[3];
strings[0] = "foo";
strings[1] = "bar";
strings[2] = "baz";
10
Noldorin

あるいは、文字配列(1文字列)を含む構造体型を宣言することもできます。それらは構造体の配列を作成し、したがって複数要素の配列を作成します。

typedef struct name
{
   char name[100]; // 100 character array
}name;

main()
{
   name yourString[10]; // 10 strings
   printf("Enter something\n:);
   scanf("%s",yourString[0].name);
   scanf("%s",yourString[1].name);
   // maybe put a for loop and a few print ststements to simplify code
   // this is just for example 
 }

他の方法に対するこの利点の1つは、strcpyを使用しなくても文字列を直接スキャンできることです。

10
FutureSci

配列内の文字列の数を追跡したくない場合、それらを反復したい場合は、最後にNULL文字列を追加するだけです。

char *strings[]={ "one", "two", "three", NULL };

int i=0;
while(strings[i]) {
  printf("%s\n", strings[i]);
  //do something
  i++;
};
9
Sergey

文字列リテラルはconst char *sです。

括弧の使い方は変です。あなたはおそらく意味

const char *a[2] = {"blah", "hmm"};

これは、定数文字を指す2つのポインタの配列を宣言し、2つのハードコードされた文字列定数を指すようにそれらを初期化します。

8
dmckee

文字列が静的な場合は、次のようにします。

const char *my_array[] = {"eenie","meenie","miney"};

基本的なANSI Cの一部ではありませんが、環境が構文をサポートしている可能性があります。これらの文字列は不変(読み取り専用)であるため、多くの環境で文字列配列を動的に構築するよりもオーバーヘッドが少なくて済みます。

たとえば、小さなマイクロコントローラプロジェクトでは、この構文は(通常)より貴重なRAMメモリではなくプログラムメモリを使用します。 AVR-Cはこの構文をサポートする環境例ですが、他のほとんどのものもそうです。

8
Bryce

あなたのコードは関数ポインタの配列を作成しています。やってみる

char* a[size];

または

char a[size1][size2];

代わりに。

配列 および ポインタ へのウィキブックを参照してください。

3
Dario

こんにちはあなたはこのベローズを試すことができます:

 char arr[nb_of_string][max_string_length]; 
 strcpy(arr[0], "Word");

必要ならcの文字列の配列を使ったいい例

#include <stdio.h>
#include <string.h>


int main(int argc, char *argv[]){

int i, j, k;

// to set you array
//const arr[nb_of_string][max_string_length]
char array[3][100];

char temp[100];
char Word[100];

for (i = 0; i < 3; i++){
    printf("type Word %d : ",i+1);
    scanf("%s", Word);
    strcpy(array[i], Word);
}

for (k=0; k<3-1; k++){
    for (i=0; i<3-1; i++)
    {
        for (j=0; j<strlen(array[i]); j++)
        {
            // if a letter ascii code is bigger we swap values
            if (array[i][j] > array[i+1][j])
            {
                strcpy(temp, array[i+1]);
                strcpy(array[i+1], array[i]);
                strcpy(array[i], temp);

                j = 999;
            }

            // if a letter ascii code is smaller we stop
            if (array[i][j] < array[i+1][j])
            {
                    j = 999;
            }

        }
    }
}

for (i=0; i<3; i++)
{
    printf("%s\n",array[i]);
}

return 0;
}
1
Aominé

実行時の選択に応じて文字列の量を変えることができるような、動的な文字列の配列がどうしても欠けていましたが、それ以外の場合は文字列を修正する必要があります。

私はこのようなコードスニペットを作成しました。

#define INIT_STRING_ARRAY(...)          \
    {                                   \
        char* args[] = __VA_ARGS__;     \
        ev = args;                      \
        count = _countof(args);         \
    }

void InitEnumIfAny(String& key, CMFCPropertyGridProperty* item)
{
    USES_CONVERSION;
    char** ev = nullptr;
    int count = 0;

    if( key.Compare("horizontal_alignment") )
        INIT_STRING_ARRAY( { "top", "bottom" } )

    if (key.Compare("boolean"))
        INIT_STRING_ARRAY( { "yes", "no" } )

    if( ev == nullptr )
        return;

    for( int i = 0; i < count; i++)
        item->AddOption(A2T(ev[i]));

    item->AllowEdit(FALSE);
}

char** evは配列文字列へのポインタを取得し、countは_countof関数を使用して文字列の量を取得します。 (sizeof(arr) / sizeof(arr[0])と同様).

A2Tマクロを使ったUnicode変換のための追加のAnsiがありますが、それはあなたの場合のためのオプションかもしれません。

0
TarmoPikaro
char name[10][10]
int i,j,n;//here "n" is number of enteries
printf("\nEnter size of array = ");
scanf("%d",&n);
for(i=0;i<n;i++)
{
    for(j=0;j<1;j++)
    {
        printf("\nEnter name = ");
        scanf("%s",&name[i]);
    }
}
//printing the data
for(i=0;i<n;i++)
{
    for(j=0;j<1;j++)
    {
        printf("%d\t|\t%s\t|\t%s",rollno[i][j],name[i],sex[i]);
    }
    printf("\n");
}

ここでこれを試してみてください!

0
Aditya