#mark- 01-数组内存存储细节
//问题:变量和数组在内存中存储的区别?
注意作图分析内存
1.变量在内存中的存储
由于变量的内存寻址是从大到小, 所以存储数据时会从高字节开始存储
2.数组的存储和变量有点不一样, 数组存储元素, 是从所占用的低字节开始存储
3.数组名就是数组的地址
// &charValues == &charValues[0] == charValues
printf("&charValues = %p\n", &charValues);
printf("charValues = %p\n", charValues);
#mark- 02-数组注意点
//问题:数组越界导致的问题?
1.注意点: 在使用数组的时候, 一定不要访问不属于自己的存储空间, 这样会导致数据混乱
2.有时候如果访问了不属于自己的存储空间, 程序会报错
#mark- 03-数组练习1
//问题:学习数组在循环中的使用
//从键盘录入当天出售BTC的价格并计算出售的BTC的总价和平均价(比如说一天出售了3个比特币)
1.第一种方法重复代码太多
2.第二种,每次赋值给变量,前一个的值都被覆盖掉了.
并且前两种都需要定义多个变量
3.第三种,定义一个数组,遍历时存储取值,不需要重复定义变量.
并且可以动态计算元素数组的个数
//示例代码:
// 1.1定义数组保存每个比特币的价格
int values[4] = {-1};
// 1.2动态计算数组的元素个数
int length = sizeof(values) / sizeof(values[0]);
// 1.3定义变量保存总和
int sum = 0;
for (int i = 0; i < length; i++) {
printf("请输入第%i个比特币的价格\n", i + 1);
scanf("%i", &values[i]);
sum += values[i];
}
#mark- 04-函数和数组
//问题1:基本数据类型和数组作为函数参数的区别?
1.基本数据类型作为函数的参数是值传递
void change(int value)
{
value = 55;
}
2.注意:数组名作为函数的参数传递, 是传递的数组的地址
void change2(int values[])
{
values[1] = 99;
}
3.数组名就是数组的地址,就是数组首个元素的地址, &number = &number[0] == number
4.注意: 如果数组作为函数的形参, 元素的个数可以省略
(形参不需要接收数组的值,只需要接收数组地址,数组地址大小是固定的,所以系统分配内存也是固定的)
不同于定义数组,定义数组需要知道元素具体个数,系统才能分配存储空间
5.基本数据类型和数组作为形参的区别:
如果形参是基本数据类型, 在函数中修改形参的值不会影响到实参的值
如果形参是数组, 那么在函数中修改形参的值, 会影响到实参的值
#mark- 05-函数和数组2
//问题:数组作为函数形参实质是什么?如何在函数中取出数组的每一元素?
数组作为形参,自动转换为指针,只能在函数外面计算数组元素个数
1.传递的数组的名称, 传递的是地址,其实传递的是指针(指针在64位编译环境占8个字节)
2.如果数组作为形参, 那么在函数中就不能通过数组的名称计算出数组元素的个数,只能在函数外面计算
系统会自动将数组形参转换为指针, 指针占用8个字节
#mark- 06-数组练习2
//问题:如何找出数组元素的最大值?
1.让某一个元素的值作为最大值
int arrayMax(int nums[], int length)
{
// 1.定义一个变量, 假设为最大值
// int max = 0; // 注意: 不能假设一个不是数组中的值最为最大
int max = nums[0];
// 2.遍历数组
for (int i = 1; i < length; i++) {
// 3.依次取出数组中每一个元素的值, 和假设的最大值进行比较
// 如果数组的元素大于假设的最大值, 就让当前元素的值作为最大值
if (max < nums[i]) {
max = nums[i];
}
}
return max;
}
2.让某一个角标作为最大值的角标
int arrayMax2(int values[], int length)
{
// 1.定义变量, 保存数组中最大值的角标(索引)
int max = 0;
// 2.遍历数组
for (int i = 1; i < length; i++) {
// 3.取出数组中对应角标的元素的值进行比较
if (values[max] < values[i]) {
// 如果当前遍历到的角标对应的元素的值大于max这个角标对应元素的值
// 那么就将当前的角标最为最大值的角标
max = i;
}
}
return values[max];
}
#mark - 07-数组练习3
//问题:数组角标的使用?
//从键盘输入3个0~9的数字,然后输出0~9中哪些数字没有出现过
// 从键盘输入100个0~2000的数字,然后输出0~2000中哪些数字没有出现过
//方法一:
// 1.接收用户输入的数据(用三个变量)
int num1, num2, num3;
printf("输入三个整数, 用逗号隔开\n");
scanf("%i,%i,%i", &num1, &num2, &num3);
// 2.遍历打印0~9
for (int i = 0; i <= 9; i++) {
// 3.判断当前打印的值是否是用户输入的值, 如果是就不打印
if (num1 != i &&
num2 != i &&
num3 != i) {
printf("%i\n", i);
}
}
//方法二:
// 空间换时间
// 1.定义数组保存所有用户输入的数
int nums[10] = {0};
// 2.接收用户输入的数据
int value = -1;
for (int i = 0; i < 3; i++) {
printf("请输入%i个整数\n", i+1);
scanf("%i", &value);
nums[value] = 1;
}
for (int i = 0; i < 10; i++) {
// printf("nums[%i] = %i\n", i , nums[i]);
if (nums[i] != 1) {
printf("%i\n", i);
}
}
#mark- 08-数组练习4
//问题:数组练习4排序的原理是什么?
排序原理:正向遍历的数组,从前面开始取,判断元素值不为0,就输出角标
循环原理:
1.将用户输入的值作为索引取修改数组中对应的元素的值
2.重复输入几次同一角标,就累加几次,输出的时候就遍历几次
// 要求从键盘输入6个0~9的数字,排序后输出
// 1.定义数组保存用户输入的数据
int nums[10] = {0};
// 2.接收用户的数据
int value = -1;
for (int i = 0; i < 6; i++) {
printf("请输入第%i个数据\n", i + 1);
scanf("%i", &value);
//累加,同一角标每输入一次,就累加1
nums[value] = nums[value] + 1;
}
//正向遍历数组中所有元素,遍历的是角标
for (int i = 0; i < 10; i++) {
//将i对应存储空间中的元素取出,判断需要输出几次
for (int j = 0; j < nums[i]; j++) {
printf("%i\n", i);
}
}
#mark- 09-选择排序
//问题:选择排序的原理是什么?
从第一个元素的值开始,依次和其它元素的值进行比较,如果后面的元素的值小于这个元素的值,就换位置
完全比较完一次之后, 最值出现在第0位
尖尖朝上: 修改内循环的 条件表达式
尖尖朝下: 修改内循环的 初始化表达式
// 已知一个无序的数组, 里面有5个元素, 要求对数组进行排序
int nums[8] = {99, 12, 88, 34, 5, 44, 12, 100};
int length = sizeof(nums) / sizeof(nums[0]);
printf("length = %i\n", length);
for (int i = 0; i < length; i++) {
printf("nums[%i] = %i\n", i, nums[i]);
}
// length - 1是为了防止角标越界
// length - 1因为最后一个元素已经没有可以比较的了
for (int i = 0; i < length - 1; i++) {
for (int j = i + 1; j < length; j++) {
// printf("*");
// printf("i = %i, j = %i\n", i, j);
//换位置,将小数放前面
if (nums[i] > nums[j]) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
printf("--------------\n");
for (int i = 0; i < length; i++) {
printf("nums[%i] = %i\n", i, nums[i]);
}
#mark- 11-冒泡排序
//问题:冒泡排序的原理是什么?
相邻两个元素比较,每完全比较一次,最值出现在末尾
思路:
1.先分析如何比较
2.找出比较的规律比较完一次之后第二次比较会少一次
3.打印倒三角
4.打印需要比较的角标
5.比较并交换位置
6.将常量替换为变量(length)
// 已知一个无序的数组, 里面有5个元素, 要求对数组进行排序
int nums[6] = {99, 12, 88, 34, 5, 7};
int length = sizeof(nums) / sizeof(nums[0]);
for (int i = 0; i < length; i++) {
printf("nums[%i] = %i\n", i, nums[i]);
}
for (int i = 0; i < length - 1; i++) {
for (int j = 0; j < length - 1 - i; j++) {
// printf("*");
// printf("%i == %i\n", j, j+1);
if (nums[j] > nums[j + 1]) {
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
#mark- 12-排序优化
//问题:如何将一段代码封装抽取?
#mark- 13-折半查找
//问题:折半查找的原理是什么?
折半查找的原理:
1.数组必须是有序的(前提条件)
2.必须已知min和max(知道范围)
3.动态计算mid的值, 取出mid对应的值进行比较
4.如果mid对应的值大于了需要查找的值, 那么max要变小为mid-1
5.如果mid对应的值小于了需要查找的值, 那么min要变大为mid+1
int findKey3(int nums[], int length, int key)
{
int min, max, mid;
min = 0;
max = length - 1;
// 只要还在我们的范围内就需要查找
while (min <= max) {
// 计算中间值
mid = (min + max) / 2;
if (key > nums[mid]) {
min = mid + 1;
}else if (key < nums[mid])
{
max = mid - 1;
}else
{
return mid;
}
}
return -1;
}
#mark- 14-折半查找练习
//问题:如何在有序数组中,插入一个数字,保证数组有序?
// 现有一个有序的数组, 要求给定一个数字, 将该数字插入到数组中, 还要保证数组是有序的
//找到需要插入数字的位置,其实这个位置就是min的位置
//当min > max 的时候,结束查找
int insertValue(int nums[], int length, int key)
{
int min , max, mid;
min = 0;// 1 2
max = length - 1;// 4 1
while (min <= max) {
mid = (min + max) / 2; // 2 0 1
if (key > nums[mid]) {
min = mid + 1;
}else if (key < nums[mid])
{
max = mid - 1;
}
}
return min;
}
#mark- 15-进制查表法(了解)
//问题:理解进制查表法
// 转换所有的进制
// value就是需要转换的数值
// base就是需要&上的数
// offset就是需要右移的位数
void total(int value, int base, int offset)
{
// 1.定义一个数组, 用于保存十六进制中所有的取值
char charValues[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
// 2.定义一个数组, 用于保存查询后的结果
char results[32] = {'0'};
// 3.定义一个变量, 用于记录当前需要存储到查询结果数组的索引
int pos = sizeof(results)/ sizeof(results[0]);
while (value != 0) {
// 1.取出1位的值
int res = value & base;// 1 7 15
// 2.利用取出来得值到表中查询对应的结果
char c = charValues[res];
// 3.存储查询的结果
results[--pos] = c;
// 4.移除二进制被取过的1位
value = value >> offset;// 1 3 4
}
// 4.打印结果
for (int i = pos; i < 32; i++) {
printf("%c", results[i]);
}
printf("\n");
}