web-dev-qa-db-ja.com

CでCharポインターの配列を作成できますか?

私はCを使い始めたばかりですが、Cで学んだ他の言語とは状況が異なります。私の宿題では、charの配列を指すcharの配列を作成したいのですが、多次元のchar配列を作成するのではなく、より詳細に制御してchar配列を作成し、個々の配列をそれぞれのインデックスに入れます元の文字配列:

char keywords[10];
keywords[0] = "float";

上記の例は、単純なケースを明確にするためのものです。しかし、私の質問は私がこれまで行ってきた研究によるものであり、私は何かについて混乱しています。通常、これは他の言語でも機能しますが、Cでは次のようになります。

char *keyword[10];
keywords[0] = "float";

しかし、関数を通じて送信したいのに、なぜこれが必要なのですか。

void function(char **keyword); //function prototype

配列ポインタを渡すだけで十分ではないでしょうか?

12
Andy

二重星に混乱しているようです

void function(char ** keyword);

二重の星は、単にこの関数では、charへのポインターへのポインターを渡すことを想定しているを意味します。この構文には、配列を使用しているという事実、または文字が文字列の多くの最初の文字であるという情報は含まれていません。このchar **が実際にどのようなデータ構造を指しているかを知るのは、プログラマとしてのあなた次第です。

たとえば、配列の先頭がアドレス0x1000に格納されているとします。関数のkeyword引数の値は0x1000にする必要があります。 keywordを逆参照すると、配列内の最初のエントリが取得されます。これは、文字列 "float"の最初の文字を指すchar *です。 char *を逆参照すると、char "f"が返されます。

そのための(考案された)コードは次のようになります。

void function(char **keyword)
{
    char * first_string = *keyword;   // *keyword is equivalent to keyword[0]
    char first_char = *first_string;  // *first_string is equivalent to first_string[0]
}

上記の例には2つのポインターがありました。逆参照する前に最初のポインターにオフセットを追加することにより、配列内のさまざまな文字列にアクセスできます。逆参照する前に2番目のポインターにオフセットを追加すると、文字列内の別の文字にアクセスできます。

12
David Grayson
char *keyword[10];

keywordchar *の配列10です。値のコンテキストでは、char *へのポインターに変換されます。

この変換は、Chris Torekが呼ぶものの一部です "The Rule"

「他の場所で述べたように、Cには配列とポインターに関する非常に重要なルールがあります。このルール-ルール-は、値のコンテキストでは、タイプTの配列のオブジェクトがタイプTのポインターの値になることを述べています'、その配列の最初の要素を指している "

詳細については、こちらをご覧ください: http://web.torek.net/torek/c/pa.html

C-FAQにも、この配列からポインタへの変換に関するエントリがあります。

質問6.3:では、Cの「ポインタと配列の同等性」とはどういう意味ですか?

http://c-faq.com/aryptr/aryptrequiv.html

2
ouah

これが答えです。

#include<stdio.h>

int main(void)
{
        char *CharPtr[3];
        char a[4]="abc";
        char b[4]="def";
        char c[4]="ghi";
        CharPtr[0]=a;
        CharPtr[1]=b;
        CharPtr[2]=c;

        printf("\n content of CharPtr[0] =%s",CharPtr[0]);
        printf("\n content of CharPtr[1] =%s",CharPtr[1]);
        printf("\n content of CharPtr[2] =%s\n",CharPtr[2]);

        printf(" \n content of char a[4]=%s",a);
        printf(" \n content of char b[4]=%s",b);
        printf(" \n content of char c[4]=%s\n",c);
}
1
user3824337

あなたがしたい場合は

void function(char **keyword);

アンディ、配列は単なる(配列の先頭への)ポインタであると考えてください。そのため、次のように記述します。

void function(char **keyword);

Charポインタへの配列を作成したからです。

理解しやすい場合は、以下を試してください。

void function(char *keyword[]);

ただし、C++コンパイラを使用するかどうかは問題ではありませんが、最初のものを使用する方がC標準です。

