ポインタの簡単な入門 (5) sizeof と strlen の高度な理解

シリーズ記事の目次



序文

目的: sizeof と strlen および 2 次元配列の関連するポインター形式の詳細な研究

1.sizeofとstrlenの比較

1.1 サイズ

演算子を学習するときに、sizeof について学習しました。sizeof は、変数が占めるメモリ領域のサイズを計算します。単位はバイトです。オペランドが型の場合、 計算された値は次のようになります。型を使用して作成された変数が占めるメモリ空間のサイズ。 sizeof は、占有されるメモリ空間のサイズのみに注意を払い、メモリに格納されているデータには注意しません。
例:

sizeof は関数ではなく、演算子です

#inculde <stdio.h>
int main()
{
    
    
 	int a = 10;
 	printf("%d\n", sizeof(a));
 	printf("%d\n", sizeof a);//也可以这样
 	printf("%d\n", sizeof(int));
 	return 0;
}

出力結果はすべて同じで、どちらも 4 です。

1.2 スレン

strlen は、文字列の長さを検出する機能を持つ C 言語ライブラリ関数です。関数のプロトタイプは次のとおりです。

	size_t strlen ( const char * str );

統計は、strlen 関数のパラメータ str のアドレスから始まり、\0 まで遡る文字列の文字数です。 strlen 関数は、\0 文字が見つかるまで検索を続けるため、範囲外の検索が発生する可能性があります。

#include <stdio.h>
int main()
{
    
    
 	char arr1[3] = {
    
    'a', 'b', 'c'};
 	char arr2[] = "abc";
 	printf("%d\n", strlen(arr1));//1
	printf("%d\n", strlen(arr2));//2
 	printf("%d\n", sizeof(arr1));//3
 	printf("%d\n", sizeof(arr1));//4
 return 0;
}

コード 1: ランダムな値、\0 はありません; コード 2: 結果は 3 です
コード 3: 結果は 3 です コード 4: 結果は 4

1.3 sizeof と strlen の比較

(1)サイズ

  1. sizeof は演算子です。
  2. sizeof は、オペランドが占有するメモリのサイズをバイト単位で計算します。
  3. は、メモリにどのようなデータが保存されているかには注意しません。
    (2) ストラレン
    ストラレン
  4. strlen はライブラリ関数であり、これを使用するにはヘッダー ファイル string.h が必要です。
  5. srtlen は、\0 より前の文字数を数えて、文字列の長さを見つけるために使用されます。
  6. メモリ内に \0 があるかどうかに注意し、 \0 がない場合は後方検索を続け、境界を越える可能性があります。

2. 配列とポインタの記述式試験問題の分析

以下のすべての質問は次のことに基づいています。

• sizeof (配列名)。配列名を sizeof に個別に入力します。ここでの配列名は配列全体を表し、計算は配列全体のサイズになります。
単位はバイトです。
• &配列名。ここでの配列名は配列全体を表し、配列全体のアドレスが取り出されます (配列全体のアドレスと配列の最初の要素)。配列
アドレスは異なります)
さらに、配列名が使用される場合は常に、配列名は最初の要素のアドレスを表します。

2.1 1次元配列

占有バイト数を書き込む

	int a[] = {
    
    1,2,3,4};
	printf("%d\n",sizeof(a));//单单数组名,是整个数组,16
	printf("%d\n",sizeof(a+0));//首元素地址加0,为地址4/8个字节
	printf("%d\n",sizeof(*a));//为首元素内容,4
	printf("%d\n",sizeof(a+1));//首元素地址加1,为第2个元素地址 ,4/8
	printf("%d\n",sizeof(a[1]));//4
	printf("%d\n",sizeof(&a));//地址 4/8
	printf("%d\n",sizeof(*&a));//所有元素地址,解引用为所有元素内容,4*4=16
	printf("%d\n",sizeof(&a+1));//地址,4/8
	printf("%d\n",sizeof(&a[0]));//地址4/8
	printf("%d\n",sizeof(&a[0]+1));//首元素地址加1,第2个元素地址,4/8

2.2 文字配列

コード 1:

	char arr[] = {
    
    'a','b','c','d','e','f'};
	printf("%d\n", sizeof(arr));//计算的是整个数组大小,6个字节
	printf("%d\n", sizeof(arr+0));//arr+0是数组第一个元素的地址4/8
	printf("%d\n", sizeof(*arr));//*arr是首元素,1
	printf("%d\n", sizeof(arr[1]));//1
	printf("%d\n", sizeof(&arr));//整个数组地址,还是地址4/8
	printf("%d\n", sizeof(&arr+1));//4/8
	printf("%d\n", sizeof(&arr[0]+1));//4/8

