c语言笔记照片_c语言笔记
如何看懂一個程序,分三步
1. 流程
2. 每個語句的功能
3. 試數
對于一些小程序的算法
嘗試自己去編程解決它,大部分人都無法自己解決
如果解決不了,嘗試看答案
關鍵要把答案看懂,這個要花很大的精力,也是我們學習的重點
看懂之后嘗試自己去更改程序,并且知道修改之后程序的不同輸出結果的含義
重要的運算符
舉例:
1/2=0 1.0/2=0.5 1/2.0=0.5
1%2=1 2%2=0 n-1% n=n-1
指針
1. 指針就是地址 地址就是指針
2. 地址就是內存單元的編號
3. 指針變量是存放地址的變量
4. 指針和指針變量是兩個不同的概念
5. 但是要注意,通常我們敘述時會把指針變量簡稱為指針,實際上它們含義并不一樣
指針的本質就是操作受限的非負整數.
#include
int main(void)
{
int *p; //p是變量的名字, int *表示p變量存的是int類型變量的地址
int i=3;
p=&I; 1.p保存了i的地址,因此p指向i;
2. p不是i,i也不是p,更準確地說修改p的值不影響i的值,修改i的值也不影響p的值.
3.如果有一個指針變量指向了普通變量,則 *指針變量 就完全等同于 普通變量. *p 完全等同于i,或者說:在所有出現*p的地方都可以替換成i,在所有出現i的地方都可以替換成*p
*p就是以p的內容為地址的變量
return 0;
}
指針的重要性:
1. 表示一些復雜的數據結構
2. 快速的傳遞數據
3.使函數返回一個以上的值
4.能直接訪問硬件
5.能夠方便處理字符串
6.是理解面向對象語言中應用的基礎
總結:c語言的靈魂
指針的定義:
地址:
內存單元的編號
從零開始的非負整數
指針的分類:
1. 基本類型指針
2. 指針和數組
3. 指針和函數
4. 指針和結構誒
5. 多級指針
*的三種含義:
1. 乘法
2.定義指針
Int *p ; // 定義了一個名字叫p的變量,int*表示p只能存放int 變量的地址
3.指針運算符
該運算符放在已經定義好的指針變量的前面
如果p是一個已經定義好的指針變量 則*p表示 以p的內容為地址的變量]
如何通過被調函數修改主調函數普通變量的值
1. 實參必須為該普通變量的地址
2. 形參必須為指針變量
3. 在被調函數中通過
*形參名 =…… 的方式就可以修改主調函數相關變量的值
指針和數組
指針和一維數組
一維數組名是個指針常量,它存放的是一維數組第一個元素的地址
如int a[5] a就是a[0]的地址
下標和指針的關系
如果p是一個指針變量,則p[i]永遠等價于 *(p+i)
確定一個一維數組需要幾個參數(如果一個函數要處理一個一維數組,則需要接受該數組的哪些信息)
1. 數組第一個元素的地址 即數組名
2. 數組長度
Int a[5]; // a是數組名 5是數組元素的個數 元素就是變量 a[0]~a[5]
Int a[3] [4] // 3行4列 a[0][0]是第一個元素 a[i][j] 第i+1行第j+1列
指針變量的運算
指針變量不能相加 不能相除 也不能相乘
如果這兩個指針變量指向的是同一塊連續空間的不同存儲單元,則這兩個指針才可以相減
一個指針變量到底占幾個字節
預備知識:
Sizeof (數據類型)
功能:返回值就是該數據類型所占的字節數
Sizeof(變量名)
功能:返回值就是該變量所占字節數例子: sizeof(int) =4 sizeof(char) =1
假設p指向char類型變量(1個字節)
假設q指向int類型變量(4個字節)
假設r指向double類型變量(8個字節)
p q r 本身所占的字節是否一樣
一個指針變量,無論它指向的變量占幾個字節,該指針變量本身只占四個字節
一個變量的地址使用該變量首字節的地址來表示
動態內存分配
傳統數組的缺點:
1. 數組的長度必須事先制定,且只能是常整數,不能是變量(c99之后可以?)
2. 傳統形式定義的數組,該數組的內存無法手動釋放
在一個函數運行期間,系統為該函數中數組所分配的空間會一直存在,直到該函數運行完畢時,數組的空間才會被系統釋放
3. 數組的長度一旦定義,其長度不能再更改,數組的長度不能在函數運行的過程中動態的擴充或縮小
4. A函數定義的數組,在A函數運行期間可以被其它函數使用,但A函數運行完畢之后,A函數中的數組將無法在其它函數中使用
傳統方式定義的數組不能跨函數使用.
malloc memory(內存) allocate(分配)的縮寫
#include
int * p = (int *) malloc (4);
1. 要使用malloc函數,必須添加malloc.h這個頭文件
2. malloc函數只有一個形參,并且形參是整型
3. 4表示請求系統為本程序分配4個字節
4. malloc函數只能返回第一個字節的地址
5. 分配了8個字節,p變量占4個字節,p所指向的內存地址也占4個字節
6. P本身所占的內存是靜態分配的,p所指向的內存是動態分配的
free(p)表示把p所指向的內存給釋放掉,p本身的內存是靜態的,不能由程序員手動釋放,p本身的內存只能在p變量所在函數運行終止時由系統釋放
為什么需要動態分配內存
動態數組很好的解決了傳統數組的4個缺陷
動態數組的構造
#include
int main(void)
{
int a[5] //如果int占4個字節的話,則本數組總共包含20個字節,每4個字節被當作 一個int變量來使用
int len;
int *pArr;
printf(“請輸入你要存放的元素的個數:”)
scanf(“%d”,&len);
pArr =(int *)malloc(4* len) //本行動態的構造了一個一維數組,該一維數組的長度是len
return 0;
}
動態內存和靜態內存的比較
靜態內存是由系統自動分配,由系統自動釋放
靜態內存是在棧分配的
動態內存是由程序員手動分配的,手動釋放
動態內存是在堆分配的
多級指針
#include
Int main(void)
{
Int i=10;
Int *p=&i; //p是int *類型 ,&p是int ** 類型
Int **q=&p;
Int ***r =&q;
因為r是int ***類型,r只能存放 int ** 類型變量的地址
跨函數使用內存
# include
void f(int **q) q是個指針變量,無論q是什么類型的指針變量,都只占4個字節
{
Int i=5;
}
Int main(void)
{
Int *p;
f(&p);
return 0;
}
結構體是根據用戶實際需要自己定義的復合數據類型
如何使用結構體
兩種方式:
Struct Student st ={1000,”zhangsan”,20};
Struct Student *pst = &st;
1.
St.sid
2.
Pst->sid
Pst所指向的結構體變量中的sid這個成員
注意事項:
結構體變量不能加減乘除,但是可以相互賦值
普通結構體變量和結構體指針變量作為函數傳參的問題
#include
#include
struct Student{
int age;
char sex;
char name[100];
};
void InputStudent(struct Student * pstu);
void OutputStudent(struct Student ss);
int main(void)
{
struct Student st;
InputStudent(&st); //對結構體變量的輸入
printf("%d %c %s\n",st.age ,st.sex, st.name);
OutputStudent(st); //對結構體變量的輸出,可以發送st的地址也可以發送st的內容
return 0;
}
void OutputStudent(struct Student ss)
{
printf("%d %c %s\n",ss.age, ss.sex , ss.name);
}
void InputStudent(struct Student * pstu) //pstu只占4個字節
{
(*pstu).age =10;
strcpy(pstu->name,"張三");
pstu->sex='f';
}
/*
//本函數無法修改主函數st的值,所以本函數是錯誤的
void InputStudent(struct Student stu)
{
stu.age=10;
strcpy(stu.name,"張三"); //不能寫成 stu.name="張三";
stu.sex='f';
}
*/
動態構造存放學生信息的結構體數組
//動態構造一個數組,存放學生信息,然后按分數排序輸出
#include
#include
struct Student
{
int age;
char sex;
float score;
char name[100];
};
int main(void)
{
int len;
struct Student * pArr;
int i,j;
struct Student t;
printf(" 請輸入學生的個數:\n");
printf("len =");
scanf("%d",&len);
//動態地構造一維數組
pArr =(struct Student *)malloc(len *sizeof(struct Student));
for (i=0;i
{
printf("請輸入第%d個學生的信息:\n",i+1);
printf("age=");
scanf("%d",&pArr[i].age);
printf("name=");
scanf("%s",pArr[i].name); //不用加&,因為name是數組名,本身就已經是數組首元素的地址
printf("score=");
scanf("%f",&pArr[i].score);
}
//按學生成績升序,冒泡算法
for(i=0;i
{
for(j=0;j
{
if(pArr[j].score>pArr[j+1].score)
{
t=pArr[j];
pArr[j]=pArr[j+1];
pArr[j+1]=t; //換位置而不是換成績
}
}
}
printf("\n\n學生的信息是:\n");
//輸出
for (i=0;i
{
printf("第%d個學生的信息是:\n",i+1);
printf("age=%d\n",pArr[i].age);
printf("name=%s\n",pArr[i].name);
printf("score=%f\n",pArr[i].score);
printf("\n");
}
return 0;
}
枚舉
什么是枚舉?
把一個事物所有可能的取值一一列舉出來
怎樣使用枚舉
#include
//只定義了一個數據類型,并沒有定義變量,該數據類型的名字是 enumm WeekDay
enum WeekDay{
MonDay,TuesDay,WednesDay,ThursDay,FriDay,SaturDay,SunDay
};
int main(void)
{
// int day; day定義成int類型不太合適
enum WeekDay day=SunDay;
printf("%d\n",day);
return 0;
}
枚舉的優缺點
代碼更安全
書寫麻煩
進制轉換
預備知識:
小數除以大數 商為零 余數是小數本身
十進制轉換為r進制
方法
除r取余,直至商零,余數倒序排列
二進制到十六進制
方法: 從左往右,四位一段,分別轉化,不夠四位的補零
二進制與八進制相互轉換
原碼:
也叫符號-絕對值碼
最高位0表示正 1表示負,其余二進制位是該數字的絕對值的二進制位
原碼簡單易懂
加減運算復雜
存在加減乘除四種運算,增加了cpu的復雜度
零的表示不唯一
反碼
反碼運算不便,也沒有在計算機中運用
移碼
移碼表示數值平移n位,n為偏移量
移碼主要用于浮點數的階碼的存儲
補碼
已知十進制求二進制
求正整數的二進制
除2取零,直至商0,余數倒敘排序
求負整數的二進制
先求與該負數相對應的正整數的二進制代碼,然后將所有位取反,末位加1,不夠位數時,左邊補1
求零的二進制
全是零
已知二進制求十進制
如果首位是0,則表明是正整數,按普通方法求
如果首位是1,則表明是負數,將所有位取反,末尾加1,所得數字就是該負數的絕對值
如果全是0,則對應的十進制數字就是0
比方說:十進制中的1用二進制表示就是01,當你二進制轉十進制的時候,你需要輸入01,系統是自動在01前頭補30個0來湊夠32位.這是正整數的時候,可是當你是十進制中的-1時,二進制表示時,先取十進制-1的絕對值1的二進制.否則系統會自動給你補30個0,導致二進制的11被認為是正整數3而不是-1
算法:
通俗定義:
解題的方法和步驟
狹義定義:
對存儲數據的操作
對不同的存儲結構,要完成某一功能所執行的操作是不一樣的
比如:
要輸出數組中所有元素的操作和要輸出鏈表中所有元素的操作肯定是不一樣的,這說明算法是依附于存儲結構的,不同的存儲結構,所執行的算法是不一樣的
廣義定義:
廣義的算法也叫泛型
無論數據是如何存儲的,對該數據的操作是一樣的
我們至少可以通過兩種結構來存儲數據
數組:
優點:
存取速度快
缺點:
需要一個連續的很大的內存
插入和刪除元素的效率很低
鏈表
優點:
插入刪除元素效率高
不需要一個連續的很大的內存
缺點:
查找某個位置的元素效率很低
專業術語:
頭結點
頭結點的數據類型和首節點的類型一模一樣
頭結點是首節點前面的那個節點
頭結點并不存放有效數據
設置頭結點是為了方便對鏈表的操作
頭指針
存放頭結點地址的指針變量
首節點
存放第一個有效數據的節點
尾節點
存放最后一個有效數據的節點
確定一個鏈表需要一個參數(頭結點的地址)
郝斌老師的09年課程
總結
以上是生活随笔為你收集整理的c语言笔记照片_c语言笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: idea创建包怎么让包分层_干货 | 通
- 下一篇: fpga初始化错误_一种SRAM型FPG