1.1 數(shù)據(jù)類型本質(zhì)分析
1.1.1 數(shù)據(jù)類型概念
- “類型”是對(duì)數(shù)據(jù)的抽象
- 類型相同的數(shù)據(jù)有相同的表示形式、存儲(chǔ)格式以及相關(guān)的操作
- 程序中使用的所有數(shù)據(jù)都必定屬于某一種數(shù)據(jù)類型
1.1.2 數(shù)據(jù)類型的本質(zhì)
- 數(shù)據(jù)類型可理解為創(chuàng)建變量的模具:是固定內(nèi)存大小的別名。
- 數(shù)據(jù)類型的作用:編譯器預(yù)算對(duì)象(變量)分配的內(nèi)存空間大小。
- 注意:數(shù)據(jù)類型只是模具,編譯器并沒有分配空間,只有根據(jù)類型(模具)創(chuàng)建變量(實(shí)物),編譯器才會(huì)分配空間。
#include < stdio.h >
int main(void)
{
int a = 10; //告訴編譯器,分配4個(gè)字節(jié)的內(nèi)存
int b[10]; //告訴編譯器,分配4*10 = 40 個(gè)字節(jié)的內(nèi)存
printf("b:%p, b+1: %p, &b:%p, &b+1: %pn", b, b + 1, &b, &b + 1);
//b+1 和 &b+1的結(jié)果不一樣 (+1 --- > +4; +1 --- > +40)
//是因?yàn)?b 和 &b 所代表的數(shù)據(jù)類型不一樣
//b 代表數(shù)組首元素的地址
//&b 代表整體數(shù)組的地址
return 0;
}
- b+1 和 &b+1的結(jié)果不一樣 (+1 ---> +4; +1 ---> +40)
- 是因?yàn)?b 和 &b 所代表的數(shù)據(jù)類型不一樣
- b 代表數(shù)組首元素的地址
- &b 代表整體數(shù)組的地址
1.1.3 數(shù)據(jù)類型的別名
① 給數(shù)據(jù)類型起別名
#include < stdio.h >
typedef unsigned int u32; //給unsigned int類型取別名
int main(void)
{
u32 a;
a = 10;
return 0;
}
② 給結(jié)構(gòu)體類型起別名
#include < stdio.h >
#define pi 3.14
////////// 正常使用結(jié)構(gòu)體 //////////
struct People
{
char name[64];
int age;
};
//////// 給結(jié)構(gòu)體類型起別名 ////////
typedef struct People_2
{
char name[64];
int age;
} people_t;
int main(void)
{
////////// 正常使用結(jié)構(gòu)體 ///的初始化///////
struct People p1;
//////// 給結(jié)構(gòu)體類型起別名 /的初始化///////
people_t p2;
p1.age = 10;
p2.age = 11;
return 0;
}
1.1.4 數(shù)據(jù)類型之 void
1、函數(shù)參數(shù)為空,定義函數(shù)時(shí),可以用void修飾: int fun(void)
2、函數(shù)沒有返回值: void fun(void);
3、不能定義vold類型的普通變量, vold a; //err,無法確定類型,不同類型分配空間不一樣
4、可以定義vold 變量: * void ; //ok, 32位是4字節(jié),64位是8字節(jié) *
5、數(shù)據(jù)類型本質(zhì):固定內(nèi)存塊大小別名
6、void和萬能指針,函數(shù)返回值,函數(shù)參數(shù)
- void的字面意思是“無類型”,void *則為“無類型指針”,void *可以指向任何類型的數(shù)據(jù)。
- void * memcpy(void *dest, const void *src, size_t len);void指針的意義
7、void指針的意義
- C語言規(guī)定只有相同類型的指針才可以相互賦值
- void*指針作為左值用于“接收”任意類型的指針
- void*指針作為右值賦值給其它指針時(shí)需要強(qiáng)制類型轉(zhuǎn)換
- int *p1 = NULL;
- char *p2 = (char *)malloc(sizoeof(char)*20);
1.2 變量的本質(zhì)分析
1.2.1 變量的概念
概念:既能讀又能寫的內(nèi)存對(duì)象,稱為變量。
#include < stdio.h >
#include < stdlib.h >
int main(void)
{
int i = 0;
// 通過變量直接操作內(nèi)存
i = 10;
int *p = &i;
printf("&i:%dn", &i);
printf("p:%dn", p);
// 通過內(nèi)存編號(hào)間接操作內(nèi)存
*p = 100;
printf("i = %d, *p = %dn", i, *p);
system("pause");
return 0;
}
1.3 程序的內(nèi)存四區(qū)模型
1.3.1 全局區(qū)(全局變量、靜態(tài)變量(const,constant或final等)、文字常量區(qū))
#include
char * getStr1()
{
char *p1 = "abcdefg2";
return p1;
}
char *getStr2()
{
char *p2 = "abcdefg2";
return p2;
}
int main(void)
{
char *p1 = NULL;
char *p2 = NULL;
p1 = getStr1();
p2 = getStr2();
//打印p1 p2 所指向內(nèi)存空間的數(shù)據(jù)
printf("p1:%s , p2:%s \n", p1, p2);
//打印p1 p2 的值
printf("p1:%p , p2:%p \n", p1, p2);
return 0;
}
問題:內(nèi)容一致, 為什么兩個(gè)指針的地址值也是一樣的?
① 程序執(zhí)行到 int main(void)
② 程序執(zhí)行到 char *p1 = NULL; char *p2 = NULL;
③ 程序執(zhí)行到 getStr1() 由于個(gè)人原因在全局區(qū)中應(yīng)該為“abcdefg1?”
④ 程序執(zhí)行到 p1 = getStr1(); 由于個(gè)人原因在全局區(qū)中應(yīng)該為“abcdefg1?”
⑤ 程序執(zhí)行到 p2 = getStr2(); 由于個(gè)人原因在全局區(qū)中應(yīng)該為“abcdefg1?”
因?yàn)樽址兞渴且恢碌模圆]有重新放在另一個(gè)內(nèi)存區(qū)域,用的是同一個(gè)。
另注意:
打印p1 p2 所指向內(nèi)存空間的數(shù)據(jù)
printf("p1:%s , p2:%s n", p1, p2);
打印p1 p2 的值
printf("p1:%p , p2:%p n", p1, p2);
1.3.2 棧區(qū)(棧區(qū)(stack) :① 由編譯器自動(dòng)分配釋放,存放函數(shù)的參數(shù)值,局部變量的值等。② 函數(shù)運(yùn)行時(shí)分配,函數(shù)結(jié)束時(shí)釋放。由編譯器自動(dòng)分配釋放 ,存放為運(yùn)行函數(shù)而分配的局部變量、函數(shù)參數(shù)、返回?cái)?shù)據(jù)、返回地址等。)
#include < stdio.h >
char *get_str(void)
{
char str[] = "abcdedsgads"; //str在棧區(qū),字符常量在全局區(qū)
printf("在子函數(shù)中:str = %sn", str);
return str;
}
int main(vo1d)
{
char *p = NULL;
p = get_str();
printf("在主函數(shù)中:p = %sn",p);
printf("n");
system("pause");
return 0;
}
請(qǐng)問打印出來的內(nèi)容一致嗎?為什么不一致?
① 程序執(zhí)行到 get_str(); 包括第一次打印,到此都是正常的。
② 程序執(zhí)行到 p = get_str(); 講數(shù)組的首地址賦值給p,到此也是正常的。
③ 程序運(yùn)行完 p = get_str(); 還未運(yùn)行 printf("在主函數(shù)中:p = %sn",p);時(shí)
注意此時(shí)的變化:棧區(qū)(stack) :① 由編譯器自動(dòng)分配釋放,存放函數(shù)的參數(shù)值,局部變量的值等。② 函數(shù)運(yùn)行時(shí)分配,函數(shù)結(jié)束時(shí)釋放。由編譯器自動(dòng)分配釋放 ,存放為運(yùn)行函數(shù)而分配的局部變量、函數(shù)參數(shù)、返回?cái)?shù)據(jù)、返回地址等。
④ 程序運(yùn)行至打印 打印出來了亂碼
1.3.3 堆區(qū)(heap) : 一般由程序員分配釋放(動(dòng)態(tài)內(nèi)存申請(qǐng)與釋放),若程序員不釋放,程序結(jié)束時(shí)可能由操作系統(tǒng)回收。
接著棧所說的內(nèi)容,我們?cè)撊绾稳〕鲞@一串字符呢?
#include < stdio.h >
#include < String.h >
char *get_str(void)
{
char *p1 = NULL;
p1 = (char *)malloc(100);
if (p1 == NULL)
{
return NULL;
}
strcpy
(p1,"adsagldsjg1k");
return p1;
}
int main(vo1d)
{
char *p = NULL;
p = get_str();
if (p != NULL)
{
printf("在主函數(shù)中:p = %sn",p);
free(p);
p = NULL;
}
printf("n");
system("pause");
return 0;
}
① 程序運(yùn)行至 char *p = NULL;
② 程序運(yùn)行至 get_str(); 中的 char *p1 = NULL;
③ 程序運(yùn)行至 p1 = (char *)malloc(100);
④ 程序運(yùn)行到 strcpy(p1,"adsagldsjg1k");
⑤ 程序運(yùn)行到 p = get_str();
⑥ 程序運(yùn)行到 printf("在主函數(shù)中:p = %sn",p);
⑦ free(p); 只是解除了程序?qū)τ诙褏^(qū)地址0x20的使用權(quán),并沒有將0x20處的數(shù)據(jù)清除。
1.4 函數(shù)的調(diào)用模型
1.5 棧的生長(zhǎng)方向和內(nèi)存存放方向
#include < stdio.h >
int main(void)
{
int a;
int b;
char buf[4];
printf("&a: %pn", &a);
printf("&b: %pn", &b);
printf("buf的地址 : %pn", &buf[0]);
printf("buf+1地址: %p n", &buf[1]);
return 0;
}
評(píng)論
查看更多