コード 2:

char arr[] = {
    
    'a','b','c','d','e','f'};
	printf("%d\n", strlen(arr));//随机值,因为没有\0
	printf("%d\n", strlen(arr+0));//随机值
	printf("%d\n", strlen(*arr));//err(错误)'b'没有\0
	printf("%d\n", strlen(arr[1]));//err
	printf("%d\n", strlen(&arr));//随机值
	printf("%d\n", strlen(&arr+1));//随机值
	printf("%d\n", strlen(&arr[0]+1));//随机值

コード 3:

	char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));//7
	printf("%d\n", sizeof(arr+0));//arr+0是数组首元素的地址,地址的大小4/8
	printf("%d\n", sizeof(*arr));//*arr是数组首元素地址,1
	printf("%d\n", sizeof(arr[1]));//1
	printf("%d\n", sizeof(&arr));//整个数组地址,数组地址也是地址4/8
	printf("%d\n", sizeof(&arr+1));//&arr+1跳过整个数组,指向了数组的后,4/8
	printf("%d\n", sizeof(&arr[0]+1));//&arr[0]+1是第2个元素地址4/8

コード 4:
ここに重要な内容があります

	char arr[] = "abcdef";
	printf("%d\n", strlen(arr));//6
	printf("%d\n", strlen(arr+0));//arr+0是首元素地址,6
	printf("%d\n", strlen(*arr));//err(错误)
	printf("%d\n", strlen(arr[1]));//err'b'没有\0
	printf("%d\n", strlen(&arr));//————&arr虽然是数组地址,但是也是指向数组起始位置
	printf("%d\n", strlen(&arr+1));//随机值
	printf("%d\n", strlen(&arr[0]+1));//&arr+1是第2个元素的地址

strlenの計算内容がアドレスの場合、計算されるのはアドレスの内容です。

コード5:

	char *p = "abcdef";
	printf("%d\n", sizeof(p));//p是指针变量,是地址4/8
	printf("%d\n", sizeof(p+1));//p+1是'b' 的地址,4/8
	printf("%d\n", sizeof(*p));//*p计算'a'大小1个字节
	printf("%d\n", sizeof(p[0]));//p[0] = *(p+0) 1个字节
	printf("%d\n", sizeof(&p));//&p是地址,这里相当于2级指针4/8
	printf("%d\n", sizeof(&p+1));//&p+1是指向p指针变量后面的空间,也是地址,是4/8字节
	printf("%d\n", sizeof(&p[0]+1));//&p[0]+1是'b'的地址,是地址就是4/8个字节

コード6:

	char *p = "abcdef";
	printf("%d\n", strlen(p));//6
	printf("%d\n", strlen(p+1));//跳过1个字节,计算后面的为5
	printf("%d\n", strlen(*p));//err
	printf("%d\n", strlen(p[0]));//err一个字节
	printf("%d\n", strlen(&p));//随机值
	printf("%d\n", strlen(&p+1));//随机值
	printf("%d\n", strlen(&p[0]+1));//5

