(1)char
字符類 char 既可以是 整數 類型,也可以是 字符 類型。z字符 類型可以轉化為對應的ASC2值。
int main(){char c;char e;c = 1;char d = '1';e = 'A';printf("c = %d\n", c);printf("d = %d\n", d);printf("e = %d\n", e);return 0;
}輸出:
c = 1 // 表示整數類型
d = 49 // 表示字符類型, 字符'1'對應ASCll碼的值是 49
e = 65 // 表示字符類型, 字符'A'對應ASCll碼的值是 65
int main(){char c;printf("Enter an integer輸入一個整數: ");//integer 整數scanf("%c", &c);printf("int = %d\n", c);printf("char = %c\n", c);return 0;
}輸出:
Enter an integer輸入一個整數: 1
int = 49
char = 1
int main(){if(49 == '1'){printf("ASC2 49 == char '1'\n");}else{printf("ASC2 49 != char '1'\n");}return 0;
}輸出:
ASC2 49 == char '1'
scanf里有空格,表示讀的空格不算做字符;沒加空格時,空格就算做字符
(2)printf和scanf
對與printf,任何小于int的類型都會被轉換成int,所以char和short會自動轉成int。比如%f就可以變成double;
對于scanf,就必須按照輸入的內容明確。比如short就用%hd,int就用%d,long long就用%ld,想輸入整數char就不行,必須先int后再轉成char類型。
(3)強制類型轉換
最后要轉成:? ? ? ?(類型名稱)值
int main(){double a =1.0;double b = 2.0;int i = (int)(a/b);printf("%d\n", i);
}輸出:
0
(4)逃逸字符
比如 \" 表示雙引號,因為在 " " 里面不能直接加雙信號以引起歧義,所以用逃逸字符,類似的有:
(5)邏輯運算
age > 20 && age < 30 age < 20 || age > 30
表示 20 < age < 30 表示 age小于20或者age大于30
運算符優先級:
! > && > ||
(6)函數定義
函數的返回1個return
方式1:
return;
方式1:
return 某表達式或者變量 ;
函數的返回多個return
int max(int a, int b){if (a>b){return a;}else{return b; }
}
(7)沒有返回值的函數
(1)void + 函數名
(2)不能使用return
(3)調用不能做返回值的賦值。
(8)函數的原型聲明和函數的定義
函數原型的目的是告訴編譯器這個函數長什么樣子,內容包括: 返回類型? ? 名稱? ? 參數
void sum(int begin, int end); //函數的原型
或者void sum(int, int); void sum(int begin, int end){ //函數的定義int i;int sum = 0;for (i = begin; i <= end; i++){sum += i;}
}
(9)函數的參數傳遞
(1)只能傳值,不能傳變量。比如下圖中main里的變量a和b與swap函數在內部運行時的a和b和t之間是獨立的,不會互相傳遞。
swap(a<b){int = 10;
}
i++; // 會報錯因為前面的i在走出swap()代碼塊后就不再存在
(2)本地變量是定義{}內或者函數內,在這個代碼塊之前不作數,出了這個代碼塊也不再作數。
(3)代碼塊外面定義的變量在里面依然有效。另外相同變量名稱,在代碼塊內就近,但出了塊后還是恢復之前的情況。
i = 10;
swap(){int i = 0;printf("%d", i); // 輸出 0
}
printf("%d", i); // 輸出 10
(10)定義數組
格式:
數組內元素類型 變量名稱[元素的數量]
int grades[100];
特點:(1) 所有元素具有相同數據類型;(2) 不能改變大小;(3) 元素在內存中連續排列;(4)可使用的元素范圍是[0 , 數據大小 - 1?]。
題目:輸入數量不確定的[0, 9]范圍內的整數,統計每一種數字出現的次數,輸入-1表示結束。
int main(){int num[10]; // int num[10] = {0}; int j = 0;for (j = 0;j < 10; j ++){num[j] = 0;}int n = 0;while(1){int input;printf("input number between 0 and 9\n");int count = scanf("%d", &input);if (input < 0 || input > 9 || count == 0){continue;}printf("input finish\n");num[input] = num[input]+1;printf("input number: %d\n", input);int i = 0;for (i = 0;i < 10; i ++){printf("count of %d: %d\n", i,num[i] );}}return 0;
}
(11)數組的大小(數組元素個數)
(1) 利用sizeof
由于int是4字節,以及sizeof(數組)是字段的長度,可得數組大小為:? sizeof(a) /? sizeof(a[0])。
但是當 數組 作為函數函數時,不能利用siezeof來計算數組的元素個數。
int a[6] = {2,4,5,6,7,8};
int b = sizeof(a);
printf("%d\n", sizeof(a)/sizeof(a[0]));輸出:
6
int a[6] = {2,4,5,6,7,8};
int b = sizeof(a);
printf("%d\n", b);輸出:
24
(11)數組的賦值
數組變量不能直接被復制,比如下面這個不對
int a[] = {2,4,5};
int b[] = a
這是不對的
而是通過每個元素的賦值實現
for (i = 0; i < length; i++){b[i] = a[i];
}
(12)二維數組
int a[3][5]? ? ?表示為a是一個3行5列的矩陣
a[0][0] ... a[0][4]...
a[2][0] ... a[2][4]
(13)二維數組的遍歷
for (i =0; i< 3; i++){for (j =0; j < 5; j++){a[i][j] = i*j;}
}
(14)(&) 變量的地址
比如scanf("%d", &i);
int i; printf("%p", &i); //獲取變量地址
// %p表示輸出地址
// %lu的含義:long unsigned數據類型無符號長整數或無符號長浮點數
在堆棧里分配內存:地址分配順序是由高位到低位,先寫的地址更高,后寫的地址更低。
對于電腦小端模式結構,導致數據的低位在內存低地址處,高位在地址高位處。
最左位為最高權位。相應的,最右邊就是最低位。
(15)指針的值
指針就是保存地址的變量,指針變量的值就是內存的地址。p表示指針,*表示p這個指針指向的是int類型的變量,然后把i的地址交給p。*p是int。
(1) 普通變量的值是實際的值;(2) 指針變量的值是具有實際值的變量的地址。
(3) 傳值,如壁虎斷尾;傳地址,跑得了和尚跑不了廟。
int i;
int * p = &i;
// p表示指針,*表示p這個指針指向的是int類型的變量
void f(int *p);
void f(int *p){print("*p = %p\n", *p);*p = 26;
}int main(){int i = 6;f(&i);g(i);return 0;
}輸出:
&i = 0x7ffc94b0756cp = 0x7ffc94b0756c
(16)*指針(*p)
p是變量i的指針,p的值就是i的地址,*p用來訪問變量i的值。
int k = *p;
*p = k+1;
void f(int *p);
void g(int k);
void f(int *p){printf("p = %p\n", p);*p = 26;
}
void g(int k){printf("k = %d\n", k);
}int main(){int i = 6;f(&i);g(i);return 0;
}輸出:在經過了f()函數通過指針變量修改i的值后,變量i的值被修改了,p的值就是i的地址。
p = 0x7ffca728651c
k = 26
(17)指針應用1:交換變量的值
swap()函數,交換2個變量的值
void swap(int *pa, int *pb);{int t = *pa;*pa = *pb;*pb = t;
}
void swap(int *pa, int *pb); // 聲明函數
void swap(int *pa, int *pb){ // 定義函數int t;t = *pa;*pa = *pb;*pb = t;
}int main(){int a = 5;int b = 6;printf("a = %d, b = %d\n", a, b);swap(&a, &b);printf("a = %d, b = %d\n", a, b); return 0;
}輸出:
a = 5, b = 6
a = 6, b = 5
(18)指針應用2:函數返回多個值
找出最小值和最大值
void minmax(int a[], int len, int *min, int *max);
void minmax(int a[], int len, int *min, int *max){int i =0;*min = a[0];*max = a[0];for (i = 0; i < len; i ++){if (*min > a[i]){*min = a[i];}if (*max < a[i]){*max = a[i];}}printf("min value is %d, max value is %d\n", *min, *max);
}int main(){int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 16, 17, 21, 23, 55};int min, max;minmax(a, sizeof(a)/sizeof(a[0]), &min, &max);return 0;
}輸出:
min value is 1, max value is 55
(19)指針應用3:函數參數里的數組就是指針
函數參數里的數組就是指針,數組的指針里寫什么也沒用。下面的數組a[]就是指針,所以也可以直接寫成*a
void minmax(int a[], int len, int *min, int *max);void minmax(int *a, int len, int *min, int *max);
(1) int a[10]; int *p = a; //無需用&取地址
(2) 但是數組的單元表達的是變量,需要用&取地址
(3) []運算符可以對數組做,也可對指針做,都可以表示為:
*p == p[0]
p既可以是數組,也可以是指針
(4) 數組變量是const的指針,所以兩個數組之間不能直接做賦值。可以用指針進行處理 *p
int a[] <==> int * const a
(20)指針與const(*const就是指針是const)
指針q是const
int * const q = &i; // q是const,也就是說q只能是指向i的地址
*q = 26; // q指向的地址,也就是變量i的值是26
q++ // ERROR
不能通過*p修改變量i的值
const int *p = &i;
*p = 26; // ERROR (*p)是const
i = 26; // OK
p = &j; // OK
const在*后表示指針不能被修改
int i;
int *const p = &i
const在*前表示不能通過指針修改變量的值
int i;
const int *p = &i;
int const *p = &i;
(21)指針運算
指針元素是sizeof的運算,比如指針p的int類型指針就是4的倍數,char類型指針就是1的倍數。
而*(p)的括號里的元素就取對應數組(由于是sizeof()的運算,所以int和char都是相同的結果),比如*p = a,則*(p+n) = a[n]。
int main(){
char ac[]= {2,3,4,5,6,7,8,9,0,11};
char *p = &ac[0];
char *p1 = &ac[5];
printf("p = %p\n", p);
printf("p1 = %p\n", p1);
printf("p1 - p = %p\n", p1 - p);int ai[]= {2,3,4,5,6,7,8,9,0,11};
int *q = &ai[0];
int *q1 = &ai[5];
printf("q = %p\n", q);
printf("q1 = %p\n", q1);
printf("q1 - q = %p\n", q1 - q);
}輸出:
p = 0x7ffcb70513e6
p1 = 0x7ffcb70513eb
p1 - p = 0x5
q = 0x7ffcb70513b0
q1 = 0x7ffcb70513c4
q1 - q = 0x5
(21)指針運算的應用:*p++
用于數組類的連續空間操作:取出p所指的數據,之后再把p移到下個位置。
char ac[] = {0,2,4,1,5,9};
char *p = ∾
while (p != -1){printf("%d\n", *p++)
}輸出ac[]數組中的每個元素
(22)指針類型強制轉換
int *p = &i;
void * q = (void *)p;
通過指針p看i,i是int類型;而通過q看i,當i是void
(23)總結指針作用
(1) 需要傳入較大的數據時用作參數。比如,對數組的操作。
(2) 動態內存分配,以及釋放內存
int *a = (int*)malloc(n*sieze(int));
for (i = 0; i < n; i++){scanf("%d", &a[i]);
}
for (i =n-1, i>=0, i--){printf("%d", a[i]);
}
free(a);
(24)字符串特點
(1) 以“\0”結尾的一串字符,比如"Hello"數組長度是6,因為還有表示結束的\0。
(2) 字符串以數組的形式存在,可用數組和指針的形式訪問。
(3) 不能用運算符對字符串做運算,最多可以用? “ ” 初始化字符數組。
(4) 通過數組的方式可以遍歷字符串。
char *str = "Hello";
//指向字符串的指針
char word[] = "Hello";
//字符數組,內容是Hello
char line[10] = "Hello";
// 字符數組有10個字節,向里面放了Hello,占據6個字符
(25)字符串常量和數組字符串
字符串常量(不可修改):指針指向某個字符串
應用:處理字符串
(1) 只讀字符串,不會改寫 (1) 指針當做數組作為函數的參數 (2) 動態分配內存時,如果malloc獲得,需要手動回收
char* s = "Hello, world!";
數組字符串(可修改):那個字符串就在我這里
應用:構造字符串
(1) 可修改 (2) 其變量的空間可自動回收
char s[] = "Hello, world!";
(26)char*是字符串嗎?
本意表示指向連續字節的指針,并不能完全確定是字符串。只有當字符數組結尾有\0才能說是字符串。
(27)字符串輸入
規定字符串最多讀取多少個字符,下面是設置每個字符串最多讀取7個字符
void f(void){char word[8];scanf("%7s", word);printf("%s\n", word);
}int main(){f();return 0;
}
(27)main()輸入參數
int main(int argc, char const *argv[])整數(后面數組字符串數) 字符串數組
(28)getchar和putchar
ctl+C通過shell是直接斷程序,crl+D是通過shell在緩沖區寫入某個特定值然后getchar關閉
(29)字符串函數:strlen
size_t strlen(const char * s);
返回字符串的長度,但不包括結尾的0。自定義strlen函數如下:
size_t mylen(const char* s){int idx = 0;while (s[idx] != '\0'){idx++;}return idx;
}int main(int argc, char const *argv[]){char line[] = "Hello";printf("strlen = %lu\n", mylen(line));printf("strlen = %lu\n", strlen(line));return 0;
}
備注:strlen 的工作原理是從字符串的起始位置開始掃描,直到遇到 '\0'(空字符,即字符串的終止符)為止,返回這之前的字符數(不包括 '\0')。換行符 \n 和普通字符(如 'a'、'1' 等)一樣會被計入長度。
(30)字符串函數:strcmp
比較兩個字符串是否相等。
int strcmp(const char *s1, const char * s2);
自定義strlcmp函數如下:
int mycmp(const char *s1, const char *s2){int idx = 0;
//法1: 數組
// while (s1[idx] == s1[idx] && s1[idx] != '\0'){
// idx++;
// }//法2: 指針while(*s1 == *s2 && *s1 != '\0'){*s1++;*s2++;}return s1[idx]-s2[idx];
}int main(int argc, char const *argv[]){char s1[] = "abc";char s2[] = "abcc";printf("%d\n", mycmp(s1,s2));printf("%d\n", strcmp(s1,s2));return 0;
}
(31)字符串函數:strcpy
把第2個參數表達的字符串copy到第1個參數表達的字符串
char *strcpy(char *dest, const char *src);
// destination source
復制一個字符串
char *dst = (char *)malloc(strlen(src)+1);
// +1是因為strlen(src)不包括字符串結尾的0
strcpy(dst,src);
自定義strcpy函數如下:
char *mycpy(char *dest, const char *src){//法1:數組
// int idx = 0;
// while(src[idx] != '\0'){
// dest[idx] = src[idx];
// idx++;
// }
// dest[idx] = '\0';
// return dest;法2:指針char *rest = dest;while(*src != '\0'){*dest++ = *src++}*dest = '\0';return rest;
}
(32)字符串函數:strchr
在字符串中找第一個單個字符,返回的是指針,并指向找到的那一個字符,當返回的NULL表示沒有找到。
char *strchr(const char *s, int c);
//從左邊開始找
char *strrchr(const char *s, int c);
//從右邊開始找
功能1:如何尋找第二個字符?
int main(int argc, char const *argv[]){char s[] = "hello";char *p = strchr(s,'l');printf("%s\n", p); // 第一次輸出:llop = strchr(p+1,'l');printf("%s\n", p); // 第二次個輸出:loreturn 0;
}輸出:
llo
lo
功能2:把找到的字符復制到另一個字符串里?
int main(int argc, char const *argv[]){char s[] = "hello";char *p = strchr(s,'l');char *t = (char *)malloc(strlen(p)+1);printf("%s\n", t);free(t); return 0;
}輸出:
llo
功能3:如何提取找到的字符的前面字符串?通過轉移'\0'的位置修改了s的長度。
備注:*p = 變量的值;char *p = 地址;int?*p = 地址
int main(int argc, char const *argv[]){char s[] = "hello";char *p = strchr(s,'l');char c = *p;*p = '\0';char *t = (char *)malloc(strlen(s)+1);strcpy(t,s);printf("%s\n", t);free(t); *p = c; return 0;
}輸出:
he
(33)字符串函數:strstr
strstr在字符串中找字符串。strcasestr在字符串中找字符串過程中忽略大小寫。
char * strstr(const char * s1, const char *s2);
char * strcasestr(const char * s1, const char *s2);
(34)enum 枚舉
大括號里常量的類型是int,值是從0到n。
當需要排列的常量值時,定義枚舉的意義就是給這些常量值名字。比const int方便。
功能1:如何自動計數枚舉的元素數量
enum color {red, yellow, green, Numcolor};int main(int argc, char const *argc[]){應用1:定義數組,確定元素個數int color = -1;char *ColorNames[Numcolor] = {"red", "yellow", "green",};應用2:for循環,確定元素個數char *colorName = NULL;if(color >=0 && color < Numcolor){colorName = ColorNames[color];}return 0;
}
(35)結構體
復合的數據類型。聲明結構類型(point)和結構變量(p1)。
寫法1:
struct point{ // point 是虛指,聲明新的結構類型int x;int y;
};
struct point p1; // p1 是實指,指結構變量寫法2:
struct { int x;int y;
}p1;寫法3:
struct point{ int x;int y;
}p1; // p1就是結構變量
結構體的初始化,取地址用&today
struct date{int month;int day;int year;
};方式1:
struct date today = {07,31,2014};方式2:
struct date thismonth = {.month = 7, .year = 2014};
結構體作為函數函數
int num(struct data today);
int num(struct data today){}
結構指向體的指針:兩種表達方式 *p.month 和 p->month
struct data{int month;int day;int year;
}myday;
struct data *p = &myday;方式1
(*p).month = 12;
方式2
p->month = 12;
可用函數充取出的結構體
struct point* getStruct(struct point *p){scanf("%d\n", &p->);scanf("%d\n", &p->y);printf("%d, %d\n", p->x, p->y);return p;
}int main(int argc, char const * argv[]){struct point y = {0, 0};getStruct(&y);output(*getStruct(&y));return 0;
}
(36)結構體類型的數組
結構體類型的數組
struct data{int x;int y;
};struct data dates[100];
struct data dates[] = {{4,6},{3,4,5}};dates[100].x
(37)do while和while區別和聯系
// do while是先做循環體,后判斷
do{<循環體語句>
}while(<循環條件>);// while 是先判斷,后做
while(<循環條件>){<循環體語句>
}
(38)