1
Mario Corchero

私はあなたがあなたの最初の文字列を割り当てていると仮定しています:

"float"

キーワードの最初のインデックス位置に[0]

char keyword[0] = "float";

これは、配列の最初のインデックス位置です。

char keyword[10];

前者が当てはまる場合、ある意味では、本質的に、データ構造を保持するデータ構造を作成しています。任意の型の配列は、Cでのその型の「最小」のデータ構造です。この例では文字配列を作成していることを考えると、実際には、各インデックス位置で最小のデータ型(char = 1bit)を使用しています。最小の組み込みデータ構造(配列)。

そうは言っても、例の場合、配列の配列を作成しようとしています。あなたのキャラクター配列

/* Hold ten characters total */
char keyword[10];  

10文字を保持するように設計されています。各インデックス位置に1つ(おそらくすでに知っています)。したがって、keywordというタイトルの配列を宣言した後、配列の最初のインデックス位置を別の(2番目の)文字配列で初期化しようとします。

/* I believe this is what you had stated */
char keywords[0] = "float";

5番目のサイズのインデックスを持つ2番目の文字配列。

希望する目標を達成するには、基本的に、他のデータ構造を「保持」するデータ構造の効果を基本的にエミュレートする配列を作成することになります。

注:データ構造を保持するデータ構造を保持するデータ構造を作成しようと計画していた場合。 A.K.A.トリプルネストされたデータ構造、そしてこの場合、私はそれがマトリックスになるだろうと思います、私はお勧めしません!

それでもなお、マトリックス構造は、キーワードの最初のインデックス位置の形式であり、キーワードの配列全体が割り当てられます。これには、キーワード配列の各インデックス位置に格納されているすべてのデータが含まれます。次に、おそらく次のようなものがあります:keywords1、keywords2、...、keywords9、

これは基本的に次の形式をエミュレートします。

char *keyword[10] = { 
                        char *keywords0[10] = {"float", etc, etc, etc.};
                        char *keywords1[10] = {"keyword1", "secondIndexOfThisArray", etc, etc, etc.}; 
                       and so

                   };

したがって、基本的に右から左に、キーワード配列は、文字配列を指すポインターの配列を指すポインターの配列です。

それがあなたが表現しているものである場合は、構造体/レコードのカスタムデータ型をより適切に定義し、そのカスタム構造で構造の下位または子レベルを定義する必要があります。それらを事前に宣言してから初期化することもできます。

例えば.

typedef *nestedDataStructures {

    struct keyWords[];
    struct keyWords1[];
    struct keyWords2[];

    ... and so on.
}; nestedDataStructures

1つのカスタム構造体に10の構造体を追加する代わりに、3または4(どのように多くの構造体と使用)に分解し、データセットを操作するときに対称の抽象レイヤーを生成するためにモジュールを作成します。

それでもなお、文字配列を作成することはできず、他の文字配列をあなたが行った方法(または多分あなたができることを知っている)で割り当てることができますが、配列を保持する配列をエミュレートしたい方法は、 X番号のインデックス位置の文字ポインタ配列を初期化し、初期化してから、元の宣言の初期化で宣言された文字列の形式の文字配列を使用します。

したがって、基本的には配列全体を事前に宣言し、プログラム設計で、各インデックス位置を逆参照するか、割り当てを使用するか、インデックス位置を出力/書き込みすることができます。

例えば、あなたはいつもこのようなことをすることができます:

/* Example of the program and declaration with out a function */
#include <stdio.h>

int main(){

    /* 
     * A character pointer array that contains multiple 
     * character arrays.
     */

    char *grewMe[2] = {"I want to ", "grow to be bigger"};

    int w = 0;

    for(; w < 2;) {
        printf("%s", grewMe[w]);
        ++w;
    }

    printf(" :-)\n");
    w = 0;
    return 0;
}
// Output:
// I want to grow to be bigger :-)

またはこのようなもの:

/* Example of program: function passed arguments 
 * of a pointer to the array of pointers 
 */