2.3 2次元配列

	int a[3][4] = {
    
    0};
	printf("%d\n",sizeof(a));//4*12=48
	printf("%d\n",sizeof(a[0][0]));//4
	printf("%d\n",sizeof(a[0]));//a[0]是第一行这个一维数组的数组名,数组名单独放在sizeof了,计算的是第一行大小,单位是字节,16
	printf("%d\n",sizeof(a[0]+1));//a[]第一行这个一维数组的数组名,这里表示数组首元素,也就是a[0][0]的地址,a[0] + 1是a[0][1]的地址
	printf("%d\n",sizeof(*(a[0]+1));//a[0][1] - 4个字节
	printf("%d\n",sizeof(a+1));//a是二维数组的数组名,但是没有&,也没有单独放在sizeof内部,所以这里的a是数组收元素的地址,应该是第一行的地址,a+1是第二行的地址
	printf("%d\n",sizeof(*(a+1)));//*(a + 1) ==> a[1] - 第二行的数组名,单独放在sizeof内部,计算的是第二行的大小,为16
	printf("%d\n",sizeof(&a[0]+1));//&a[0]是第一行的地址,&a[0]+1就是第二行的地址,4/8
	printf("%d\n",sizeof(*(&a[0]+1)));//访问的是第二行,计算的是第二行的大小,16个字节,相当于放在int(*p)[4] = &a[o] + 1;
	printf("%d\n",sizeof(*a));//这里的a是第一行的地址,*a就是第一行,sizeof(*a)计算的是第一行的大小-16
	printf("%d\n",sizeof(a[3]));//这里不存在越界,因为sizeof内部的表达式不会真实计算的,计算的是第四行的类型大小-16

配列名の意味:

  1. sizeof (配列名)、ここでの配列名は配列全体を表し、配列全体のサイズが計算されます。
  2. &配列名。ここでの配列名は配列全体を表し、配列全体のアドレスが取得されます。
  3. さらに、すべての配列名は最初の要素のアドレスを表します。

3. ポインタ演算に関する筆記試験問題の分析

3.1 質問 1:

#include <stdio.h>
int main()
{
    
    
 	int a[5] = {
    
     1, 2, 3, 4, 5 };
 	int *ptr = (int *)(&a + 1);
 	printf( "%d,%d", *(a + 1), *(ptr - 1));
 return 0;
}
//程序的结果是什么?

ここに画像の説明を挿入します
*(ptr-1) 分析:
ここに画像の説明を挿入します

3.2 質問 2

ポインタ + 整数

//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结构是啥?
struct Test
{
    
    
 	int Num;
 	char *pcName;
 	short sDate;
 	char cha[2];
 	short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{
    
    
 	printf("%p\n", p + 0x1);//0x100000+20 == x100014
 	printf("%p\n", (unsigned long)p + 0x1);//0x100000+1 == 0x100001
 	printf("%p\n", (unsigned int*)p + 0x1);//0x100000+1 == 0x100004
 	return 0;
}

結果:
ここに画像の説明を挿入します
は 16 進数で出力することもできます:

struct Test
{
    
    
 	int Num;
 	char *pcName;
 	short sDate;
 	char cha[2];
 	short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{
    
    
 	printf("%#x\n", p + 0x1);//0x100000+20 == x100014
 	printf("%#x\n", (unsigned long)p + 0x1);//0x100000+1 == 0x100001
 	printf("%#x\n", (unsigned int*)p + 0x1);//0x100000+1 == 0x100004
 	return 0;
}

#この関数は Ox プレフィックスを出力します

結果:
ここに画像の説明を挿入します

3.3 質問 3

焦点を当てる

#include <stdio.h>
int main()
{
    
    
 	int a[3][2] = {
    
     (0, 1), (2, 3), (4, 5) };//这里是(),是逗号表达式,不是{},逗号表达式结果是运算到最右边的结果
 	//int a[3][2] = { 1, 3, 5 };
 	int *p;
 	p = a[0];
 	printf( "%d", p[0]);
 	return 0;
}

分析:
ここに画像の説明を挿入します
出力結果:
ここに画像の説明を挿入します
なぜ 1 なのでしょうか? 実際には、a[0] (配列の最初の行) が与えられます。 p. は、最初の行の最初の要素のアドレスです。

3.4 質問 4

//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{
    
    
 	int a[5][5];
 	int(*p)[4];
 	p = a;
 	printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//-4,-4(元素个数)
 	return 0;
}

分析:
ここに画像の説明を挿入します
ここに画像の説明を挿入します
输出结果:
ここに画像の説明を挿入します

3.5 質問 5

#include <stdio.h>
int main()
{
    
    
 	int aa[2][5] = {
    
     1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 	int *ptr1 = (int *)(&aa + 1);//跳过一个数组
 	int *ptr2 = (int *)(*(aa + 1));//相当于a[1],第2行,ptr得到的是第2行首元素地址
 	printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
	return 0;
}

この種の質問には絵を描くのが最適です

ここに画像の説明を挿入します

出力結果:
ここに画像の説明を挿入します

3.6 質問6

#include <stdio.h>
int main()
{
    
    
 	char *a[] = {
    
    "work","at","alibaba"};//指针数组
 	char**pa = a;
 	pa++;
 	printf("%s\n", *pa);
 return 0;
}

分析します:

ここに画像の説明を挿入します

出力結果:
ここに画像の説明を挿入します

3.7 質問 7

#include <stdio.h>
int main()
{
    
    
 	char *c[] = {
    
    "ENTER","NEW","POINT","FIRST"};
 	char**cp[] = {
    
    c+3,c+2,c+1,c};
 	char***cpp = cp;
 	printf("%s\n", **++cpp);
 	printf("%s\n", *--*++cpp+3);
 	printf("%s\n", *cpp[-2]+3);
 	printf("%s\n", cpp[-1][-1]+1);
 return 0;
}

分析:
cpp の逆参照では、次のような cp[] 内のコンテンツが検索されます。c + 3
ここに画像の説明を挿入します
ここに画像の説明を挿入します
出力結果: < a i =3> さて、ポインタの学習はこれで終了です。ここでご覧になったので、「いいね!」を押してください。ありがとうございます。
ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/chendemingxxx/article/details/134770374