目录
1 数组名的理解
arr我们打印出了首元素1
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = arr;
printf("%d\n", *p);
//1
return 0;
}
这里arr打印出来的是40
这是一种特殊的形式
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%zd\n", sizeof(arr));//40?
//如果说arr是数组首元素的地址的话,那这里不是计算一个地址的大小,是4/8吗?
return 0;
}
其实数组名就是数组⾸元素(第⼀个元素)的地址是对的,但是有两个例外:
sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩,单位是字节
&数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素的地址是有区别的)
除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。
%p - 专门用来打印地址的,是16进制的形式,前面的0不会省略
&arr是数组地址
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
printf("arr = %p\n", arr);//首元素的地址
printf("&arr[0] = %p\n", &arr[0]);//首元素的地址
printf("&arr = %p\n", &arr);//数组的地址
return 0;
}
他们的差异如下代码
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//printf("%zd\n", sizeof(arr));//10*4 = 40
printf("arr = %p\n", arr);//首元素的地址
printf("arr+1 = %p\n", arr+1);printf("&arr[0] = %p\n", &arr[0]);//首元素的地址
printf("&arr[0]+1 = %p\n", &arr[0]+1);printf("&arr = %p\n", &arr);//数组的地址
printf("&arr+1 = %p\n", &arr+1);return 0;
}
&arr = 0000007F62F0F578
&arr+1 = 0000007F62F0F5A0
0x78和0xA0之间加了一个0x28
0x78
0x28
0xA0
0x28转成十进制(16^0*8)+(16^1*2)=40
数组地址加1跳过了整个元素的地址就是加了40
指针类型决定了+1/-1跳过几个字节
2 使⽤指针访问数组
代码1:
int main()
{
int arr[10] = { 0 };
//给数组中存放1 2 3 4 5 6 7 8 9 10
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
int* p = arr;
for (i = 0; i < sz; i++)
{
scanf("%d", p);
p++;
}p = arr;
//打印出数组的所有内容
for (i = 0; i < sz; i++)
{
printf("%d ", *p);
p++;
}
return 0;
}
代码2:
int main()
{
int arr[10] = { 0 };
//给数组中存放1 2 3 4 5 6 7 8 9 10
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
int* p = arr;
for (i = 0; i < sz; i++)
{
scanf("%d", p+i);
}//打印出数组的所有内容
for (i = 0; i < sz; i++)
{
printf("%d ", *(p+i));
}
return 0;
}
代码3:
数组形式
int main()
{
int arr[10] = { 0 };
//给数组中存放1 2 3 4 5 6 7 8 9 10
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
int* p = arr;
for (i = 0; i < sz; i++)
{
scanf("%d", &arr[i]);
}//打印出数组的所有内容
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
代码4:
int main()
{
int arr[10] = { 0 };
//给数组中存放1 2 3 4 5 6 7 8 9 10
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
int* p = arr;
for (i = 0; i < sz; i++)
{
scanf("%d", arr+i);
}//打印出数组的所有内容
for (i = 0; i < sz; i++)
{
printf("%d ", *(arr+i));
}
return 0;
}
指针和数组名好像是一回事
arr[i] == *(arr+i)
arr是起始地址,[i]就是下标位i的元素等于*(arr+i)给他加i偏移过i个元素找到新的地址解引用
代码5:
int main()
{
int arr[10] = { 0 };
//给数组中存放1 2 3 4 5 6 7 8 9 10
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
int* p = arr;
for (i = 0; i < sz; i++)
{
scanf("%d", arr + i);
}//打印出数组的所有内容
for (i = 0; i < sz; i++)
{
printf("%d ", i[arr]);
}
return 0;
}
[]只是一个运算符
增加角度理解代码
3 ⼀维数组传参的本质
void test(int arr[10])//形参写成一维数组
{
int sz2 = sizeof(arr) / sizeof(arr[0]);
printf("2: %d\n", sz2);
}int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz1 = sizeof(arr) / sizeof(arr[0]);
printf("1: %d\n", sz1);test(arr);//传的是一维数组
return 0;
}
传过去的是地址在x64环境底下地址是8
在x86环境底下是4
数组名是数组⾸元素的地址;那么在数组传参的时候,传递的是数组名,也就是说本质上数组传参传递的是数组⾸元素的地址。
在函数内求参数部分的数组的元素个数是错误的
结论:⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。
打印出来:
void test(int* arr, int sz)//形参写成一维数组
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);//arr[i] ==> *(arr+i)
}
}int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int sz1 = sizeof(arr) / sizeof(arr[0]);
printf("1: %d\n", sz1);test(arr, sz1);//传的是一维数组
return 0;
}
4 冒泡排序
冒泡排序的核⼼思想就是:两两相邻的元素进⾏⽐较。
思考:
void bubble_sort(int arr[], int sz)
{
//趟数
int i = 0;
for (i = 0; i < sz - 1; i++)
{
//一趟内部的比较
int j = 0;
for (j = 0; j <sz-1-i; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}int main()
{
int arr[] = { 9,8,7,6,5,4,3,2,2,1,0 };
//将arr中的数字排成升序
//冒泡排序 - 两两相邻的元素进行比较
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
print_arr(arr, sz);
return 0;
}
代码优化:
void bubble_sort(int arr[], int sz)
{
//趟数
int i = 0;
for (i = 0; i < sz - 1; i++)
{
//一趟内部的比较
int flag = 1;//假设已经有序
int j = 0;
for (j = 0; j <sz-1-i; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0;
}
}
if (flag == 1)
break;
}
}void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}int main()
{
int arr[] = { 9,0,1,2,3,4,5,6,7,8 };
//将arr中的数字排成升序
//冒泡排序 - 两两相邻的元素进行比较
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
print_arr(arr, sz);
return 0;
}
打印比较次数
int count = 0;
void bubble_sort(int arr[], int sz)
{
//趟数
int i = 0;
for (i = 0; i < sz - 1; i++)
{
//一趟内部的比较
int flag = 1;//假设已经有序
int j = 0;
for (j = 0; j < sz - 1 - i; j++)
{
count++;
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0;
}
}
if (flag == 1)
break;
}
printf("count = %d\n", count);
}
void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}int main()
{
int arr[] = { 9,0,1,2,3,4,5,6,7,8 };
//将arr中的数字排成升序
//冒泡排序 - 两两相邻的元素进行比较
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
print_arr(arr, sz);
return 0;
}
5 ⼆级指针
一级指针
int a = 10;
int* pa = &a;//pa是指针变量,pa是一级指针
pa是变量,也有自己的地址
int** ppa = &pa;//ppa是二级指针变量
int main()
{
int a = 10;
int* pa = &a;
int** ppa = &pa;
a = 200;
printf("%d\n", **ppa);//200return 0;
}
二级指针变量是用来存放一级指针变量地址的!
6 指针数组
字符数组 char arr[5];//存放字符的数组
整型数组 int arr[10];//存放整型的数组
指针数组 char* arr[5];//存放指针的数组
char* int* float*
指针数组的每个元素都是⽤来存放地址(指针)的。
指针数组的每个元素是地址,⼜可以指向⼀块区域。
7 指针数组模拟⼆维数组
使用指针数组,模拟一个二维数组
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
int* arr[] = { arr1, arr2, arr3 };
//arr是指针数组
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;
}