笔记:数组的内存分配 , 排序算法,数组和函数之间的关系

#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");

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容