#include <stdio.h>

void mygrowth(char *growMe[]);

int main(){

    char *growMe[2] = {"I want to ", "grow to be bigger"};

    mygrowth(growMe);  
    printf(" :-)\n");

    return 0;

}
void mygrowth(char *growMe[])
{

    int w = 0;
    for (; w < 2;) {
        printf("%s", growMe[w]);
        ++w;
    } 
}

引数として渡される各インデックス位置の割り当て:

/* 
 * This program compiles, runs and outputs properly
 * Example of a program with a function of 
 * arguments pnt2pnter 
 */

#include <stdio.h>
#include <stdlib.h>

void thoughtAsAFunction(char **iThink);

int main()
{

    char *iThink[10] = {"I am trying to grow, but it's a hard task to ",
                        "accomplish. My father is short ", 
                        "my mother is even shorter than him, ", 
                        "what is the probability of me getting taller? ", 
                        "Well both my grandfather's were Six ",
                        "Foot Five, and both my grandmother's ", 
                        "were over 5 foot 8 inches tall! If my ",  
                        "grandparent's genes point to my parents, and my ", 
                        "parent's genes point to mine I might have a chance ",
                        "of being 6 foot. Do you know what I mean? "};

    thoughtAsAFunction(iThink);

    printf(":-)\n");

    return 0;
}
void thoughtAsAFunction(char **iThink) {

    int andy = 0;
    for (; andy < 10;) {
        char * pntThroughPnt = iThink[andy];
        printf("%s", pntThroughPnt);
        ++andy;
    }
    andy = 0;
}

または、ループカウント変数の増分を使用して、参照渡しします。

/*
 * This program compiles, runs, and outputs all of the character
 * arrays. 
 * 
 */
#include <stdio.h>
#include <stdlib.h>

void thoughtAsAFunction(char **iThink);

int main()
{

    char *iThink[10] = {"I am trying to grow, but it's a hard task to ",
                        "accomplish. My father is short ", 
                        "my mother is even shorter than him, ", 
                        "what is the probability of me getting taller? ", 
                        "Well both my grandfather's were Six ",
                        "Foot Five, and both my grandmother's ", 
                        "were over 5 foot 8 inches tall! If my ",  
                        "grandparent's genes point to my parents, and my ", 
                        "parent's genes point to mine, then I might have a chance ",
                        "of being 6 foot. Do you know what I mean? "};

    int andy = 0;
    for (; andy < 10;) {
        // pass by reference and increment.
        thoughtAsAFunction(&iThink[andy]);
        ++andy;

    }

    printf(":-)\n");
    andy = 0;

    return 0;
}
void thoughtAsAFunction(char **iThink) {

    char * pntThroughPnt = *iThink;
    printf("%s", pntThroughPnt);

}

これは、ポインターの配列(char * array [10];)を宣言し、各ポインターが文字の配列を指す場合に当てはまることに注意してください。

0
oOpSgEo

char *keywords[10]は、文字ポインターの配列です。したがって、keywords[0]keywords[1] ..などは、異なる文字配列へのアドレスを持ちます。

printfでは、%skeywords[0]を使用して、アドレス(配列の最初のバイトのアドレス)がkeywords[0]に格納されている文字配列全体を出力できます。

関数に渡すときに、*keywordsを指定すると、アドレスであるvalue at(address stored at keywords[0]を参照していることになります。したがって、アドレスの代わりに値を取得するには、別の*...を追加できます。これで少しわかりやすくなります。

0
Vikas

Cでは、配列を実際に関数に渡すことはできません。代わりに、配列の先頭にポインターを渡します。 char*の配列があるため、関数はchar*へのポインターを取得します。これはchar**です。

必要に応じて、char *keyword[]の代わりにchar **keywordを(プロトタイプに)書き込むことができます。コンパイラーが自動的に変換します。

また、Cでは配列のようにポインターを逆参照することができるため、「ポインターへの変換」ではほとんど何も失われません。

0
asaelr