#mark- 01-數(shù)組內(nèi)存存儲(chǔ)細(xì)節(jié)
//問(wèn)題:變量和數(shù)組在內(nèi)存中存儲(chǔ)的區(qū)別?
注意作圖分析內(nèi)存
1.變量在內(nèi)存中的存儲(chǔ)
由于變量的內(nèi)存尋址是從大到小, 所以存儲(chǔ)數(shù)據(jù)時(shí)會(huì)從高字節(jié)開始存儲(chǔ)
2.數(shù)組的存儲(chǔ)和變量有點(diǎn)不一樣, 數(shù)組存儲(chǔ)元素, 是從所占用的低字節(jié)開始存儲(chǔ)
3.數(shù)組名就是數(shù)組的地址
// &charValues == &charValues[0] == charValues
printf("&charValues = %p\n", &charValues);
printf("charValues = %p\n", charValues);
#mark- 02-數(shù)組注意點(diǎn)
//問(wèn)題:數(shù)組越界導(dǎo)致的問(wèn)題?
1.注意點(diǎn): 在使用數(shù)組的時(shí)候, 一定不要訪問(wèn)不屬于自己的存儲(chǔ)空間, 這樣會(huì)導(dǎo)致數(shù)據(jù)混亂
2.有時(shí)候如果訪問(wèn)了不屬于自己的存儲(chǔ)空間, 程序會(huì)報(bào)錯(cuò)
#mark- 03-數(shù)組練習(xí)1
//問(wèn)題:學(xué)習(xí)數(shù)組在循環(huán)中的使用
//從鍵盤錄入當(dāng)天出售BTC的價(jià)格并計(jì)算出售的BTC的總價(jià)和平均價(jià)(比如說(shuō)一天出售了3個(gè)比特幣)
1.第一種方法重復(fù)代碼太多
2.第二種,每次賦值給變量,前一個(gè)的值都被覆蓋掉了.
并且前兩種都需要定義多個(gè)變量
3.第三種,定義一個(gè)數(shù)組,遍歷時(shí)存儲(chǔ)取值,不需要重復(fù)定義變量.
并且可以動(dòng)態(tài)計(jì)算元素?cái)?shù)組的個(gè)數(shù)
//示例代碼:
// 1.1定義數(shù)組保存每個(gè)比特幣的價(jià)格
int values[4] = {-1};
// 1.2動(dòng)態(tài)計(jì)算數(shù)組的元素個(gè)數(shù)
int length = sizeof(values) / sizeof(values[0]);
// 1.3定義變量保存總和
int sum = 0;
for (int i = 0; i < length; i++) {
printf("請(qǐng)輸入第%i個(gè)比特幣的價(jià)格\n", i + 1);
scanf("%i", &values[i]);
sum += values[i];
}
#mark- 04-函數(shù)和數(shù)組
//問(wèn)題1:基本數(shù)據(jù)類型和數(shù)組作為函數(shù)參數(shù)的區(qū)別?
1.基本數(shù)據(jù)類型作為函數(shù)的參數(shù)是值傳遞
void change(int value)
{
value = 55;
}
2.注意:數(shù)組名作為函數(shù)的參數(shù)傳遞, 是傳遞的數(shù)組的地址
void change2(int values[])
{
values[1] = 99;
}
3.數(shù)組名就是數(shù)組的地址,就是數(shù)組首個(gè)元素的地址, &number = &number[0] == number
4.注意: 如果數(shù)組作為函數(shù)的形參, 元素的個(gè)數(shù)可以省略
(形參不需要接收數(shù)組的值,只需要接收數(shù)組地址,數(shù)組地址大小是固定的,所以系統(tǒng)分配內(nèi)存也是固定的)
不同于定義數(shù)組,定義數(shù)組需要知道元素具體個(gè)數(shù),系統(tǒng)才能分配存儲(chǔ)空間
5.基本數(shù)據(jù)類型和數(shù)組作為形參的區(qū)別:
如果形參是基本數(shù)據(jù)類型, 在函數(shù)中修改形參的值不會(huì)影響到實(shí)參的值
如果形參是數(shù)組, 那么在函數(shù)中修改形參的值, 會(huì)影響到實(shí)參的值
#mark- 05-函數(shù)和數(shù)組2
//問(wèn)題:數(shù)組作為函數(shù)形參實(shí)質(zhì)是什么?如何在函數(shù)中取出數(shù)組的每一元素?
數(shù)組作為形參,自動(dòng)轉(zhuǎn)換為指針,只能在函數(shù)外面計(jì)算數(shù)組元素個(gè)數(shù)
1.傳遞的數(shù)組的名稱, 傳遞的是地址,其實(shí)傳遞的是指針(指針在64位編譯環(huán)境占8個(gè)字節(jié))
2.如果數(shù)組作為形參, 那么在函數(shù)中就不能通過(guò)數(shù)組的名稱計(jì)算出數(shù)組元素的個(gè)數(shù),只能在函數(shù)外面計(jì)算
系統(tǒng)會(huì)自動(dòng)將數(shù)組形參轉(zhuǎn)換為指針, 指針占用8個(gè)字節(jié)
#mark- 06-數(shù)組練習(xí)2
//問(wèn)題:如何找出數(shù)組元素的最大值?
1.讓某一個(gè)元素的值作為最大值
int arrayMax(int nums[], int length)
{
// 1.定義一個(gè)變量, 假設(shè)為最大值
//? ? int max = 0; // 注意: 不能假設(shè)一個(gè)不是數(shù)組中的值最為最大
int max = nums[0];
// 2.遍歷數(shù)組
for (int i = 1; i < length; i++) {
// 3.依次取出數(shù)組中每一個(gè)元素的值, 和假設(shè)的最大值進(jìn)行比較
// 如果數(shù)組的元素大于假設(shè)的最大值, 就讓當(dāng)前元素的值作為最大值
if (max < nums[i]) {
max = nums[i];
}
}
return max;
}
2.讓某一個(gè)角標(biāo)作為最大值的角標(biāo)
int arrayMax2(int values[], int length)
{
// 1.定義變量, 保存數(shù)組中最大值的角標(biāo)(索引)
int max = 0;
// 2.遍歷數(shù)組
for (int i = 1; i < length; i++) {
// 3.取出數(shù)組中對(duì)應(yīng)角標(biāo)的元素的值進(jìn)行比較
if (values[max] < values[i]) {
// 如果當(dāng)前遍歷到的角標(biāo)對(duì)應(yīng)的元素的值大于max這個(gè)角標(biāo)對(duì)應(yīng)元素的值
// 那么就將當(dāng)前的角標(biāo)最為最大值的角標(biāo)
max = i;
}
}
return values[max];
}
#mark - 07-數(shù)組練習(xí)3
//問(wèn)題:數(shù)組角標(biāo)的使用?
//從鍵盤輸入3個(gè)0~9的數(shù)字,然后輸出0~9中哪些數(shù)字沒(méi)有出現(xiàn)過(guò)
// 從鍵盤輸入100個(gè)0~2000的數(shù)字,然后輸出0~2000中哪些數(shù)字沒(méi)有出現(xiàn)過(guò)
//方法一:
// 1.接收用戶輸入的數(shù)據(jù)(用三個(gè)變量)
int num1, num2, num3;
printf("輸入三個(gè)整數(shù), 用逗號(hào)隔開\n");
scanf("%i,%i,%i", &num1, &num2, &num3);
// 2.遍歷打印0~9
for (int i = 0; i <= 9; i++) {
// 3.判斷當(dāng)前打印的值是否是用戶輸入的值, 如果是就不打印
if (num1 != i &&
num2 != i &&
num3 != i) {
printf("%i\n", i);
}
}
//方法二:
// 空間換時(shí)間
// 1.定義數(shù)組保存所有用戶輸入的數(shù)
int nums[10] = {0};
// 2.接收用戶輸入的數(shù)據(jù)
int value = -1;
for (int i = 0; i < 3; i++) {
printf("請(qǐng)輸入%i個(gè)整數(shù)\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-數(shù)組練習(xí)4
//問(wèn)題:數(shù)組練習(xí)4排序的原理是什么?
排序原理:正向遍歷的數(shù)組,從前面開始取,判斷元素值不為0,就輸出角標(biāo)
循環(huán)原理:
1.將用戶輸入的值作為索引取修改數(shù)組中對(duì)應(yīng)的元素的值
2.重復(fù)輸入幾次同一角標(biāo),就累加幾次,輸出的時(shí)候就遍歷幾次
// 要求從鍵盤輸入6個(gè)0~9的數(shù)字,排序后輸出
// 1.定義數(shù)組保存用戶輸入的數(shù)據(jù)
int nums[10] = {0};
// 2.接收用戶的數(shù)據(jù)
int value = -1;
for (int i = 0; i < 6; i++) {
printf("請(qǐng)輸入第%i個(gè)數(shù)據(jù)\n", i + 1);
scanf("%i", &value);
//累加,同一角標(biāo)每輸入一次,就累加1
nums[value] = nums[value] + 1;
}
//正向遍歷數(shù)組中所有元素,遍歷的是角標(biāo)
for (int i = 0; i < 10; i++) {
//將i對(duì)應(yīng)存儲(chǔ)空間中的元素取出,判斷需要輸出幾次
for (int j = 0; j < nums[i]; j++) {
printf("%i\n", i);
}
}
#mark- 09-選擇排序
//問(wèn)題:選擇排序的原理是什么?
從第一個(gè)元素的值開始,依次和其它元素的值進(jìn)行比較,如果后面的元素的值小于這個(gè)元素的值,就換位置
完全比較完一次之后,? 最值出現(xiàn)在第0位
尖尖朝上: 修改內(nèi)循環(huán)的 條件表達(dá)式
尖尖朝下: 修改內(nèi)循環(huán)的 初始化表達(dá)式
// 已知一個(gè)無(wú)序的數(shù)組, 里面有5個(gè)元素, 要求對(duì)數(shù)組進(jìn)行排序
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是為了防止角標(biāo)越界
// length - 1因?yàn)樽詈笠粋€(gè)元素已經(jīng)沒(méi)有可以比較的了
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);
//換位置,將小數(shù)放前面
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-冒泡排序
//問(wèn)題:冒泡排序的原理是什么?
相鄰兩個(gè)元素比較,每完全比較一次,最值出現(xiàn)在末尾
思路:
1.先分析如何比較
2.找出比較的規(guī)律比較完一次之后第二次比較會(huì)少一次
3.打印倒三角
4.打印需要比較的角標(biāo)
5.比較并交換位置
6.將常量替換為變量(length)
// 已知一個(gè)無(wú)序的數(shù)組, 里面有5個(gè)元素, 要求對(duì)數(shù)組進(jìn)行排序
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-排序優(yōu)化
//問(wèn)題:如何將一段代碼封裝抽取?
#mark- 13-折半查找
//問(wèn)題:折半查找的原理是什么?
折半查找的原理:
1.數(shù)組必須是有序的(前提條件)
2.必須已知min和max(知道范圍)
3.動(dòng)態(tài)計(jì)算mid的值, 取出mid對(duì)應(yīng)的值進(jìn)行比較
4.如果mid對(duì)應(yīng)的值大于了需要查找的值, 那么max要變小為mid-1
5.如果mid對(duì)應(yīng)的值小于了需要查找的值, 那么min要變大為mid+1
int findKey3(int nums[], int length, int key)
{
int min, max, mid;
min = 0;
max = length - 1;
// 只要還在我們的范圍內(nèi)就需要查找
while (min <= max) {
// 計(jì)算中間值
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-折半查找練習(xí)
//問(wèn)題:如何在有序數(shù)組中,插入一個(gè)數(shù)字,保證數(shù)組有序?
// 現(xiàn)有一個(gè)有序的數(shù)組, 要求給定一個(gè)數(shù)字, 將該數(shù)字插入到數(shù)組中, 還要保證數(shù)組是有序的
//找到需要插入數(shù)字的位置,其實(shí)這個(gè)位置就是min的位置
//當(dāng)min > max 的時(shí)候,結(jié)束查找
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-進(jìn)制查表法(了解)
//問(wèn)題:理解進(jìn)制查表法
// 轉(zhuǎn)換所有的進(jìn)制
// value就是需要轉(zhuǎn)換的數(shù)值
// base就是需要&上的數(shù)
// offset就是需要右移的位數(shù)
void total(int value, int base, int offset)
{
// 1.定義一個(gè)數(shù)組, 用于保存十六進(jìn)制中所有的取值
char charValues[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
// 2.定義一個(gè)數(shù)組, 用于保存查詢后的結(jié)果
char results[32] = {'0'};
// 3.定義一個(gè)變量, 用于記錄當(dāng)前需要存儲(chǔ)到查詢結(jié)果數(shù)組的索引
int pos = sizeof(results)/ sizeof(results[0]);
while (value != 0) {
// 1.取出1位的值
int res = value & base;// 1 7 15
// 2.利用取出來(lái)得值到表中查詢對(duì)應(yīng)的結(jié)果
char c = charValues[res];
// 3.存儲(chǔ)查詢的結(jié)果
results[--pos] = c;
// 4.移除二進(jìn)制被取過(guò)的1位
value = value >> offset;// 1 3 4
}
// 4.打印結(jié)果
for (int i = pos; i < 32; i++) {
printf("%c", results[i]);
}
printf("\n");
}