1標準輸入輸出頭文件的意義?以及main函數的作用?
<>系統頭文件、””自定義頭文件。引入系統的標準頭文件,可以用其中的一些函數,如printf();
main函數是C語言程序的入口(開始執行的位置),{}表示main函數的起止點
2怎樣理解註釋增強代碼的可讀性和可維護性?
//、/**/對代碼的解釋說明
3C語言中有哪些基本的數據類型,佔的字節數,以及格式化的描述形式?
char 、signed char 、unsigned char 、bool 1 %c
short 、unsigned short 2 %hd
int 、float 、unsigned int 4 %d 、%f
double、 long int 、unsigned long 8 %lf 、%ld
sizeof(數據類型名) 求某種類型的字節數
4變量的本質,變量的命名規則,以及變量初始化的方式?
本質:內存裏的存儲單元。開闢空間、往空間裏面寫內容、從空間裏面讀取內容
命名規則:每個變量必須以字母和下劃線開頭,由字母下劃線數字組成
大小寫是兩個不同的字符
不能用C的關鍵字做變量名
初始化:聲明同時進行初始化、先聲明然後在運行時使用賦值表達式初始化、先聲明然後用戶輸入數值進行初始化
5什麼是常量,它的意義?
在變量前面加上const關鍵字,成爲常量。
常量的值必須在創建的同時初始化,且一經初始化就不能改變
6怎樣聲明一個枚舉類型,如何使用,枚舉如何代替宏定義?
enum weekday {Mon, Tue, Wed,Thr, Fri, Sat, Sun } a, b, c;
enum 關鍵字,weekday枚舉名,a,b,c 枚舉變量名
{ , ,}表示這種類型可能取的值,每個值對應一個整數,從0開始,依次加1;
1、enum weekday
{
…
}; //沒有定義變量
enum weekday a, b, c; //可以用這種方法定義
2、enum weekday
{
…
}a,b,c; //可以增加e, f, g等變量
3、enum
{
…
}a, b, c; //沒有枚舉類型名,只能有abc三個變量
{ ,}表示這種類型可能取的值,每個值對應一個整數,從0開始,依次加1;
可以代替整型的宏定義,增強代碼可維護性;
枚舉是封裝好的define集合,用便於記憶的字符來代表常量,枚舉類型實質是整型變量,通過枚舉類型將一類有關聯的標識組合起來,增加程序的可讀性和可維護性
枚舉變量可以用在switch語句中作爲常量使用;使用枚舉變量時,應該把枚舉變量的值賦值爲枚舉中常量集合中某個常量的值
7定義初始化一個數組,用下標訪問數組
int a[5];
int a[ ]={1, 2, 3, 4};
int a[5]={1, 2, 3, 4};
8大數分解
萬 12345/10000
千 12345/1000%10 == 12345%10000/1000
百 12345/100%10 == 12345%1000/100
十 12345/10%10 == 12345%100/10
個 12345%10
9 怎麼樣理解前置(後置)自增自減?
當需要使用自增自減的值時,考慮其是前置還是後置
前置:++i 先進行自增自減,再使用增減後的值
後置:i-- 先使用變量當前的值,然後再進行自增自減運算
10怎樣使用&& ||?
與、全真爲真,有假則假
或、全假爲假,有真則真
非、非真爲假,非假爲真
11條件表達式
if()
…
else if ()
…
else
…
12隱式和顯示類型轉化?
當某一個操作符擁有不同類型的操作數時,將發生類型轉換
顯式:(數據類型名) 變量名 float i = 1.23; int j = (int) i;
i的類型依然是float,只是把i的整數部分賦給了j
隱式:char c = ‘a’; int i = c;
賦值表達式,把等號右邊的類型,轉型爲等號左邊的類型;
在一個表達式中,默認狀態下變量是從低類型向高類型轉化的
13控制流
順序結構:按照語句編寫的順序順序執行
;是語句結束的標誌;{}被用在程序塊中,其右側括號後面不加分號;任何可以放置單個語句的地方,都可以用一個複合語句來代替
選擇結構:if:條件爲真時,執行語句,否則跳過不執行
if-else:條件爲真時執行if分支語句,否則執行else分支語句(嵌套)
switch:根據條件表達式的值,執行多個動作當中的某一個動作
switch (…) //表達式或者變量,必須返回整數型(包括字符型)
{
case 1: …;break; case:… 必須是常量表達式,且不允許重複
case 2: …;break;
default: …; break;
}
循環結構:while:首先初始化循環控制變量while(…//條件爲真) {…//進入循環體;改變循環控制變量}
do/while:後置測試循環,先循環一次,再測試條件 do{…循環體;修改循環控制變量}while (表達式)//控制變量不需要初始化
for:前置測試循環,先測試條件是否滿足,若滿足再進入循環體執行 for(循環控制變量初始化;條件表達式,爲真則執行循環體語句;修改循環控制變量) {…循環體語句} à首先初始化循環控制變量,然後執行條件表達式,爲真則執行循環體語句,然後改變循環控制變量,再執行條件表達式,爲真則執行循環體語句。。。直到條件表達式爲假
14break,continue, return作用?
break:結束循環,執行循環後面的語句;多層循環只跳出break所在這一層循環;跳出switch結構
continue:跳過本次循環而執行下次循環
return:退出該函數的執行(跳出函數)
15函數作用
可以多人合作開發
單元測試,有利於早發現bug
複用性
16怎樣封裝函數,函數調用的實質;
封裝函數:main.c中需包含自定義的調用函數的頭文件;調用函數頭文件聲明調用函數原型;調用函數.c文件定義、實現調用函數
實質:
17函數的值傳遞
傳值方式,在函數調用時,把實參值的一份拷貝賦值給形參
在被調用函數體內,操作和修改的是形參的值,實參的值不受影響
單向傳遞,從實參到形參
18指針實質,指針訪問變量,指針的類型,野指針,空指針,手動開闢內存空間
指針也是一個變量,它的值是另外一個變量的地址,即指針是存放內存地址的變量
指針類型與它指向的變量的類型保持一致
char *p = &achar; //p指針變量名;*表示p是一個指針變量;&取地址運算符,返回變量地址;char*指針變量的類型,p是一個字符型指針,char代表指針指向的變量的類型;%p打印地址,打印指針變量的值;指針是long int,8個字節
解引用運算符,*p:放等號右邊,讀取p指向的變量的值;左邊,給p指向的變量寫入內容
如果定義一個指針沒有初始化,它存儲的是垃圾地址,即爲野指針
當定義一個指針還不確定指向哪個變量,就把它置爲空,空指針是被初始化爲NULL的指針,裏面的地址是0(不要解引用空指針,因0號地址屬於系統級內存空間,不允許用戶級程序訪問)
int * p = (int *) malloc(sizeof(int));
free(p);
19傳地址,傳指針,返回指向局部變量的指針(解決方案),函數返回值
int exchange(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int aa=1,bb=2;
指針int p = &aa, *q = &bb;
指針exchange(p, q);
地址exchange(&aa, &bb);
printf(“..”);
}
111、定義全局變量*p,開闢堆空間,主函數回收開闢的堆上的內存空間
#include <stdio.h>
#include <stdlib.h>
int *p=NULL;
int *Test()
{
p=(int *)malloc(sizeof(int));
*p=10;
return p;
}
int main()
{
int c=*Test();
printf("%d\n",c);
free(p);
return 0;
}
222、static
#include <stdio.h>
int *Test()
{
static int temp=12; //加static定義到靜態存儲區,不加則聲明局部變量,調用函數結束時內存回收
return &temp; //不能返回一個指向局部變量的指針
}
int main()
{
int c=*Test();
printf("%d\n",c);
return 0;
}
20內存分配問題
逐步分析
全局變量:在所有函數體之外聲明的變量,作用於所有源文件,全局區
靜態全局變量:不可用於其他文件
靜態局部變量
局部變量:棧(形參放在棧上)
堆:手動開闢的內存空間
靜態存儲區:變量前加static,生命週期很長,從申請到程序退出
21怎樣用指針訪問數組?
數組元素在內存空間中連續分佈,每個元素有相應的內存地址;數組名就是數組首地址,就是指向數組首元素的指針,即a == &a[0];數組名是個指針常量,存儲的地址是不能更改的
p = a; 或 p = &a[0]; 則a[1]==*(p+1);
22指針運算和數組?
#include <stdio.h>
int main()
{
char a[8];
int b[8];
float c[8];
char *pa = a + 1;
int *pb = b + 4;
float *pc = c +6;
printf("%p,%p\n",a,pa);
printf("%p,%p\n",b,pb);
printf("%p,%p\n",c,pc);
printf("%ld,%ld,%ld\n",pa-a,pb-b,pc-c); //1,4,6
printf("%ld,%ld,%ld\n",sizeof(pa-a),sizeof(pb-b),sizeof(pc-c)); //8,8,8
return 0;
}
23指針常量的使用
#include <stdio.h>
int main ()
{
const int a=9;//常量,定義時要初始化
//a=9; 常量初始化後不能修改,即使賦相同的值也不行
const int aa = 99;
int b = 10;
int c = 11;
//int pp=&b;
int * const p = &b;
//p=pp; 指針常量初始化後不能修改,即使賦相同的值也不行
//p=&c; 不同的值更不行
printf("%d\n",*p);
const int *q = &a; //指向常量的指針,這個指針最好要指向一個常量
q= &b; //也可以指向變量
printf("%d\n",*q);
q=&aa; //指向常量的指針,也可以指向其他常量
printf("%d\n",*q);
return 0;
}
int* const p = &a; //必須在聲明時初始化,且指針常量的值不能再修改,即不能存一個新的地址,不能指向別的變量,但是可以通過指針常量修改它所指向的變量的值
24指向常量指針的使用?
const int a = 1;
const int *q = &a; //指向常量的指針,這個指針指向一個常量
q = &b; //也可以指向變量或者其他常量
25全局變量,函數域,塊域
標識符:變量名、函數名
作用域:能夠訪問某標識符的程序段
全局變量:在所有函數體之外聲明的變量,作用於所有源文件,全局區
局部變量
函數域:標識符只能在它所在的函數被訪問到
函數形參:函數實現時形參的名字可以和函數原型形參名字不同;但類型要一致。函數原型的形參的作用域,只限於函數原型本身
塊域:被大括號{}包圍的範圍叫塊;其作用域:從標識符開始到塊結束,可以被識別
當在塊內部聲明瞭一個與外部標識符同名的標識符時,外部標識符可以被臨時隱藏
就近原則:若有同名標識符,優先使用同一作用域內的標識符
如果想訪問被臨時隱藏的全局變量,要使用全局域操作符::
26鏈接編譯理解
預處理 編譯 鏈接
預處理階段,編譯器以C文件作爲一個單元,首先讀這個C文件,發現包含頭文件,就會在所有搜索路徑中尋找文件,找到之後,就會將相應頭文件中再去處理宏,變量,函數聲明,嵌套的頭文件包含等,檢測依賴關係,進行宏替換,看是否有重複定義與聲明的情況發生,最後將那些文件中全部掃描進這個當前的C文件中,形成一箇中間"C文件"
編譯階段,將中間C文件的所有變量,函數分配空間,將各個函數編譯成二進制碼,按照特定目標文件格式生成目標文件,在這種格式的目標文件中進行各個全局變量,函數的符號描述,將這些二進制碼按照一定的標準組織成一個目標文件
連接階段,將上一步生成的各個目標文件,根據一些參數,連接生成最終的可執行文件,主要的工作就是重定位各個目標文件的函數,變量等,相當於將個目標文件中的二進制碼按一定的規範合到一個文件中
想在多個文件中訪問一個變量,就要在變量前面加上extern關鍵字
27怎樣使用函數指針
函數指針的類型就是指針指向的函數的參數類型和返回值類型
int ( *fp) (int a, intb); //聲明一個函數指針
int func (int m, intn); //聲明一個函數
fp = func; 或 fp = &func;
28字符串和字符數組的區別
字符串:用雙引號包圍 “abcde”
字符數組:數組的每一個元素都是字符,字符用單引號包圍
在內存裏用字符數組存儲字符串,字符數組要加一個元素,以空字符\0作爲結尾
定義:字符串就是存入字符的數組,以’\0’作爲結束標誌,%s輸出
區別:字符串用字符數組存儲,但是字符數組不需要有結束標誌’\0’,字符串需要
29怎樣拷貝一個存在靜態常量區的字符串
char c[6] = “hello”; //聲明之後,首先在靜態存儲區的常量區開闢一塊空間,寫入hello,然後開闢一塊連續的棧空間,把字符串拷貝一份,然後將內容寫入到棧空間,c本身是個變量,所以可以通過c修改他所指向的內存的值
可以把一個字符串賦值給一個char * 類型的指針,但不能通過指針修改這個字符串
char *str = "I am astudent";
//const char *str = "Iam a student";
//把一個字符串賦給一個字符指針,相當於賦給一個指向字符常量的指針
str = "sun"; //可以,改變地址,指向sun
//strcpy(str,"abcde");//錯誤,改變值
30使用strcpy strcmp strcatstrlen等字符串函數的操作
strlen (length) 返回字符串的字符數(長度),不包括\0
strcat (to, from) ,把from”…”連接到to”…”的結尾
strcpy (to, from) ,把from”…”copy到to”…”
strcmp (s1, s2) s1 > s2,返回正數s1 < s2,返回負數s1 = s2,返回0
兩個字符串從前到後,逐個比較每對字符的ASCII碼的大小;若相同,則繼續比較,直到遇到第一對不同的字符,ASCII碼整數大的字符爲大
31 起別名的語法規範
typedef type IDENTIFIER 關鍵字 已有類型 類型別名,一般全大寫字母
typedef unsigned int UN;
用來代替自定義的枚舉類型、結構體類型、系統定義的長度較長的類型
32 聲明結構體類型的變量的兩種主要形式,以及初始化
//111
struct //直接定義結構體變量,結構體本身沒有名字
{
char name[15];
int num;
int age;
}Astu; //結構體變量的聲明,必須緊跟在結構體定義的後面
//222
struct student //結構體類型,類型名爲struct student
{
char name[15];
int num;
int age;
}Bstu; //可以在這裏聲明結構體變量
struct student Cstu; //也可以用結構體類型名,聲明一個結構體變量
//333
typedef struct //給結構體類型起一個別名 STU
{
char name[15];
int num;
int age;
}STU; //結構體別名
STU Dstu; //通過別名,聲明結構體變量
>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<
STU Dstu = {…, …, …};
33 結構體類型的指針訪問結構體類型的變量
訪問:p = &Astu; Astu.name p -> num (*p).age
34 如何計算結構體類型的變量在系統內存裏佔用的字節數
結構體的值從上往下依次分配,先找到最大字節的變量,然後依次從上到下分配內存,當分配到相應類型時,圖中編號一定要能整除當前類型字節數。(大小要能被每一種類型大小整除)
char a[10]; //0—9
int b; //12—15
char c; //16
double a; //24—31
double 最大,8字節,以8字節爲單位畫內存分配:
0 1 2 3 4 5 6 7
8 9 10 11 12 13 14 15
16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31
<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>><<<<<<<>>>>>>>>>
int a; //0—3
fioat b; //4—7
char c[15]; //8—22
0 1 2 3
4 5 6 7
8 9 1011
12 13 14 15
16 17 18 19
20 21 22 23
24 25 26 27
35宏替換
#define N 10 //預處理階段,源代碼裏所有的N將被替換成10
#define max(a,b) ((a) >(b) ? (a) : (b)) //宏替換的參數都要加上括號
#define exchange ( x, y)\
{\
int temp = *x;\
*x = *y;\
*y = temp;\
} //替換自定義函數,除最後大括號的結束行,其餘的都要加上”\”
36條件包含
#if 。。。 //如果爲真,則包含後面內容,直到#endif、#elif、#else結束
#ifndef XXX
#define XXX
……
#endif //避免重複定義同一個頭文件
#ifdef XXX //如果宏定義了XXX,執行下面語句
……
#else //否則,執行else下面語句
……
#endif
#ifndef XXX //如果沒有宏定義XXX,執行下面語句
……
#else //否則,執行else下面語句
……
#endif