#include
#include
main() //主函數,跟java類似 程序的入口函數
{
printf("Hello world !\n"); //在控制台輸出
system("java cn.itcast.demo.HelloWorld");//調用執行java文件
system("pause");
}
//system("pause");是:調用cmd裡面的暫停命令,讓cmd窗口暫停執行以下 ,方便我們觀察程序的執行結果.
c語言的數據類型
char, int, float, double, signed,unsigned, long, short and void
1.在c99的語法的中 是沒有boolean的數據類型的,true false 非0代表真 0代表的是假.
2.c語言裡面沒有byte類型 ,
如何讓c語言表示 java中的byte呢? 可以利用char類型代替java中的byte類型
3.c語言裡面沒有String的字符串 , c想表示一個字符串 一般是通過char數組來表示的
sizeof(); 參數是數據類型 返回值就是這個數據類型在內存中占用多少空間
4. 注意: signed, unsigned:只能修飾整數類型的數據 不能修飾浮點型的數據。
signed表示有符號,unsigned表示無符號。
5.java中的char是兩個字節 ,c語言裡面 1個字節
*/
#include
main()
{ // %d 代表的是一個占位符
printf("char占用的字節為%d\n",sizeof(char)); 1個字節
printf("int占用的字節為%d\n",sizeof(int)); 4個字節
printf("float占用的字節為%d\n",sizeof(float)); 4個字節
printf("double占用的字節為%d\n",sizeof(double)); 8個字節
printf("short占用的字節為%d\n",sizeof(short)); 2個字節
printf("long占用的字節為%d\n",sizeof(long));
printf("signed int占用的字節為%d\n",sizeof(signedint));
printf("unsigned int占用的字節為%d\n",sizeof(unsignedint));
//printf("unsigneddouble占用的字節為%d\n",sizeof(unsigned double)); 該行代碼會報錯。
system("pause");
}
1、C語言中的刪除操作使用占位符實現的,不同類型的數據對應不同占位符:
%d - int
%ld – long int
%c - char
%f - float
%lf – double
%x – 十六進制輸出 int 或者long int 或者short int
%o - 八進制輸出
%s – 字符串
%hd - short
short
2、C語言的輸入函數:
Int len;
Scanf(“%d”,&len); //掃描鍵盤的輸入函數:
參數1:輸入數據的指定類型的占位符。
餐宿2:指定保存輸入數值的變量地址。
例:
#include
main()
{
int i = 129024;
long l = 333L;
char c ='B';
float f = 3.1415926f;
double d = 3.1415;
short s = 257;
printf("int i =%d\n",i);
printf("int l =%ld\n",l);
printf("int c =%d\n",c);
printf("int f =%f\n",f);
printf("int d =%lf\n",d);
printf("short s=%hd\n",s);
char cc;
printf("請輸入一個int類型的值\n");
//& 取地址
scanf("%c",&cc);
printf("char cc =%c\n",cc);
//接收輸入的字符串:使用char數組:
//定義一個char類型的數組 叫arr 用來存放字符串
char arr[]={' ', ' ',' ','',' '};
printf("請輸入一個字符串\n");
scanf("%s",arr);
printf("數組的內容%s\n",arr);
system("pause");
}
1、所謂指針就是一個地址,地址其實就是一個內存空間的編號.
2、每個變量在內存中都有一個地址 :通過& 符號獲取變量的地址.
例:
#include
main(){
int i;
//把i變量在內存中的地址 打印出來
//打印出變量的地址,指針就是一個地址 ,
//地址為十六進制:如:0xXXXX ,#表示打印的數值前面帶0x
printf("i的地址為%#x\n",&i);
//60秒的倒計時
for(i =60; i>0;){
printf("剩余時間%d\n",i);
sleep(4000);
i--;
}
printf("游戲結束\n");
system("pause");
}
3、指針和指針變量:
例:
#include
main(){
// 1. 指針就是地址, 通過一個地址可以訪問到一塊內存空間, 如果修改這個內存空間裡面的內容
int i = 5; //定義一個int類型的變量 變量的名字 叫 i 裡面存放的內容 是一個int類型的值
// 2. 指針變量 用來存放一個變量地址的變量
int* p; //定義了一個int* 類型的變量 變量的名字叫p 裡面存放的內容 是一個
//int* 類型的值
//也可以定義為:int *p; 或 int * p;
p = &i; // p裡面存放的就是 i變量的地址了.
printf("p的值為%#x\n",p);
// 指針和指針變量的關系
// 指針是一個地址 ..
// 指針變量是存放一個地址的變量
//其實是兩個完全不同的概念,但是 世面的書籍 習慣上把指針跟指針變量沒有做區別
// * 號操作符的使用:
1.使用場景,定義一個指針變量 int* double* long*
2.表示兩個數據相乘 3*5 = 15;
3. 如果*號後面跟的是一個指針變量, 用*可以訪問指針變量內部存放的地址 裡面存儲的變量
//*p; //獲取p變量裡面存放地址所指向的變量,就是i對應的值;
//*p 和 i 代表的是同一個變量
printf("*p的值為%d\n",*p);
system("pause");
}
1、指針未經賦值不能使用: 以下代碼會報錯:
#include
main(){
int i = 5;
int* p ;
printf("*p的值為%d\n",*p);
system("pause");
}
2、不同的指針類型 不能進行相互的轉化
#include
/**
不同的指針類型 不能進行相互的轉化
每一種變量類型 在內存中占用的空間 是不相同的.
*/
main(){
short s = 278;
int i = 2777777; //4個byte
int* p = &i;
short* q = &i; // short 在內存空間裡面占用的是兩個 byte
printf("*p=%d\n",*p);
printf("*q=%hd\n",*q);
system("pause");
}
3、不能使用已經被系統回收掉的內存空間裡的數據:
通過修改地址裡面的值 達到了交換數據的目的
#include
void swap2(int* p, int* q){//p代表的是 i的地址, q代表的是 j的地址
// 把i變量和 j變量的地址 傳遞給了子函數,在子函數裡面直接通過修改地址裡面的值 達到了交換數據的目的
// *p 代表的就是 i變量
// *q 代表的就是 j變量
int temp;
temp = *p;
*p = *q;
*q = temp;
}
//主方法
main(){
int i = 3;
int j = 5;
// swap(i,j);
swap2(&i,&j);
printf("i=%d\n",i);
printf("j=%d\n",j);
system("pause");
}
1、直接訪問硬件 (opengl 顯卡繪圖)
2、 快速傳遞數據(指針表示地址)
3、 返回一個以上的值(返回一個數組或者結構體的指針)
例:在子函數中同時修改兩個變量對應的值:
#include
//相當於是讓子函數 修改了主函數裡面連個數據的值, 子函數返回一個以上的數據
void f(int* p , int* q){ // p表示的是i的地址, q代表的是 j的地址
*p = *p+3;
*q = *q+3;
}
main(){
int i = 3;
int j = 5;
f(&i,&j); //調用子函數
printf("i=%d\n",i);
printf("j=%d\n",j);
system("pause");
}
4、 表示復雜的數據結構(結構體)
5、 方便處理字符串
// c語言是沒有String類型的 要在c語言裡面表示一個字符串 一般都是通過字符數組的方式表示
#include
main(){
// char arr[]={'h','e','l','l','o'};
//char類型的指針變量
char* arr ="hello";
//輸出字符傳
printf("%s\n",&arr[0]);//arr[0]字符數組的首地址。
system("pause");
}
6 、指針有助於理解面向對象
1、數組:
數組在內存中是一塊連續的內存空間。
數組的名稱 等於數組中第一個元素的地址(首地址)。
int arr[]={1,2,3,4};
printf("arr = %#x \n",arr);
printf("第一個元素的地址為%#x\n",&arr[0]);
上面兩行代碼輸出的值相同。
2、指針操作數組:
例:開發一個子方法 把數組的每一個元素都打印出來
#include
// 第一個參數 數組的首地址, 第二個參數 數組的長度
void printArr(int* parr , intlen){
int i;
for( i=0;i
//輸出方式一:根據數組的下標獲取數組中的值:
printf("arr[%d]=%d\n",i,parr[i]);
// *parr //數組第一個元素對應的內容
//*(parr+1) 獲取數組第二元素對應的內容(因為內存是連續的空間)
printf("arr[%d]=%d\n",i,*(parr+i));
}
}
main(){
int arr[]={1,2,3,4,5,6,7,8,9};
printArr(arr,9);
system("pause");
}
1、指針的運算只對連續的內存空間才有意義,數組是一塊連續的內存空間:
例:數組元素指針之間的運算:
#include
main(){
//數組是一塊連續的內存空間
int intarr[] = {1,2,3,4,5,6,7,8,9};
// int* arr0 = &intarr[0];
int* arr0 = intarr;//數組第一個元素的地址
int* arr1 = &intarr[1];
int* arr2 = &intarr[2];
printf("arr0地址為%#x\n",arr0);
printf("arr1地址為%#x\n",arr1);
printf("arr2地址為%#x\n",arr2);
printf("arr2與arr0之間的距離為%d\n", arr2 - arr0);
// 指針的運算 相減和相加得到的結果其實都是 內存地址的偏移量,不是單純的內存地址整數加減結果.結果代表的有特殊的業務含義, 幾個內存空間之間的偏移量.
char chararr[] ={'1','2','3','4','5'};
// int* arr0 = &intarr[0];
char* chararr0 = chararr;//數組第一個元素的地址
char* chararr1 = &chararr[1];
char* chararr2 = &chararr[2];
printf("chararr0地址為%#x\n",chararr0);
printf("chararr1地址為%#x\n",chararr1);
printf("chararr2地址為%#x\n",chararr2);
printf("chararr2與chararr0之間的距離為%d\n", chararr2 - chararr0);
system("pause");
}
#include
main(){
//在32位的操作系統上, 2的32次方個內存地址 4個byte
// 在我當前的32電腦操作系統上 用的devcpp工具, gcc
int i =3;
int* ip = &i;
double d = 3.14159;
double* dp = &d;
float f = 6.28f;
float* fp = &f;
short s = 255;
short* sp = &s;
//指針的長度都為4。
printf("int的指針長度為%d\n", sizeof(ip));
printf("double的指針長度為%d\n",sizeof(dp));
printf("float的指針長度為%d\n",sizeof(fp));
printf("short的指針長度為%d\n",sizeof(sp));
system("pause");
}
1、動態內存
動態內存創建在堆空間上的 一塊不連續的內存空間 可以占用整個操作系統的全部內存
堆內存就是操作系統維護的剩余的內存空間,
在java裡面new出來的的所有的對象都是分配在堆內存裡面。
在C語言裡面,申請堆內存空間使用malloc 函數。
malloc函數接受一個參數 ,參數代表動態的在堆內存申請多大的內存空間.
malloc的返回值 代表的是申請的這塊內存空間的首地址.
使用free(intp);函數釋放堆內存空間,將堆內存標記為可用。
例:申請堆內存空間:
#include
//引入動態內存分配的頭文件
#include
f(int** padress){
//*padress 拿到了主函數裡面的p變量
// 申請一塊內存空間 空間的大小為8個字節,空間的首地址把他賦給 intp的變量
int* intp = (int*)malloc(sizeof(int)*2);
*intp = 33; // 在堆內存申請的空間裡面放置一個int類型的值 值為33
*(intp+1) = 99; //
*padress = intp; //把堆內存的地址賦給 主函數裡面的p變量
//free(intp); //釋放堆內存空間,將堆內存標記為可用。
printf("子函數i的地址為%#X\n",intp);
}
main(){
int* p ;// 用來存放 子函數裡面的i變量的地址
//int -> int* ->int**
//在主函數裡面把子函數的i變量的地址給獲取出來
f(&p);
// 手動的回收掉申請的那塊內存空間
free(p); // 99 內存中的殘留的影像,或者幻影
printf("主函數i的地址%#X\n",p);
printf("主函數 i的值為%d\n",*p);
printf("主函數 第二個的值為%d\n",*(p+1));
system("pause");
}
2、靜態內存 創建在棧空間上的 一塊連續的內存空間 2M
3、動態內存優點:
動態內存可以跨函數使用,靜態函數不可以。
動態內存中數組的長度能在函數運行中動態增加或者縮小
動態的增加數組長度:使用reallco函數。
例:動態的增加數組長度:使用reallco函數:
#include
//引入動態內存分配的頭文件
#include
void printArr(int* arr , intlen){
int i;
for(i = 0; i
printf("學生編號%d的成績為%d\n",i,arr[i]);
}
}
main(){
printf("請輸入學生的總數\n");
int len;
scanf("%d",&len);
//根據len動態的創建一個數組
int* pgrade = malloc(sizeof(int)*len);
int i;
for(i=0;i
printf("請輸入學生%d的成績\n",i);
scanf("%d",(pgrade+i));
}
printf("打印學生的成績列表\n");
printArr(pgrade,len);
printf("請輸入增加學生的個數\n");
int addnumber;
scanf("%d",&addnumber);
pgrade = realloc(pgrade,sizeof(int)*(len+addnumber));
int j;
for(j=len;j<(len+addnumber);j++){
printf("請輸入新添加的學生%d的成績\n",j);
scanf("%d",(pgrade+j));
}
printf("重新打印學生的成績列表\n");
printArr(pgrade,len+addnumber);
system("pause");
}
1.申請方式
棧:
由系統自動分配.例如,聲明一個局部變量int b; 系統自動在棧中為b開辟空間.例如當在調用涵數時,需要保存的變量,最明顯的是在遞歸調用時,要系統自動分配一個棧的空間,後進先出的,而後又由系統釋放這個空間.
堆:
需要程序員自己申請,並指明大小,在c中用malloc函數
如char* p1 = (char *)malloc(10);
但是注意p1本身是在棧中的.
2 申請後系統的響應
棧:只要棧的剩余空間大於所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。
堆:首先應該知道操作系統有一個記錄空閒內存地址的鏈表,當系統收到程序的申請時, 會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內存空間。另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多余的那部分重新放入空閒鏈表中。
3.申請大小的限制
棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是2M(vc編譯選項中可以設置,其實就是一個STACK參數,缺省2M),如果申請的空間超過棧的剩余空間時,將提示overflow。因此,能從棧獲得的空間較小。
堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。
4.申請效率的比較:
棧:由系統自動分配,速度較快。但程序員是無法控制的。
堆:由malloc/new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便.
5.堆和棧中的存儲內容
棧:在函數調用時,第一個進棧的是主函數中後的下一條指令(函數調用語句的下一條可執行語句)的地址,然後是函數的各個參數,在大多數的C編譯器中,參數是由右往左入棧的,然後是函數中的局部變量。注意靜態變量是不入棧的。
當本次函數調用結束後,局部變量先出棧,然後是參數,最後棧頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。
堆:一般是在堆的頭部用一個字節存放堆的大小。堆中的具體內容有程序員安排。
6.內存的回收
棧上分配的內存,編譯器會自動收回;堆上分配的內存,要通過free來顯式地收回,否則會造成內存洩漏。
堆和棧的區別可以用如下的比喻來看出:
使用棧就像我們去飯館裡吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等准備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。
使用堆就像是自己動手做喜歡吃的菜肴,比較麻煩,但是比較符合自己的口味,而且自由度大。
public StringgetPersonName(Person p){
return person.getName();
}
p變量裡面存放的是一個 堆內存裡面person對象的地址. (值). // 感覺java是只有值傳遞。
p變量他代表的是person對象的一個引用, 引用傳遞.
例:使用r取到i的值:
#include
main(){
int i = 3;
int* p = &i;
int** q = &p;
int*** r = &q;
//取到i 的值
printf("i=%d\n",***r);
system("pause");
}
獲取函數的首地址,通過首地址,就可執行該函數。
例:
#include
/**
1.定義int (*pf)(int x, int y);
2.賦值 pf = add;
3.引用 pf(3,5);
*/
int add(int x, int y){
return x+y;
}
main(){
int (*pf)(int x,int y); // 定義一個函數的指針指針的類型是返回值為int 接受的參數 int
pf =add;
printf("result=%d\n", pf(3,6));
system("pause");
}
#include
//定義一個結構體
struct Student
{
char sex; //1
int age; //4
float score; //4
int id; //4
};
main(){
//
struct Student st={80,55.6f,10000,'F' };
//獲取結構體的指針
struct Student* pst = &st;
printf("age=%d\n",st.age);
//結構體的長度
printf("結構體的長度%d\n",sizeof(st));
//通過指針獲取結構體中的變量
printf("age=%d\n", (*pst).age);
//通過指針獲取結構體中的變量 的第二種寫法:
printf("age=%d\n", pst->age);
system("pause");
}
// 聯合體的作用是聲明一塊公用的內存空間,長度跟公用的數據類型中最長的一個條目一致,
當多次為同一個聯合體賦值時,會覆蓋:
#include
main( )
{
struct date { int year, month, day;}today;
union { long i; int k; char ii; } mix;
// 聯合體的作用是聲明一塊公用的內存空間
// 長度跟公用的數據類型中最長的一個條目一致
printf("date:%d\n",sizeof(struct date));
printf("mix:%d\n",sizeof(mix));
//下面的賦值,先定義的會被覆蓋。
mix.i = 99;
mix.k = 18;
mix.ii = 'A';
printf("i=%ld",mix.i);
system("pause");
}
#include
enum WeekDay
{
Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
};
int main(void)
{
//int day;
enum WeekDay day = Sunday;
printf("%d\n",day);
system("pause");
}
聲明自定義數據類型,配合各種原有數據類型來達到簡化編程的目的的類型定義關鍵字。
typedef int haha;//聲明一個int型的數據類型
例:
#include
typedef int haha;
int main(void)
{
haha i = 3;
printf("%d\n",i);
system("pause");
return 0;
}