Cで文字列の配列を作成しようとしています。このコードを使用すると、
char (*a[2])[14];
a[0]="blah";
a[1]="hmm";
gccは私に "警告:互換性のないポインタ型からの代入"を与えます。これを行う正しい方法は何ですか?
編集:私はprintf(a[1]);
を行う場合、それは正しく "hmm"を出力するので、これはなぜコンパイラの警告を与える必要があるのか興味があります。
文字列を変更したくない場合は、単純に変更できます。
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つの配列が割り当てられ、その後静的文字列の内容がそれらにコピーされます。
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要素の配列として宣言します。
これがあなたの選択肢のいくつかです:
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例が必要かどうか教えてください。
ANSI Cでは:
char* strings[3];
strings[0] = "foo";
strings[1] = "bar";
strings[2] = "baz";
あるいは、文字配列(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
を使用しなくても文字列を直接スキャンできることです。
配列内の文字列の数を追跡したくない場合、それらを反復したい場合は、最後にNULL文字列を追加するだけです。
char *strings[]={ "one", "two", "three", NULL };
int i=0;
while(strings[i]) {
printf("%s\n", strings[i]);
//do something
i++;
};
文字列リテラルはconst char *
sです。
括弧の使い方は変です。あなたはおそらく意味
const char *a[2] = {"blah", "hmm"};
これは、定数文字を指す2つのポインタの配列を宣言し、2つのハードコードされた文字列定数を指すようにそれらを初期化します。
文字列が静的な場合は、次のようにします。
const char *my_array[] = {"eenie","meenie","miney"};
基本的なANSI Cの一部ではありませんが、環境が構文をサポートしている可能性があります。これらの文字列は不変(読み取り専用)であるため、多くの環境で文字列配列を動的に構築するよりもオーバーヘッドが少なくて済みます。
たとえば、小さなマイクロコントローラプロジェクトでは、この構文は(通常)より貴重なRAMメモリではなくプログラムメモリを使用します。 AVR-Cはこの構文をサポートする環境例ですが、他のほとんどのものもそうです。
こんにちはあなたはこのベローズを試すことができます:
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;
}
実行時の選択に応じて文字列の量を変えることができるような、動的な文字列の配列がどうしても欠けていましたが、それ以外の場合は文字列を修正する必要があります。
私はこのようなコードスニペットを作成しました。
#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がありますが、それはあなたの場合のためのオプションかもしれません。
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");
}
ここでこれを試してみてください!