私はC言語に不慣れで、次の演習で誤解があります。
void printAllStrings(const char** arr[])
{
while(*arr!=NULL)
{
char** ptr=(char**)*arr;
while(*ptr!=NULL)
{
printf("%s\n",*ptr);
ptr++;
}
arr++;
}
}
int main()
{
char* arrP1[]={"father","mother",NULL};
char* arrP2[]={"sister","brother","grandfather",NULL};
char* arrP3[]={"grandmother",NULL};
char* arrP4[]={"uncle","aunt",NULL};
char** arrPP[]={arrP1,arrP2,arrP3,arrP4,NULL};
printf("Before sort :\n");
printAllStrings(arrPP);
sort(arrPP);
printf("\nAfter sort :\n");
printAllStrings(arrPP);
printf("\nMaximum length string : %s \n",maxLengthString(arrPP));
return 0;
}
上記のコードはすべての文字列を出力します。
私の質問は:
でprintAllStrings
機能渡されたパラメータ(char** arr[]
文字列の)配列、我々はポインタにポインタを渡すことができます- char** arr
。
この行の意味は何ですかchar** ptr=(char**)*arr
。私は、char型へのポインタのこのキャストを理解しています。しかし、なぜポインターをキャストする必要があるのは、すでにchar型を指しているのでしょうか。
- printAllStrings関数で、渡された
(char** arr[])
文字列のパラメータ配列で、ポインタをポインタに渡すことができます-char** arr[]
。
上記の例ではchar** arr[]
、とchar** arr[]
(2つは同じ)があるので、「合格できますか?」質問は不明です。パラメータを(char ***arr)
に変更できるかどうかを尋ねている場合は、そうです。間接参照の最初のレベル(たとえば[ ]
)がポインタに変換されるためです。
- この行の意味は何ですか
char** ptr=(char**)*arr
。私は、char型へのポインタのこのキャストを理解しています。しかし、なぜポインターをキャストする必要があるのは、すでにchar型を指しているのでしょうか。
その理由は、あなたのパラメータがありconst char** arr[]
、その後、あなたが宣言しchar** ptr
た破棄const
修飾子のをarr
。const char **
とchar **
同じではありません。したがってptr
、逆参照されたarr
((char** ptr=arr;
)など)で初期化しようとすると、コンパイラはconst
修飾子の破棄について文句を言います。
問題を正しく修正するのではなく、たとえば
const char **ptr = *arr;
初期化を「ファッジ」して、const
修飾子を強制的に破棄します。その結果ptr
、const
型が保持されなくなり、ptr
定数以外の方法で使用しようとしたときにコンパイラーが警告を発するのを防ぐことができます(const
修飾子を捨てるだけで本当に悪いことが起こります))
私は間違っているかもしれませんが、割り当てのポイントは、ポインタの配列を初期化するために使用する文字列リテラルのconst
性質を保持することであるように見えます。したがって、配列を次のように宣言するのではなく、次のようにします。
char* arrP1[]={"father","mother",NULL};
それらconst
をcharへのポインタの配列として宣言する必要があります。
const char *arrP1[]={"father","mother",NULL};
その場合のパラメータprintAllStrings
は理にかなっており、文字列リテラルの変更など、許可されていないことを実行しようとすると、コンパイラは警告を表示します。
arrP1[0][0] = 'l';
(コンパイラはスローしますerror: assignment of read-only location ‘*arrP1[0]
)
コード全体で型を一貫して運ぶ場合は、キャストをどこにでも「ファッジ」する必要はなく、コンパイラーは自分自身からユーザーを保護するのに役立ちます。たとえば、文字列リテラルがconst
修飾されていることを確認するための型の単純な作り直し(配列の並べ替えは可能ですが)は、次のような方法で実行できます。
#include <stdio.h>
#include <string.h>
void printAllStrings (const char **arr[])
{
while (*arr != NULL) {
const char **ptr = *arr;
while (*ptr != NULL) {
printf ("%s\n", *ptr);
ptr++;
}
arr++;
}
}
const char *maxLengthString (const char **arr[])
{
size_t max = 0;
const char *longest = NULL;
while (*arr != NULL) {
const char **ptr = *arr;
while (*ptr != NULL) {
size_t len = strlen (*ptr);
if (len > max) {
max = len;
longest = *ptr;
}
ptr++;
}
arr++;
}
return longest;
}
int main (void) {
const char *arrP1[] = {"father", "mother", NULL};
const char *arrP2[] = {"sister", "brother", "grandfather", NULL};
const char *arrP3[] = {"grandmother", NULL};
const char *arrP4[] = {"uncle", "aunt", NULL};
const char **arrPP[] = {arrP1, arrP2, arrP3, arrP4, NULL};
printf ("Before sort :\n");
printAllStrings (arrPP);
// sort (arrPP); /* you didn't post sort, so the following swaps */
const char **tmp = arrPP[0]; /* simple swap example */
arrPP[0] = arrPP[1];
arrPP[1] = tmp;
printf ("\nAfter sort :\n");
printAllStrings (arrPP);
printf ("\nMaximum length string : %s \n", maxLengthString (arrPP));
return 0;
}
(投稿しなかったsort()
ので、要素の上に単にスワップしてarrPP
ソートする機能を保持していることを示しmaxLengthString ()
、最後のステートメントを機能させるためにのクイック実装が追加されました-ただし、最初のステートメントが見つかるだけです。複数の文字列が同じ長さの場合は最長の文字列)
使用例/出力
$ ./bin/array_ptp_const_char
Before sort :
father
mother
sister
brother
grandfather
grandmother
uncle
aunt
After sort :
sister
brother
grandfather
father
mother
grandmother
uncle
aunt
Maximum length string : grandfather
物事を見て、さらに質問があれば私に知らせてください。これがあなたが探していたものであるかどうかはわかりませんが、あなたのコードと質問に基づいて、それは最も論理的な選択のように思われました。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加