標準C基礎知識筆記四
定義數組要指定元素的個數(固定的)
數組名代表什么數組,當作為數值來用時,表示數組第一個元素;
下標一定比元素個數少1
盡量避免越界
一般來說多維能解決的問題,用一維數組也能解決
*(a+i);//這個是地址的加法 相當于a+i*sizeof(int)
對于char數組可以存放字符串,但是必須有\0結尾標志
^D,輸入結束
strcmp();用來比較兩個字符串
strcpy只能用于字符串賦值
strct在某一個字符串追加一個字符串
“字符串”是存儲在只讀存儲器中的,只有系統能訪問不能修改。===》如果修改的話,會出現段錯誤
strlen(...)
strcmp(...,...) 相等0,左邊大為正,左邊小為負(比較的是ascii碼)
strchr 從左往右查找字符串
strrchr 從右往左查找字符串
strstr 從字符串中查找字符串
結構的對齊與補齊
聯合(共用體)
函數
vi struct.c
#include <stdio.h>
typedef struct Goods{
char name[18];//18個字節
double price;//8個字節
char special;//1
int num;//4個字節
short saled;//2個字節
}gs;
int main()
{
gs a[10];//定義一個Goods的變量數組,不用初始化,可以通過鍵盤來輸入
printf("%d\n",sizeof(gs));//查看gs類型占用多少字節的存儲空間
//對齊;一般來說一個變量分配空間的時候都會考慮分配內存邊界上,
//一個變量的占用的內存地址,一般是這個變量占用的字節的倍數;
//雖然這樣看起來有點浪費,但是訪問起來速度快
//char隨便一個地址就可以訪問;short為2的倍數,int為4的倍數;double為8的倍數
//一般編譯器超過4,也按照4的倍數來訪問
return 0;
}
對齊規則:每個成員都從本身長度的倍數開始
-------------------------------------------------------
| name 18 | 空2|price 8|special 1| int num 4| 空 4|
-------------------------------------------------------
補齊:是為了多個元素挨著擺放時,也能滿足對齊規則
為什么要對齊和補齊呢?(不同的OS,其尋址是不一樣的)
32位的操作系統在訪問數據的時候都是從內存中按照4的倍數來訪問數據。
數組的元素的內存存儲地址不一定是連續的,可能存在間隙;
位斷:
由于內存分配是按照幾個字節來分配的。但個別時候可能只需要幾個位即可;C語言可以設置為某幾個
成員用幾個位
//一般會用在嵌入式開發中。每一個位控制一個東西,控制一個管腳
#include <stdio.h>
struct mode{//比如用戶的讀寫執行權限rwxrwxrwx
unsigned char userread:1;
unsigned char userwrite:1;
unsigned char userexecute:1;
unsigned char groupread:1;
unsigned char groupwrite:1;
unsigned char groupexecute:1;
unsigned char otherread:1;
unsigned char otherwrite:1;
unsigned char otherexecute:1;
unsigned char f3:3;
unsigned int f10:10;
};
int main()
{
struct mode m={1,1,0,1,0,0,1,0,0,6,999};//初始化
printf("size:%d\n",sizeof(m));
printf("%d%d%d,%d%d%d,%d%d%d",
m.userread,m.userwrite,m.userexecute,
m.groupread,m.groupwrite,m.groupexecute,
m.otherread,m.otherwrite,otherexecute
);
printf("%d,%d\n",m.f3,m.f10);
return 0;
}
//備注:在vi下替換某幾行內的某個字符串user為另一個字符串other
// :10,12s/user/other/
聯合union
所有成員共用一塊地方(共用體),操作任何一個都會影響其他的。
那么什么時候用聯合呢?這些成員總是只用一個。
#include <stdio.h>
union IP{
char i4[4];
int net;
//可以使用192.168.x.x格式來表示IP;也可用一個整數來表示一個IP地址
};
int main()
{
printf("sieze:%d\n",sizeof(union IP));
IP me{192,168,0,20};
printf("%x\n",me.net);
me.net=0x12345678;
int i;
for (i=0;i<4;i++)
printf("%d ",me.i4[i]);
printf("\n")
return 0;
}
不同系統,其存儲方式也是不一樣的,有的是小端存儲有的是大端存儲
C語言本身就是一個函數語言;把實現某一個功能的打個包==》函數
printf scanf strcpy strlen strcat....標準C里面的標準庫函數
vi function.c
#include <stdio.h>
int main()
{
int n=Main(); //Main()帶回一個數值10
printf("hello world!\n");
n+=Main();
return 0;
}
int Main()//函數名是區分大小寫的
{
printf("你好 世界\n");
return 10;
}
一個C語言只有一個main函數,也是程序的入口,可以在main函數內調用其他函數。
寫一個函數清輸入緩沖區
#include <stdio.h>
void clear();//函數聲明;
int main()
{
char name[20];
char gender;
printf("請輸入姓名:");
scanf("%s",name);
clear();//這個決定了要把void clear()函數放到前面;負責會出現隱式聲明錯誤;
printf("請輸入性別(M/F):");
scanf(" %c",&gender);//理解為什么在" %c"有一個空格;因為上面輸入姓名之后肯定要敲個回車來確定輸入。但這個回車會留在輸入緩沖區中;會影響下面的輸入。
//所以要加個空格來解決這個問題
printf("%s:%c\n",name,gender);
}
void clear()//void代表這個函數不帶東西回來;函數體
{
scanf("%*[^\n]");
scanf("%*c");
}
C語言中對于不認識的類型,一般會默認的為int類型(隱式聲明)
函數定義:函數名、函數聲明、函數體
函數調用:
從鍵盤輸入一個指定范圍內的整數(get5,80)
#include <stdio.h>
int get(int a,int b)//形參(定義的時候使用)
{
printf("請輸入兩個整數:\n");
printf("a=%d,b=%d\n",a,b);
int n;//這里的n與main里面的n是不同的n。在不同的{}號的是不同的。
do{
printf("請輸入%d到%d的一個整數:",a,b);
//scanf("%d",&n);//切記:在這里%d后面沒有\n
if(scanf("%d",&n)!=1){
scanf("%*[^\n]*c");
//進一步判斷輸入的a<b,如果a>b,則需要交換數值
//判斷輸入的是整數而非小數或字符
}
}while(n<a||n>b);
return (a+b)/2;
}
int main()
{
int n=get(1,100);//實參(調用的時候使用)
int m=get(10,50);
printf("n=%d,m=%d\n",n,m);
return 0;
}
******************************************************
寫一個函數在多個程序里面能夠使用(函數調用);
------------------------------------
編寫一個程序里面帶clear函數
vi clear.c
#include <stdio.h>
void clear(){
scanf("%*[^\n]");
scanf("%*c");
}
編寫一個聲明clear函數
vi func_clear.h
void clear();//前面已經寫了一個clear函數,在這里只是寫一個函數聲明
在寫的程序里面調用這個函數
vi param.c
#include <stdio.h>
#include "func_clear.h" //函數的聲明
int main()
{
clear();
return 0;
}
//把聲明插入一份就行了。
一個程序兩個文件怎么來編譯呢?==》分開編譯,連接
編譯:
gcc -c clear.c //只編譯
gcc -c param.c
gcc clear.o param.o//合在一起,誰前誰后無所謂
man gcc
每一個頭文件感興趣就可以man下看看到底是怎么回事。
一般.h文件都在/user/include目錄下
//寫一個小程序來觀看函數調用
//輸入一行文字
//將其中的數字轉換成對應的漢字,小寫字母變成大寫,其他不變
vi check.c
#include "check.h" //把函數聲明插進來
bool isLower(char c)
{
return(c>='a'&&c<='z');
}
bool isNum(cha c)
{
return(c>='0'&&c<='9');
}
vi check.h
//函數聲明
typedef enum bool{true=1,false=0}bool;//c語言里面并沒有bool類型,定義一個類型
bool isLower(char c);
bool isNum(char c);
轉換函數
vi convert.c
#include <stdio.h>
char toUpper(char c) //把小寫轉換成大寫
{
return(c-'a'+'A'); //c-'a'字符在字母表中的偏移量;+'A'在大寫字母中的偏移量
}
char* toChinese(char c) //漢字是一串字符,而非一個字符;操作字符串,只要知道數組的開始地址即可。
{
char num[10][5]={"零","一","二","三","四","五","六","七","八","九"};
//這樣定義的含義?10個一維數組,每個一維數組
printf("%s",num[c-'0']);
return(num[c-'0']);//基本上沒作用;變量是有范圍的
//'0',數字為48;c-'0'
}
vi convert.h
char toUpper(char);
char* toChinese(char);
#include <stdio.h>
#include "check.h"
#include "convert.h"
int main()
{
char c;
printf("請輸入一行文字:");
do{
scanf("%c",&c);
if (islower(c))
printf("%c",toupper(c));
else if(isnum(c))
printf("%s",tochinese(c));
else
printf("%c",c);
}while(c!='\n');
return 0;
}
vi charaddr.c
#include <stdio.h>
int main()
{
char a[100]="good afternoon,everyone!";
char* p=a+5;//a+5===>&a[5],在這里兩者是等價的
printf("%s\n",p);
return 0;
}
問題:
//判斷某年有多少天
//日期是否有效日期;
//日期是這一年的第幾天
//日期是這一年的第幾周的哪一天
函數:
單一定義原則;
函數多次聲明;
常用的C語言標準庫文件
stdio.h //輸出輸入
stdlib.h //工具
time.h //時間相關
math.h //數學相關
string.h //字符和內存操作
ctype.h //字符操作
局部變量和全局變量
#include <stdio.h>
#include <string.h>
char w[7][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
//這種變量為全局變量(無什么范圍限制;在C里面先聲明后使用)
//也可以使用extern來聲明,告訴編譯器,w在其他地方有定義;
//extern char w[7][10];
char* week(int);
char* weekday(int n)
{
return w[n];
}
int main()
{
printf("%s\n",weekday(3));
strcpy(week(5),"fr");//通過week(5)知道其地址,然后重新賦值
printf("%s\n",week(5));
return 0;
}
vi weekday.c
#include <stdio.h>
//下面這句配合extern來使用
char w[7][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
char e[7][10]={"Sunday","Monday",...};
//通過這種方式也可以實現多語言的支持
//static h[7][10]={,,,,};//static限制全局變量只能在本文件中使用,對外隱藏
void showweekday(int n)
{
printf("%s\n",weekday(5));
printf("%s\n",e[2]);
return 0;
}
char* week(int n)//構建一個函數,讓外界通過調用這個函數來訪問static全局變量
{
return h[n];
}
文件本身并不限制全局變量的范圍;static可以限制全局變量只能在本文件中使用
但是其他文件怎么能訪問這個static的全局變量呢,可以構建一個函數,通過調用函數的方式即可
strcpy(week(5),"fr");
全局函數只能在本文件中使用也是加static
#include <stdio.h>
#include <string.h>
char* weekday(int n)
{
static char w[7][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
return w[n];
}
int counter()
{
int cnt=0;
//static int cnt=0;
//靜態局部變量,第一次使用的時候分配空間,一直保留直到程序結束。static局部變量只初始化一次。
return ++cnt;
}
int main()
{
printf("%s\n",weekday(3));
int i;
//auto signed int i;//自動,基本不用。
for (i=0;i<5;i++)
printf("%d\n",counter());
return 0;
}
由于全局變量并不安全,所以程序里面盡量少用全局變量。
靜態全局變量和局部變量不會有垃圾數據,要么是0要么是指定的數據。
time:從1970.1.1 00:00:00計算到現在的時間的秒數
register寄存器---請求把變量放到寄存器中而不是內存中;寄存器比內存快
寄存器是沒有地址的;通過&i取地址會報錯。
#include <stdio.h>
int main()
{
register int i=100;//register是一個使用寄存器的請求,用不用不一定
printf("%d\n",i);
return 0;
}
volatile int n;//這個變量可能會隨時被莫名其妙的修改
一般會用在嵌入式開發中,可能由某個硬件直接來控制(如傳感器)。