コンテンツ
8.2 Sn = a + aa + aaa + aaaa + aaaaaの最初の5つの項の合計を見つける練習をします。ここで、aは数値です。
1.1ポインタとは
1.ポインタは、メモリ内の最小単位の番号、つまりアドレスです(各スペースにはアドレスがあります)
2.通常、話し言葉で話されるポインタは、メモリアドレスを格納するために使用される変数であるポインタ変数を参照し、アドレスはアドレス空間の一部を一意に識別します。
3:ポインターは32ビットを生成します:32ビットプラットフォームのCPUを介して4バイト、および32ビット:64ビットプラットフォームのCPUを介して8バイト。
#include <stdio.h>
int main()
{
int a = 10;//在内存中开辟一块空间
int *p = &a;//对变量a,取出它的地址,可以使用&操作符。
//a变量占用4个字节的空间,a的4个字节的第一个字节的地址存放在p变量中,p就是一个指针变量
return 0;
}
2.1ポインタとポインタの種類
変数には、整数、浮動小数点数など、さまざまなタイプがあります。ポインタには型がありますか?
ポインタ変数のサイズは4/8バイトで、アドレスを格納するために使用されます
int main()
{
int a = 10;
int* pa = &a;
char ch = 'w';
char* pc = &ch;
printf("%d\n", sizeof(pa));
printf("%d\n", sizeof(pc));
return 0;
}
2.2ポインタ型の意味
2.3ポインターの種類は、間接参照時にポインターが持つ権限の量を決定します
整数ポインター逆参照は4バイトにアクセスし、文字ポインター参照は1バイトにアクセスします
int main()
{
int a = 0x11223344; //44 33 22 11
int* pa = &a;
*pa = 0; //00 00 00 00 操作了4个字节
char* pa = &a;
*pa = 0; //00 33 22 11 操作了1个字节
return 0;
}
2.4ポインターのタイプによって、ポインターが前進または後退する量(距離)が決まります
int main()
{
int a = 10;
int*pa = &a;
char* pc = &a;
printf("%p\n", pa);
printf("%p\n", pc);
printf("%p\n", pa+1);
printf("%p\n", pc+1);
return 0;
}
3.1ワイルドポインタ
ワイルドポインタは、ポインタが指していることがわからない場所です(ランダム、正しくない、指定されていない)
3.2原因:ポインタが初期化されていません
int main()
{
int* p;//指针变量没有初始化,放的是随机值,随机值中的空间不属于我们,非法操作
*p = 20;
return 0;
}
3.3原因:ポインタの範囲外アクセス
int main()
{
int arr[5] = { 1,2,3,4,5 };
int i = 0;
int* p = arr;
for (i = 0; i < 10; i++)
{
printf("%d ", *p);//指针所指向的空间越界访问
p++;
}
return 0;
}
int* test()
{
int a = 10;
printf("%d\n", a);
return &a; //函数结束空间销毁,a的地址未知,非法访问内存
}
int main()
{
int*p = test();
*p = 100;
return 0;
}
3.4ワイルドポインタの回避
1.ポインタの初期化
2.範囲外のポインタに注意してください
3.ポインタはスペースを指し、NULLに設定されます(NULLは0アドレスであり、使用されていない場合にのみ初期化されます)
4.ローカル変数のアドレスを返さないようにします
5.使用前にポインタの有効性を確認します(アサーションのアサート)
4.1ポインタ演算
4.2ポインタ+-ポインタの整数関係演算
int values[5];
int *vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[N_VALUES];)//地址有大有小,指针也有关系运算
{
*vp++ = 0;
}
4.3ポインタ-ポインタ(前提:2つのポインタが同じスペースを指している必要があります)
int main()
{
int arr[10] = { 0 };
printf("%d\n", &arr[0] - &arr[9]);//答案是9,指针-指针得到两个指针之间的元素的个数
return 0;
}
ポインター-ポインターはstrlenを実装します
int my_strlen(char* str)
{
char* start = str;
while (*str)
{
str++;
}
return str - start;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
5.ポインタと配列
配列名は、配列の最初の要素のアドレスを表します
ただし、2つの例外があります。
sizeof(配列名)、配列名は配列全体を表し、配列全体のサイズが計算されます
&配列名、配列名は配列全体を表し、配列全体のアドレスが取り出されます
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
printf("%p\n", arr);
printf("%p\n", &arr[0]);
return 0;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));//指针+-整数写法
}
return 0;
}
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr);
printf("%p\n", arr+1);
printf("%p\n", &arr[0]);
printf("%p\n", &arr[0]+1);//是一个整形指针类型,+1跳过一个整形
printf("%p\n", &arr);
printf("%p\n", &arr+1);//+1跳过一个数组,是一个数组指针类型
return 0;
}
6.セカンダリポインタ
int main()
{
int a = 10;
int* pa = &a;//pa是指针变量(一级指针) *是指针,int是类型
int** ppa = &pa;//ppa是一个二级指针,存放一级指针变量的地址
//int* 是一级指针变量的类型,*代表是一个指针
int*** pppa = &ppa;//pppa就是三级指针.....
//ppa如何找到a,*ppa=pa,*pa=a ->可以写成 **ppa找到a;
return 0;
}
7.ポインタの配列
ポインターの配列はポインターですか、それとも配列ですか?整数配列を学習しました:int arr [5]、5つの整数の配列
ポインターの配列は、int *arr[5]などのポインターの配列です。
int main()
{
//int arr[5];//指针数组 - 存放整型的数组
//char ch[6];//字符数组 -存放字符的数组
int a = 10;
int b = 11;
int c = 12;
int d = 13;
int e = 14;
int* arr2[5] = {&a, &b, &c, &d, &e};//指针数组
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", *(arr2[i])); //法很难看,在一级指针中不会这么用
}
return 0;
}
int main()
{
int data1[] = { 1,2,3,4,5 };
int data2[] = { 2,3,4,5,6 };
int data3[] = { 3,4,5,6,7 };
//arr就是一个指针数组
int* arr[3] = { data1 ,data2, data3 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
8.1演習:文字列の内容を逆にする関数を記述します。
思路:用指针的方式找到字符串的起始地址和结束地址,用临时变量交换
#include <assert.h>
#include <stdio.h>
void reverse(char* str)
{
assert(str);//检查要使用的指针是否为NULL
int len = strlen(str);
char* left = str;
char* right = str + len - 1;
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main()
{
char arr[100];
scanf("%s",arr);
reverse(arr);
printf("%s", arr);
return 0;
}
8.2 Sn = a + aa + aaa + aaaa + aaaaaの最初の5つの項の合計を見つける練習をします。ここで、aは数値です。
例:2 + 22 + 222 + 2222 + 22222
思路:
该表达式的第i项中有i个a数字,第i项为ret因此:可以推导出ret*10+a
int main()
{
int a = 0;
int n = 0;
scanf("%d%d", &a, &n);
int i = 0;
int sum = 0;
int ret = 0;
for (i = 0; i < n; i++)
{
ret = ret * 10 + a;
sum += ret;
}
printf("%d ", sum);
return 0;
}
8.30から100000までのすべての「水仙」を見つけて出力します。
「水仙の数」はn桁の数を指し、各数のn乗の合計は、実際には数自体に等しくなります。たとえば、153 = 1 ^ 3 + 5 ^ 3 + 3 ^ 3の場合、 153は「水仙番号」です。
思路
1. 求位数
2. 获取每个位置上的数据,并对其进行立方求和
3. 求和完成后,检测结果是否与其相等
#include <math.h>
//153
int main()
{
int i = 0;
for (i = 0; i <= 100000; i++)
{
int tmp = i;
int n = 1;
//第一步判断是几位数
while (tmp / 10)
{
n++;
tmp = tmp / 10;
}
//计算每一位次方和
tmp = i;
int sum = 0;
while (tmp)
{
sum += pow(tmp % 10, n);
tmp = tmp / 10;
}
//3.判断
if (i == sum)
{
printf("%d ", i);
}
}
return 0;
}
8.4ひし形の印刷
思路
1.为了让第一行*来到中间,其他地方要打印空格,我们先打印上面7行的*,再打印下面6行
2.第一个*左边6个空格,往下一行-1
int main()
{
int n = 0;
scanf("%d", &n);
//输入打印上半部分 n,例如上半部分为7,下半部分自动为6,方便打印成菱形
int i = 0;
for (i = 0; i < n; i++)
{
//打印一行
//打印空格
int j = 0;
for (j=0; j<n-1-i; j++)
{
printf(" ");
}
//打印* *号是1,3,5,7...往下增,i为0时打印一个*,i为1时打印三个*
for (j = 0; j < 2 * i + 1; j++)
{
printf("*");
}
printf("\n");
}
//打印下半部分 n-1
for (i = 0; i < n-1; i++)
{
//打印一行
//打印空格
int j = 0;
for (j = 0; j <= i; j++)
{
printf(" ");
}
//打印*
for (j = 0; j < (n-1-i)*2-1; j++)
{
printf("*");
}
printf("\n");
}
return 0;
}