** 前言**:一二维数组字符串的使用与创建,字符串和数组如何传参给函数,字符串指针,字符串的输入与输出,清空输入缓冲区的方法,选择排序和冒泡排序。
一.一维数组
1.一维数组的创建与定义
(1).定义及初始化一维数组
int arr1[10] = { 1,2,3,4 };//定义数组可以规定大小也可以不规定大小
int arr2[] = { 1,2,3,4,5 };
int arr3[5] = { 1,2,3,4,5 };
char arr4[3] = { 'a','b','c' };
char arr5[3] = { 'a',93,'c' };//93是ASCII码值,用%c类型打印会打印出ASCII值所对对应的字符串,同理,一个字符'a'用%d类型打印会打印出对应的ASCII码值,就像下段代码
char arr6[] = "abcdefg";
一维数组在创建时可以不规定大小,如果不规定大小,则需要对数组初始化,即数组要有内容,这时候数组的大小(元素个数)就根据初始化的内容来确定,但我们需要注意以下代码的不同。
char arr1[] = "abc";
char arr2[3] = { 'a','b','c' };
从表面上看,arr1和arr2储存的内容都是'a' 'b' 'c' 三个字符,但实际上他们在内存中是这样分配的
在字符数组(字符串)的使用和创建中,要特别特别特别注意这个点。
2.一维数组的使用
int main()
{
int arr[10] = { 0 };//这里数组不完全初始化
int i = 0;
for (i = 0; i < 10; i++)
{
arr[i] = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
这里说明了数组的下标是从0开始的!!arr[i]就是具体的值。
大家也看到了两处画红线的i<10,建议大家都这么写,因为i<多少,这个多少就是数组的元素个数,简单明了。
一维数组的打印一般都是用for循环一个一个打印来实现的,同理,二维数组就用两个for循环
3.数组元素个数的计算和大小的计算
数组大小的计算一般用sizeof计算
数组的元素个数就是数组的大小(单位是字节)除以单个元素的大小
4.一维数组在内存中的储存
一维数组在内存中储存是连续的,由低地址存到高地址
5.避免数组越界
当我们这里写成i<=10,说明会打印总共11个数字,但是我们的数组大小只定义了10,这时数组就会越界,所以我们写程序时一定要
二.二维数组
1.二维数组的定义和初始化
二维数组的创建
int arr1[3][4];
char arr2[3][5];
double arr3[2][4];
二维数组的初始化
int arr1[3][4];
int arr2[3][4] = { {1,2},{3,4} };
int arr3[][3] = { {1,2,3},{4,5} };//二维数组只有在有初始化时,行才可以省略,列任何情况都不可省
2.二维数组的使用
二维数组就用两个for循环去操作,同样的,数组下标都是从0开始~
3.二维数组在内存中的储存
二维数组在内存中储存也是连续的
三.进阶
1.数组名或字符串名到底是什么
很明显,数组名和数组的地址都是首元素的地址,这三者地址的数值相同,但作用不同。
可以看到,str+1和&str[0]+1是一样的,他们的地址+1只会越过一个元素(4个字节),数组名和首元素地址可以等价。但是直接取出数组的地址再+1,这时候就是直接操作整个数组了,地址直接越过了整个数组16个字节,这一点非常需要注意。函数传参一般传的都是数组名,因为在函数内部我们要操作(改变或使用)这个数组肯定是一个一个元素使用。
2.字符串的输入与输出
(1) 注意这里的scanf("%s", str),这里str不用加&,这是因为str是字符串名,字符串名就是首元素地址,所以这里的str已经是一个地址了,不用我们自己加&。
(2)这里的printf("%s", str),也是同理,在打印字符串的时候,我们需要用的是%s类型,而%s需要接收的是地址,我们这里将字符串名str传给%s,也就是字符串首元素的地址,也是'a'的地址,printf就会从'a'开始打印,直到遇到'\0'终止符。
(3)而如果我们要打印字符串里的某个(单个)字符,就需要注意要用%c,字符串的下标也是从0开始的。
3.函数中的数组传参
(1)自己定义一个数组接收
//这里我们自己再定义了一个数组int a[]来接收传过来的数组
void test(int a[])//void是返回类型,我们这里不需要返回什么东西,所以用void
{
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", a[i]);
}
}
int main()
{
int arr[5] = { 1,2,3,4,5 };
test(arr);
return 0;
}
我们在函数test中自己创建了一个数组int a[]来接收,并将数组a的内容打印出来。
(2)创建一个指针来接收
void test(int* p)//自己定义了一个指针*p来接收
{
int i = 0;
for (i = 0; i < 5; i++)
{
p[i] = 6;
}
}
int main()
{
int i = 0;
int arr[5] = { 1,2,3,4,5 };
test(arr);//尝试将数组的每一个值都改成6
for (i = 0; i < 5; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
为什么可以用指针来接收传过来的数组呢?因为前面说过,数组名就是首元素地址,所以也可以用指针来接收~ 学过指针之后,我们就会知道,在数组中
int arr[5] = { 1,2,3,4,5 };
arr[i]=*(arr+i)
所以在上面test(arr)传参时,我们将数组名arr也就是首元素地址传过去,我们可以用指针int*p接收,在函数中,可以直接把p当作数组名用,我们用arr[i]时,arr放在arr[i]哪,p就放在哪,也就是p[i],在test中直接用就可以。
4.常量字符串(字符串指针)
我们知道数组名或者字符串名都表示首元素地址,同理,那这个首元素的地址我们就可以储存到指针里,所以这里创建了一个指针str1指向了首元素字符'a',所以在printf中,我们知道%s后面需要对应的是一个地址,所以直接将地址(指针)str1放进去就ok了,printf就会从str1开始往后打印,直到遇到'\0'。
5.字符输入与输入缓冲区常见问题&清空输入缓冲区的方法
int main()
{
int num;
char ch;
scanf("%d", &num);
scanf("%c", &ch);
return 0;
}
当我们尝试运行这段代码
会发现当我们输入20给num后,按下回车后想要给ch输入,这时候会发现按下回车后程序就结束了。
在解决这个bug之前,我们需要了解一个概念,叫输入缓冲区,我们的数据在传给参数的过程中,要先经过输入缓冲区,然后再一起传给参数。
当我们输入20后,20就被传入到了输入缓冲区,按下回车,这时20就顺利地从输入缓冲区赋值给了num,但是这个回车就留在了输入缓冲区,因为在ascii表中,回车也相当于一个字符,有对应的键值(ASCII),是13,所以轮到向ch输入的时候,scanf直接就从输入缓冲区把剩下的那个回车给读取了,所以就跳过了scanf("%s",&ch),这一点要非常注意,回车也相当于是一个字符。
那怎么解决这个bug呢,在我们scanf后,可以把输入缓冲区给清空,这里介绍几种办法。
(1)
int main()
{
int num;
char ch;
scanf("%d", &num);
setbuf(stdin, NULL);
scanf("%c", &ch);
return 0;
}
在一次scanf输入后,加入一句setbuf(stdin, NULL),stdin是标准输入流,也就是键盘输入,这句话的意思就是将键盘输入流指针改为空指针,可以理解成将输入缓冲区置空,个人觉得这个方法比较便捷。
(2)
int main()
{
int num;
char ch;
scanf("%d", &num);
fflush(stdin);
scanf("%c", &ch);
return 0;
}
在一次scanf输入后,加入一句fflush(stdin),stdin是标准输入流,也就是键盘输入,fflush就是把标准输入流清空,这个方法也不错,但是在vs编译器中不起作用,其它还是可以的。
(3)
int main()
{
int num;
char ch;
char c;
scanf("%d", &num);
c = getchar();
scanf("%c", &ch);
printf("%d\n", num);
printf("%c\n", ch);
return 0;
}
多定义一个字符c去接收这个回车
四.冒泡排序&选择排序
1.冒泡排序
冒泡排序就是元素间两两比较,较大的就把它往后放
#include <stdio.h>
void Bubble_sort(int* arr,int sz)//这里用指针*arr接收传过来的数组名,sz为数组元素个数
{
for (int i = 0; i < sz - 1; i++)//sz为元素个数,前面讲过元素个数为sz,那就i<sz,这里的sz-1是因为有sz个元素,需要sz-1躺排序,-1是因为排到剩下第一个数时就不用继续排了。
{
for (int j = 0; j < sz - 1 - i; j++)//因为下面对数组下标会用到j+1,所以这里j<sz-1//可以想象一下,经过0趟排序时,需要比较sz-1-0对数,经过一趟比较后,就变成需要比较sz-1-1=9对数,再经过一趟比较,就变成需要比较sz-1-2对,所以这里j<sz-1-i,也可以理解成一趟排序后减少一个需要排序的数,0趟排序减少0个需要排序的数。
{
if (arr[j] > arr[j + 1])//如果arr[j]比arr[j+1]大,就把它往后放
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
int main()
{
int arr[] = { 2,3,4,3,5,7,9,4,6,7,1,3 };
int sz = sizeof(arr) / sizeof(arr[0]);
Bubble_sort(arr,sz);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
10个数,只要比较10-1趟。
2.冒泡排序的优化
假如我们需要排序的数组有10个元素,则需要排9趟,但我们发现它在排了3趟的时候,它就已经有序了,那我们也没有再继续浪费算力去给它排序,我们只需要在每趟排序前,加上一个标志flag
#include <stdio.h>
void Bubble_sort(int* arr,int sz)//这里用指针*arr接收传过来的数组名,sz为数组元素个数
{
for (int i = 0; i < sz - 1; i++)//sz为元素个数,前面讲过元素个数为sz,那就i<sz,这里的sz-1是因为有sz个元素,需要sz-1躺排序,-1是因为排到剩下第一个数时就不用继续排了。
{
int flag = 1;//定义一个标志flag=1
for (int j = 0; j < sz - 1 - i; j++)//因为下面对数组下标会用到j+1,所以这里j<sz-1//可以想象一下,经过0趟排序时,需要比较sz-1-0对数,经过一趟比较后,就变成需要比较sz-1-1=9对数,再经过一趟比较,就变成需要比较sz-1-2对,所以这里j<sz-1-i,也可以理解成一趟排序后减少一个需要排序的数,0趟排序减少0个需要排序的数。
{
if (arr[j] > arr[j + 1])//如果arr[j]比arr[j+1]大,就把它往后放
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0;//若有排序到,则证明还无序,flag=0
}
}
if (flag == 1)//若flag==1,则证明已经有序
{
break;//跳出循环,完成排序
}
}
}
int main()
{
int arr[] = { 2,3,4,3,5,7,9,4,6,7,1,3 };
int sz = sizeof(arr) / sizeof(arr[0]);
Bubble_sort(arr,sz);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
3.选择排序
选择排序和冒泡排序差不多,假设数组arr有10个元素,选择排序就是在后9个元素中找出最小值(符合条件)的元素的下标,并和第1个元素交换数值,然后在剩下的9个元素中,进行这样的操作。
完整代码
void SelectSort(int* arr)//选择排序
{
for (int i = 0; i < 10; i++)
{
int min = i;
for (int j = i + 1; j < 10; j++)//在第i个元素的后面开始找最小值
{
if (arr[j] < arr[min])
{
min = j;
}
}
if (i != min)//如果下标min发生了改变,就交换数值
{
int tmp = arr[i];
arr[i] = arr[min];
arr[min] = tmp;
}
}
}
int main()
{
int arr[10] = { 8,3,4,5,7,9,4,6,7,1 };
SelectSort(arr);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
五.结语
可能总结的不是很到位,后面的结构体、函数、指针会再提及数组,数组和指针、函数的关系还是很大的~
✨看完了不妨点个赞收藏吧~
✨您的支持就是博主创作的最大动力
✨再次感谢您的耐心阅读!有不懂的欢迎在评论区讨论哦~
❤️感谢您的支持!!!!!
版权归原作者 iHikko 所有, 如有侵权,请联系我们删除。