この記事は、主に2次元配列の3つの側面、複数の文字列の格納方法、およびqsortの使用を補うために、LeetCodeトピック#524を実行するときにまとめられました。
#524.文字を削除して、辞書で最も長い単語と一致させる
質問タイプ
ダブルポインター
まとめ
1. 2次元配列の使用について
- 2次元配列の概念:2次元配列は、配列要素が1次元配列であることを除いて、1次元配列に似ています。実際、[0]、[1] ...は1次元配列の最初のアドレスです。2次元配列の概念を理解するには、
int a[4][3]
たとえば、2次元配列のメモリモデルを理解する必要があります。[___|___|___][___|___|___][___|___|___][___|___|___] ^ ^ ^ ^ a a+1 a+2 a+3 int ** a[0] a[1] a[2] a[3] int * a[0][0] a[1][0] a[2][0] a[3][0] int 下标与指针的关系和一维数组相同: a[1] = *(a+1) a[2] = *(a+2) ... a[1][1] = *(a[1]+1) a[1][2] = *(a[1]+2) ...
- [0]と配列要素a [0] [0]のアドレスは数値的に同じですが、同じアドレス(ポインター)タイプではないことに注意してください
- 2次元配列の
int a[3][4]
配列名:配列名では、aは最初の1次元配列へのポインター、(a + 1)は2番目の...を指し、a [0] = *(a + 0)= * aは最初の1次元配列の配列名、a [1] = *(a + 1)は2番目の1次元配列の配列名... - 整数配列へのポインタを宣言する方法は?:
int (*p)[4]
、ここで、アドレスp
をp++
増やすなどの操作中に正しいオフセットを実行できるように、ポイントする配列の要素数を指定する必要があります4*sizeof(int)
。配列へのポインタを使用して、次のような2次元配列を操作できます。
あなたは要素を一、二次元配列へのポインタずつにアクセスしたい場合は、宣言することができますint a[3][4]; int (*p)[4] = a; p++; ...
int *p = &a[0][0]
かint *p = a[0]
- 多次元配列を関数パラメーターとして使用する場合、対応する関数パラメーターを宣言するにはどうすればよいですか?:関数パラメーターとしての多次元配列名は、1次元配列と同じ方法で転送されます。実際の転送は、配列の最初の要素へのポインターです。最初に、1次元配列の配列名が関数パラメーターとして使用されている場合を見てください。
ここで、func1の関数プロトタイプは、次の2つのタイプのいずれかになります。int a[10]; ... func1( a );
2次元配列の状況を見てください。void func1( int *vec ); void func1( int vec[] );
func2の関数プロトタイプは次のように宣言できます。int b[4][10] ... func2( b );
次の文が間違っていることに注意してください:void func2( int (*mat)[10] ); void func2( int mat[][10] );
void func2( int **mat );
。2次元配列の名前はポインターへのポインターに属していますが、1次元配列の性質(要素数)を含む1次元配列のポインター(最初のアドレス)int **mat;
と、整数変数(アドレス)へのポインターを指します。 )。二次元アレイ名があればb
、関数に渡されたvoid func2( int **mat )
演算は、マットの問題を行ったときに生成される:mat++
オフセットのみアドレスsizeof(int)
アレイマットBに相当するが、[4] [1]、もしそうであればvoid func2( int (*mat)[10] );
、次にmat++
取り組みますオフセット10*sizeof(int)
。 - 文字列のセットを保存する方法は?:2つの方法があります。1つはポインターの配列を使用する方法で、宣言と初期化は次のとおりです。
またはchar *ps[] = { "just", "do", "it" };
この方法を使用すると、配列要素は個々の文字列へのポインタであり、char *ps[3] = { "just", "do", "it" };
3*sizeof(char *)
もう1つの方法は2次元配列を使用することです。宣言と初期化は次のとおりです。
この方法を使用すると、文字列の内容はすべて2次元配列に格納されます。占有スペースのサイズはですchar s[3][10] = { "just", "do", "it" };
3*10*sizeof(char)
。このメソッドは、特に文字列の長さが非常に異なる場合に多くのスペースを消費し、多くの無駄なスペースが生じます。 - sizeof(配列名)の値は何ですか?:配列名はポインターですが、sizeof(配列名)はポインターが占めるバイト数ではなく、配列全体が占めるバイト数です。たとえば、次のとおりです。
iの値は32ではなく100です(特定のポインター数によって決定されます)char s[10][10]; int i = sizeof( s );
2.
qsort でのcmp関数の定義についてqsortは、配列要素をソートするために使用されます。関数のプロトタイプはvoid qsort (void* base, size_t num, size_t size, int (*compar)(const void*,const void*));
、comparが比較関数です。qsort関数は、比較される2つの配列要素のポインタを渡し、その戻り値に従って処理します並べ替え。要素ポインタは比較関数に渡されるため、その内部実装は通常、次の形式になります。
int compareMyType (const void * a, const void * b)
{
if ( *(MyType*)a < *(MyType*)b ) return -1;
if ( *(MyType*)a == *(MyType*)b ) return 0;
if ( *(MyType*)a > *(MyType*)b ) return 1;
}
つまりvoid *
、型のポインターを配列要素のポインター型に変換し直してから、整数配列のソートなどの比較を行う必要があります。
int compar( const void *a, const void *b )
{
return ( *(int*)a - *(int*)b ); //从小到大排序
}
int a[4] = { 3, 1, 4, 5 };
qsort( a, 4, sizeof(int), compar );
別の例は、文字列配列の比較です。
int compar( const void *a, const void *b )
{
//注意,由于比较的是二维数组的元素,因此qsort传递给
//compar的是数组元素的指针,也就是各一维数组的指针,
//其类型和二维数组名相同,为指向字符数组的指针,其
//声明方式为:char (*p)[5],因此类型转换为(char (*)[5]),
//由于strcmp需要的是字符串的指针,因此需要解引用。
//强制转换后a的类型为指向字符数组的指针,因此解引用
//后类型为字符数组的数组名(首地址),也是字符串指针
//,于是就可以给strcmp使用了。
return strcmp( *(char (*)[5])a, *(char (*)[5])b );
}
char a[3][5] = { "go", "to", "do" };
qsort( a, 3, 5*sizeof(char), compar );
別の例は、文字ポインター(文字列リテラル)の配列の並べ替えです。
int compar( const void *a, const void *b )
{
//由于数组元素为字符指针类型,传递给
//compar的是字符指针的指针(地址),
//因此应先转换回类型char **
return strcmp( *(char **)a, *(char **)b );
}
char *a[3] = { "go", "to", "do" };
qsort( a, 3, sizeof(char *), compar );