程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> C語言入門知識 >> C語言08字符串 & 預處理 & 結構體

C語言08字符串 & 預處理 & 結構體

編輯:C語言入門知識

項目開發中字符串模型建立

strstr的while dowhile模型

//int cltClient_rev(void *handle, unsigned char *buf, int *buflen)

//不要相信別人給你傳送的內存地址是可用的

int getCout(char *str, char *substr, int *count)

{

int rv = 0;

char *p = str;

int ncout = 0;

if (str==NULL || substr== NULL || count==NULL)

{

rv = -1;

printf("func getCout()check (str==NULL || substr== NULL || count==NULL) err:%d \n" , rv);

return rv;

}

do

{

p = strstr(p, substr);

if (p == NULL) //沒有找到則跳出來

{

break;

}

else

{

ncout++;

p = p + strlen(substr);

}

} while (*p != '\0');

//fuzhi

*count = ncout;

printf("ncout:%d\n", ncout);

return rv;

}

void main36()

{

char *p = "abcd1111abcd222abcd3333";

int ncout = 0;

while (p = strstr(p, "abcd"))

{

p = p + strlen("abcd");

ncout ++;

if (*p == '\0')

{

break;

}

}

printf("ncout:%d\n", ncout);

system("pause");

}

兩頭堵模型(兩種寫法)

//求去掉空格

//int trimSpaceStr2(char *p, unsigned char *buf2, int *buf2len)

int trimSpaceStr2( char *p, char *buf2)

{

int ret = 0;

int ncount = 0;

int i, j;

i = 0;

j = strlen(p) -1;

while (isspace(p[i]) && p[i] != '\0')

{

i++;

}

while (isspace(p[j]) && j>0 )

{

j--;

}

ncount = j - i + 1;

//

strncpy(buf2, p+i, ncount);

buf2[ncount] = '\0';

return ret;

}

//求去掉空格

//int trimSpaceStr2(char *p, unsigned char *buf2, int *buf2len)

//不要輕易去改變指針輸入特性中in內存塊的內存。。。。

int trimSpaceStr2_notgood( char *p)

{

int ret = 0;

int ncount = 0;

int i, j;

i = 0;

j = strlen(p) -1;

while (isspace(p[i]) && p[i] != '\0')

{

i++;

}

while (isspace(p[j]) && j>0 )

{

j--;

}

ncount = j - i + 1;

//

strncpy(p, p+i, ncount);

p[ncount] = '\0';

return ret;

}

字符串反轉模型

void main51()

{

char p[] = "abcde";

char c ;

char *p1 = p;

char *p2 = p + strlen(p) -1;

while (p1 < p2)

{

c = *p1;

*p1 = *p2;

*p2 = c;

++p1;

--p2;

}

printf("p:%s \n", p);

system("pause");

}

 

兩個輔助指針變量挖字符串

int getKeybyValue(char *pKeyValude, char *pKey, char *pValude)

{

char rv = 0;

char *p = NULL;

if (pKeyValude==NULL )

{

rv = -1;

printf("func getKeybyValue() err:%d pKeyValude \n", rv);

return rv;

}

if ( pKey==NULL )

{

rv = -1;

printf("func getKeybyValue() err:%d pKey=NULL \n", rv);

return rv;

}

if ( pValude==NULL )

{

rv = -1;

printf("func getKeybyValue() err:%d pValude \n", rv);

return rv;

}

//1 在pKeyValude中查找是否有關鍵字pKey

p = strstr(pKeyValude, pKey);

if (p == NULL)

{

rv = -1;

printf("func getKeybyValue() err:%d 查找沒有關鍵字pKey \n", rv);

return rv;

}

p = p + strlen(pKey); //為下一次檢索做准備

//2 有沒有=

p = strstr(p, "=");

if (p == NULL)

{

rv = -2;

printf("func getKeybyValue() err:%d 查找沒有= \n", rv);

return rv;

}

p = p + 1; //為下一次提取valude做准備

//3 提取按照要求的valude

rv = trimSpaceStr03(p, pValude);

if (rv != 0)

{

printf("func trimSpaceStr03() err:%d \n", rv);

return rv;

}

return rv;

}



指針作函數參數輸入模型



-------------------------------------------------------------------------
字符串
-------------------------------------------------------------------------
1.字符串基礎:


#include "stdlib.h"
#include "stdio.h"
#include "string.h"


//int * char *
//c語言裡面沒有字符串這種類型。。。。。
//通過字符數組來模擬字符串
//C風格字符串是以零結尾的字符串
//
void main11()
{
//字符數組初始化
//指定長度 如果定義的長度剩余部分補充0
char buf1[100] = {'a', 'b', 'c'};
//不指定長度
char buf2[] = {'a', 'b', 'c'};
char buf3[] = {'a', 'b', 'c','\0'};


//通過字符串初始化字符數組 並且追加\0
char buf4[] = "abcdefg";


printf("%s\n", buf4 );


system("pause");
}


//sizeof
void main12()
{
//字符數組初始化
//指定長度 如果定義的長度剩余部分補充0
char buf1[100] = {'a', 'b', 'c'};
//不指定長度
char buf2[] = {'a', 'b', 'c'};
char buf3[] = {'a', 'b', 'c','\0'};


//通過字符串初始化字符數組 並且追加\0
char buf4[] = "abcd";


printf("%s\n", buf4 );
//注意sizeof是對數組類型進行大小測量 包括了\0
printf("sizeof(buf4): %d\n ", sizeof(buf4));
//strlen是求字符串的長度不包括\0
printf("strlen(buf4): %d \n", strlen(buf4));
system("pause");
}


//操作數組的方法
//下標法和指針法
void main()
{
int i = 0;
char *p = NULL;
//通過字符串初始化字符數組 並且追加\0
char buf4[] = "abcd";

for (i=0; i {
printf("%c", buf4[i]); //p[]
}
//[] *的本質到底是什麼?
//*p 是我們程序員手工的(顯示)去利用間接賦值
//【】 只不過是,c/c++ 編譯器幫我們做了一個*p的操作。。。。。。
// buf4[i]======> buf4[0+i] ====> *(buf4+i)
//===*(buf4+i) --> bu4[i];


printf("\n");
p = buf4;
for (i=0; i {
printf("%c", *(p+i)); //*p
}
system("pause");
}


2.自定義字符串拷貝基本模型


#include "stdlib.h"
#include "stdio.h"
#include "string.h"


//自定義:字符串copy函數,完成字符串from ,到to的copy
void copy_str1(char *from, char *to)
{
for (; *from!='\0'; from++, to++)
{
*to = *from;
}
*to = '\0';
}
void copy_str2(char *from, char *to)
{
while(*from!='\0')
{
*to = *from;
from++;
to++;
}
*to = '\0';
}


//++優先級高,但是++是後綴++
//所以先執行*to = *from; 再 from++; to ++from++;
void copy_str3(char *from, char *to)
{
while((*to++ = *from++))
{
;
}
}


void main()
{
//輸入:
//在主調裡函數分配內存
char *p = "abcdefg";
char p2[100] ;//char *p2 = NULL;
//在被調函數裡使用內存
copy_str3(p, p2);//strcpy(p2, "abcdeeg");
//輸出:
printf("p2:%s\n", p2);
system("pause");
}


¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
看見一級指針,要去分辨指針的輸入輸出特性 ¥
指針的輸入特性:在主調函數裡面分配內存,在被調用函數裡面使用 ¥
指針的輸出特性:在被調用函數裡面分配內存,主要是把運算結果甩出來 ¥
¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥


3.項目開發字符串模型(此處為指針輸入特性)


//char *p = "abcd1111abcd222abcd3333" 請你找出字符串abcd出現的次數
//要求1:請自己定義一個接口(函數),並實現功能;70分
//要求2:編寫測試用例。30分
/*
//輸入:要查找的字符串
待查找的子串
輸出的結果*/
//接口提示:int cltClient_rev(void *handle, unsigned char *buf, int *buflen)


#include
#include
#include


//1級指針作函數參數(形參),用於修改0級指針(實參)
int getCout(char *str, char *substr, int *count)
{
int rv = 0;//用於輸出檢查和函數返回
char *p = str;//定義一個指針,用於接收形參地址
int ncout = 0;//用於計數
//不能相信別人傳過來的地址就一定可用,需作安全檢查
if (str==NULL || substr== NULL || count==NULL)
{
rv = -1;//地址不可用
printf("func getCout()check err:%d \n" , rv);
return rv;
}


do
{
p = strstr(p, substr);//此處調用的是庫函數
if (p == NULL) //沒有找到則跳出來
{
break;
}
else
{
ncout++;//找到了就,計數加1
p = p + strlen(substr);//地址向後移動待查字符串個長度
}


} while (*p != '\0');//目標字符串遍歷完成就結束循環

*count = ncout;//取實參地址間接修改實參
printf("ncout:%d\n", ncout);


return rv;//函數返回(int類型)
}


void main()
{
int ret = 0;//用於接收接口函數的返回值
int ncout = 0;//用於計數(第3個參數)
//輸入:在主調函數裡分配內存
/*目標字符串(第1個參數)*/
char *p = "abcd1111abcd222abcd3333";//分配了內存,可得到計數值
//char *p = NULL;//沒有分配內存,沒有計數值
/*待查字符串(第2個參數)*/
char *subp = "abcd";
//輸出:在被調函數裡使用內存
ret = getCout(p, subp, &ncout);
//安全檢查
if (ret != 0)
{
printf("func getCout() err:%d \n", ret);
return ;
}
printf("coutn:%d \n", ncout);
system("pause");


}
//下面這樣的代碼很不OK!!!
void main01()
{
char *p = "abcd1111abcd222abcd3333";
int ncout = 0;
while (p = strstr(p, "abcd"))
{
p = p + strlen("abcd");
ncout ++;
if (*p == '\0')
{
break;
}
}
printf("ncout:%d\n", ncout);
system("pause");
}


4.兩頭堵模型


#include "stdio.h"
#include "stdlib.h"
#include "string.h"
//不成熟的做法
void main01()
{
int count = 0;
int i = 0, j = 0;


char *p = " abcd ";
j = strlen(p) -1;


while (isspace(p[i]) && p[i] != '\0')
{
i++;
}


while (isspace(p[j]) && j>0)
{
j--;
}
count = j-i +1;

printf("count:%d", count);


system("pause");
}


//一級指針的輸入模型,沒有內存就沒有指針


/*int trimSpace_很不ok的做法(char *mybuf)
{
int count = 0;
int i = 0, j = 0;
char *p = mybuf;
j = strlen(p) -1;
while (isspace(p[i]) && p[i] != '\0')
{
i++;
}
while (isspace(p[j]) && j>0)
{
j--;
}
count = j-i +1;
printf("count:%d", count);
//void * __cdecl memcpy(void *, const void *, size_t);
memcpy(mybuf, mybuf+i, count);
mybuf[count] = '\0';
return 0;
//system("pause");
}
*/


//一般情況下不要修改輸入的內存塊的值


int trimSpace_ok(char *mybuf, char *outbuf)
{//此函數去掉字符串前後空格
int count = 0;
int i = 0, j = 0;


char *p = mybuf;//定義一個指針接收形參地址
j = strlen(p) -1;
//isspace()函數用於檢測字符串是否為空
while (isspace(p[i]) && p[i] != '\0')
{
i++;
}


while (isspace(p[j]) && j>0)
{
j--;
}
count = j-i +1;

printf("count:%d\n", count);
//void * __cdecl memcpy(void *, const void *, size_t);
memcpy(outbuf, mybuf+i, count);
outbuf[count] = '\0';
return 0;
}


void main()
{
int ret = 0;//用於檢查和接收函數返回至
char *p = NULL;
char buf2[100];


//對於字符串分配內存有三種方式,可以在堆、棧、全局區(常量區),
//你要知道你的內存是怎麼分配的
char *buf = " abcd11111abcd2222abcdqqqqq "; //常量區
//char buf[] = " abcd11111abcd2222abcdqqqqq ";//棧


/*很不OK的做法
ret = trimSpace(buf);
if (ret != 0)
{
printf("func trimSpace() err:%d\n", ret);
return ;
}
*/


ret = trimSpace_ok(buf, buf2);
if (ret != 0)
{
printf("func trimSpace() err:%d\n", ret);
return ;
}
printf("buf2:%s \n", buf2);
system("pause");


}


5.字符串反轉模型


#include "stdlib.h"
#include "stdio.h"
#include "string.h"


void main()
{
char p[] = "abcde";//分配內存
char c ;
char *p1 = p;//指向字符串頭
char *p2 = p + strlen(p) -1;//指向字符串尾


while (p1 < p2)//如果p1 {
c = *p1;
*p1 = *p2;
*p2 = c;
++p1;
--p2;//++、--可寫到交換語句中
}
printf("p:%s \n", p);
system("pause");


}


6.兩個輔助變量挖字符串


/*
有一個字符串符合以下特征(”abcdef,acccd,eeee,aaaa,e3eeeee,sssss,";)
要求寫一個函數(接口),輸出以下結果:
1) 以逗號分割字符串,形成二維數組,並把結果傳出;
2) 把二維數組行數運算結果也傳出。
strchr(“aa,aa”,’,’ );


請自己定義一個接口(函數)。
要求1:能正確表達功能的要求,定義出接口(函數)(30分);
要求2:正確實現接口(函數),並實現功能(40分);
要求3:編寫正確的測試用例。(30分)。
*/
//abcdef,acccd,eeee,aaaa,e3eeeee,sssss,
/*
abcdef
acccd
eeee,
aaaa,
e3eeeee,
sssss,
*/


#include "stdio.h"
#include "string.h"
#include "stdlib.h"


int spitString(const char *buf1, char c, char buf[10][30], int *num)
{
int ret = 0;
char *p = NULL;
char *pTmp = NULL;
int ncount = 0;
if (buf1==NULL || num==NULL)
{
return -1;
}
//步驟1 初始化條件 pTmp,p都執行檢索的開頭
p = buf1;
pTmp = buf1;
do
{
//步驟2 strstr strchr,會讓p後移 在p和pTmp之間有一個差值
p = strchr(p, c);
if (p == NULL) //沒有找到則跳出來
{
break;
}
else
{
//挖字符串
strncpy(buf[ncount], pTmp, p-pTmp);
buf[ncount][p-pTmp] = '\0';


ncount++;


//步驟3 讓p和pTmp重新初始化,達到檢索的條件
pTmp = p = p + 1;
}


} while (*p != '\0');
//printf("ncout:%d\n", ncount);
*num = ncount;
return ret;
}
void main()
{
int ret = 0, i = 0;
const char *buf1 = "abcdef,acccd,eeee,aaaa,e3eeeee,sssss,";
char c = ',';
char buf[10][30];
int num = 0;
ret = spitString(buf1, c, buf, &num);
if (ret != 0)
{
printf("func spitString() err:%d\n", ret);
return ret;
}


for (i=0; i {
printf("%s\n", buf[i]);
}


system("pause");
}


7.二級指針第一種內存模型模型(指針數組):


在棧中的一維數組保存的地址指向常量區分配的內存


#include "stdio.h"
#include "stdlib.h"
#include "string.h"
//二級指針作函數參數修改一級指針的值
int printfArr(char **ArrayStr, int iNum)
{
int i = 0;
for (i=0; i {
printf("%s \n", ArrayStr[i]);
}
return 0;
}


int sortArrayStr(char **ArrayStr, int iNum)
{
int i = 0, j = 0;
char *tmp = NULL;//用於交換是的臨時變量,由於C語法規定,必須在語句前定義
//排序
for (i=0; i {
for (j=i+1; j {
if (strcmp(ArrayStr[i],ArrayStr[j]) > 0)
{
//一級指針交換(數組元素)
tmp = ArrayStr[i];
ArrayStr[i] = ArrayStr[j];
ArrayStr[j] = tmp;
}
}
}
return 0;
}


//二級指針第一種內存模型
void main()
{
//分配內存(常量區,不可修改)
char *ArrayStr[] = {"ccccc", "aaaa", "bbbb","11111"};


printf("排序之前\n");
printfArr(ArrayStr,4);


sortArrayStr(ArrayStr, 4);


printf("排序之後\n");
printfArr(ArrayStr,4);


system("pause");
}


8.二級指針第二種內存模型(二維數組):


在棧中分配(二維數組型)內存


#include "stdio.h"
#include "stdlib.h"
#include "string.h"


int printfArr22(char **ArrayStr, int iNum)
{
int i = 0;
for (i=0; i {
printf("%s \n", ArrayStr[i]);
}
return 0;
}


//int array[10]===>int *array===>
// int printfArr22(char array[10], int iNum);
int printfArr23(char myArray[10][30], int iNum)
{
int i = 0;
for (i=0; i {
printf("%s \n", myArray[i]);
}
return 0;
}


// int printfArr22(char array[10], int iNum);
int sortArr23(char myArray[10][30], int iNum)
{
int i = 0, j = 0;
char buf[30]; //buf數組名代表數組首元素的地址
//排序
for (i=0; i<4; i++)
{
for (j=i+1; j<4; j++)
{
if (strcmp(myArray[i], myArray[j]) > 0)
{
strcpy(buf, myArray[i]);
strcpy(myArray[i],myArray[j]);
strcpy(myArray[j], buf);
}
}
}
}


void main()
{
int i = 0;
char myArray[10][30] = {"ccccc", "aaaa", "bbbb","11111"};


//打印第二種內存模型
for (i=0; i<4; i++)
{
printf("%s \n", myArray[i]);
}


printf("第二種內存模型,排序之前\n");
printfArr23(myArray, 4);
//printfArr23(myArray[10][30], 4);


sortArr23(myArray, 4);


printf("第二種內存模型,排序之後\n");
printfArr23(myArray, 4);
system("pause");
}


9.二級指針第三種內存模型(手工二維內存、二級指針):


在棧中的指針ArrayStr指向堆中分配的(指針數組型)內存


#include "stdio.h"
#include "stdlib.h"
#include "string.h"


int printfArr33(char **ArrayStr, int iNum)
{
int i = 0;
for (i=0; i {
printf("%s \n", ArrayStr[i]);
}
return 0;
}


int printfArr2_23(char myArray[10][100], int iNum)
{
int i = 0;
for (i=0; i {
printf("%s \n", myArray[i]);
}
return 0;


}


int sortArrayStr03(char **ArrayStr, int iNum)
{
int i = 0, j = 0;
char *tmp = NULL;
//排序
for (i=0; i {
for (j=i+1; j {
if (strcmp(ArrayStr[i],ArrayStr[j]) < 0)
{
tmp = ArrayStr[i];
ArrayStr[i] = ArrayStr[j];
ArrayStr[j] = tmp;
}
}
}
return 0;
}


void main()
{
int i = 0, j = 0;
char buf[100];
char **myarray = (char **)malloc(10*sizeof(char*)); //int array[10]
if (myarray == NULL)
{
return;
}
for (i=0; i<10; i++)
{
myarray[i] = (char *)malloc(100*sizeof(char)); //char buf[100];
if (myarray[i] == NULL)
{
printf("ddddde\n");
return;
}
sprintf(myarray[i],"%d%d%d ", i, i, i);
}


//第三種內存模型打印
printf("排序之前\n");
printfArr33(myarray, 10);
//printfArr2_23(myarray, 10); //第二種打印不適合 err


sortArrayStr03(myarray, 10);


//第三種內存模型打印
printf("排序之後\n");
printfArr33(myarray, 10);


for (i=0; i<10; i++)
{
free(myarray[i] );
}
if (myarray != NULL)
{
free(myarray);
}


system("pause");
}




10.一維數組的本質(常量指針)


#include "stdio.h"
#include "stdlib.h"
#include "string.h"


void main()
{
int a;
int *p = NULL;
int i = 0;


//我聲明了一個數組類型 (固定大小內存塊的別名)
typedef int(MyArr5)[5];
//定義一個指向數組類型的指針變量
MyArr5 *pArray;// &a;
{
int j = 0;
int *pI = &j;
}
{
//int buf[10][30]
//a1代表數組首元素的地址(不是整個數組的地址),請問a1 指針變量
//1變量-->2指針變量--》 3常量指針變量 (常量指針)
//結論:不能被隨便的改變指針變量的值(不能隨便的改變指針的指向)
//為什麼它是一個const


//4在定義a1[5]的時候,編譯器分配內存,為了能順利的回收內存,為了有機會讓編譯器拿到原始內存首地址。
//編譯器就把a1做成const量。
//不能深入的理解c指針各種現象,是產生bug的根源


int a1[5] = {1,3,4,55, 6};
//char *p = &a1;
//a1 = 0x11;


//給數組指針賦值 需要。。。&a1
MyArr5 *pArray = &a1; //4個字節
//用數組指針去遍歷數組
for (i=0; i<5; i++)
{
//a1[i] = i;
// = i;
printf("%d ", (*pArray)[i]);
}
}




{
//直接定義一個 數組指針類型 用這個類型定義指針變量
//我聲明了一個數組類型 (固定大小內存塊的別名)
typedef int(MyArr5_1)[5];
//定義一個指向數組類型的指針變量
//聲明一個 數組指針類型
typedef int (*PMyArr5)[5];
PMyArr5 myP = NULL;


int b[5] = {1,3,4,55, 6};


myP = &b;


for (i=0; i<5; i++)
{
//a1[i] = i;
// = i;
printf("%d ", (*myP)[i]);
}
}




{
int c[5] = {1,3,4,55, 6};
//定義一個指向數組的指針變量
int (*myparra)[5] = &c;
for (i=0; i<5; i++)
{
printf("%d ", (*myparra)[i]);
}
}
system("pause");
}


11.多(2)維數組的本質(數組指針)


#include "stdlib.h"
#include "string.h"
#include "stdio.h"


//證明二維數組的存儲,是線性的
void printArray(char aa[][5]);
void printArray2(int *p);


void main()
{
int a[3][5];
int c[5]; //&c + 1;
int b[10]; //b代表數組首元素的地址 &b代表這個數組的地址 &b+1相當於 指針後移4*10個單位
//指針步長===》鐵律1

//a代表什麼什麼那?a是一個數組指針 指向低維數組的指針
//a +1;
printf("a:%d, a+1:%d \n", a, a+1); //4*5


{
int i=0, j = 0, tmp = 0;
for (i=0; i<3; i++)
{
for (j=0; j<5; j++)
{
a[i][j] = ++tmp;
}
}


printf("\n");
for (i=0; i<3; i++)
{
for (j=0; j<5; j++)
{
printf("%d \n", a[i][j]);
}
}
}


//a的本質是一個數組指針。。。。每次往後跳一維的維數。。。。。。
{
int i = 0, j = 0;
//定義了一個數組指針 變量
int (*myArrayPoint)[5] ; //告訴編譯給我開辟四個字節內存
myArrayPoint = a;
printf("\n");
for (i=0; i<3; i++)
{
for (j=0; j<5; j++)
{
//myArrayPoint[i][j] = ++tmp;
printf("%d \n", myArrayPoint[i][j]);
}
}
}


/*
char array[10][30];
(array+i) //相當於 第i行的首地址 //二級指針


(*(array+i))//一維數組的首地址


(*(array+i))+j //相當於第i行第j列的地址了把。。。。


*((*(array+i))+j) //相當於第i行第j列的地址了把。。。。<====>array[i][j]
*/
system("pause");
}


12.指針數組實例


#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include
#include


//演示:指針數組的用法
//演示:找錯誤 注意return


//求關鍵字在表中的位置
//一個入口 多個出口
int searcheKeyTable(const char* table[], const int size, const char* key, int *pos)
{
int rv = 0;
int i = 0;
int inum = 0;
if (table==NULL || key==NULL || pos==NULL)
{
rv = -1;
printf("func searcheKeyTable:%d", rv);
return rv;
}
inum = (sizeof(table)/sizeof(*table));


for(i=0; i {
if( strcmp(key, table[i]) == 0 )
{
*pos = i;
//break;
return rv;
}
}


//沒有找到返回-1
if (i == size)
{
*pos = -1;
}
return rv;
}


#define DIM(a) (sizeof(a)/sizeof(*a))


int main61()
{
int inum = 0;
int pos = 0;
int a[10];
int i = 0;
//指針數組
char* c_keyword[] = {
"while",
"case",
"static",
"do"
};


searcheKeyTable( c_keyword, DIM(c_keyword),"do", &pos);
//searcheKeyTable( c_keyword, inum,"do", &pos);
printf("pos:%d\n", pos);
//searcheKeyTable(NULL, DIM(c_keyword),"do", &pos);
//printf("pos:%d\n", pos);
searcheKeyTable( c_keyword, DIM(c_keyword), "static", &pos);
printf("pos:%d\n", pos);


system("pause");
return ;
}


//main函數是操作系統調用的函數
//在程序執行的時候可以向main函數傳遞參數


/*
argc 命令行參數
argv 命令行參數數組
env 函數變量數組


int main();
int main(int argc);
int main(int argc, char *argv[])
*/




int main111(int argc, char* argv[], char**env)
{
int i = 0;
//main02_1();


printf("******************* Begin argv *******************\n");
for(i=0; i {
printf("%s\n", argv[i]);
}


// for(i=0; argv[i]!=NULL; i++)
// {
// printf("%s\n", argv[i]);
// }
printf("******************* End argv *******************\n");


printf("\n");
printf("\n");
printf("\n");


printf("******************* Begin env *******************\n");


for(i=0; env[i]!=NULL; i++)
{
printf("%s\n", env[i]);
}


printf("******************* End env*******************\n");


getchar();
}


int main()
{
int inum = 0;
int pos = 0;
int a[10];
int i = 0;
//指針數組
char* c_keyword[] = {
"while",
"case",
"static",
"do",
'\0'
};
// NULL 0 '\0'


for(i=0; c_keyword[i]!=NULL; i++)
{
printf("%s\n", c_keyword[i]);
}
system("pause");
}




13.野指針及其釋放問題


#include "stdio.h"
#include "stdlib.h"
#include "string.h"


int myfree(char *p2)
{
if (p2 != NULL)//判斷是否內存被操作系統占用
{
free(p2);//釋放
p2 = NULL;//釋放後最好“拴在”NULL處
}
}


void main()
{
//聲明指針變量的時候null
char *p = NULL;//不初始化會產生野指針
p = (char *)malloc(100);//分配堆內存
//此處執行業務
myfree(p);//業務執行完畢釋放內存
/*
if (p != NULL)
{
free(p);
p = NULL;
}
若重復釋放內存也會產生野指針,導致程序崩潰
*/
system("pause");
}






















1 字符串地址的測試

1.1 問題

測試字符串常量和字符數組 類型的變量地址是否相同。

1.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:字符串地址的測試

代碼如下所示:

  1. #include
  2. #include
  3.  
  4. int main()
  5. {
  6. char *str = "This is a string.";
  7. char array[100];
  8. strcpy(array, str);
  9.  
  10. printf("字符串常量的地址:%p\n", str);
  11. printf("字符數組的地址:%p\n", array);
  12.  
  13. return 0;
  14. }

上述代碼中,以下代碼:

  1. char *str = "This is a string.";

定義了一個字符型指針str,用於指向一個字符串常量。

上述代碼中,以下代碼:

  1. printf("字符串常量的地址:%p\n", str);
  2. printf("字符數組的地址:%p\n", array);

使用printf函數分別輸出字符串常量的地址和字符數組的地址。從輸出結果可見,它們是不相同的。

1.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2. #include
  3.  
  4. int main()
  5. {
  6. char *str = "This is a string.";
  7. char array[100];
  8. strcpy(array, str);
  9.  
  10. printf("字符串常量的地址:%p\n", str);
  11. printf("字符數組的地址:%p\n", array);
  12.  
  13. return 0;
  14. }

2 字符串的定義和使用

2.1 問題

定義一個int類型的指針,指向一個整型變量,然後分別使用&和*取得地址或者數據。

2.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:字符串的定義和使用

代碼如下所示:

  1. #include
  2.  
  3. int main()
  4. {
  5. char str[5] = {};
  6. scanf("%4s", str);
  7. printf("%s\n", str);
  8.  
  9. return 0;
  10. }

上述代碼中,以下代碼:

  1. char str[5] = {};

定義了一個字符數組str,該數組有5個元素。

上述代碼中,以下代碼:

  1. scanf("%4s", str);

使用scanf函數輸入一個字符串。其中,%4s是限定輸入的字符串中字符的個數不能大於4,否則將只輸入前4個字符。指定值為4是因為字符數組str的長度為5,多出來的一個需要存儲\0。

上述代碼中,以下代碼:

  1. printf("%s\n", str);

使用函數printf輸出字符串。字符數組所對應的格式控制符是%s。

2.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2.  
  3. int main()
  4. {
  5. char str[5] = {};
  6. scanf("%4s", str);
  7. printf("%s\n", str);
  8.  
  9. return 0;
  10. }

3 字符串函數的使用

3.1 問題

使用指針實現字符串的函數strlen()、strcat()的功能,可以自定義兩個函數。

3.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:字符串函數的使用

代碼如下所示:

  1. #include
  2.  
  3. int mystrlen(char *str)
  4. {
  5. int count = 0;
  6. while (*str)
  7. {
  8. count++;
  9. str++;
  10. }
  11.  
  12. return count;
  13. }
  14.  
  15. char* mystrcat(char *s, char *d)
  16. {
  17. char* old = s;
  18. while(*s)
  19. s++;
  20. while(*d)
  21. {
  22. *s = *d;
  23. s++;
  24. d++;
  25. }
  26.  
  27. return old;
  28. }
  29.  
  30. int main()
  31. {
  32. char str[100] = "This is ";
  33. printf("str的長度為:%d\n", mystrlen(str));
  34.  
  35. char* str1 = "a string";
  36. mystrcat(str, str1);
  37. printf("連接後的字符串為:%s\n", str);
  38.  
  39. return 0;
  40. }

上述代碼中,以下代碼:

  1. int mystrlen(char *str)
  2. {
  3. int count = 0;
  4. while (*str)
  5. {
  6. count++;
  7. str++;
  8. }
  9.  
  10. return count;
  11. }

定義了一個函數mystrlen,用於模擬庫函數strlen的功能。該函數的參數為求長度的字符串。在該函數中,以下語句:

  1. int count = 0;

首先定義一個整型變量count,用於存儲字符串中字符的個數。在該函數中,以下語句:

  1. while (*str)
  2. {
  3. count++;
  4. str++;
  5. }

設置一個循環,逐個計算字符串中字符的個數,當*str不為\0時,代表該字符串沒有結束。在該函數中,以下語句:

  1. return count;

返回字符串的長度。

上述代碼中,以下代碼:

  1. char* mystrcat(char *s, char *d)
  2. {
  3. char* old = s;
  4. while(*s)
  5. s++;
  6. while(*d)
  7. {
  8. *s = *d;
  9. s++;
  10. d++;
  11. }
  12.  
  13. return old;
  14. }

定義了一個函數mystrcat,用於模擬庫函數strcat的功能。該函數的兩個參數為將字符串d連接到字符串s的後面。在該函數中,以下語句:

  1. char* old = s;

首先保存被連接字符串的首地址,用於函數結束返回時作返回值用。在該函數中,以下語句:

  1. while(*s)
  2. s++;

設置一個循環找到被連接字符串的結束符\0,以便將另一個字符串連接到這個位置。在該函數中,以下語句:

  1. while(*d)
  2. {
  3. *s = *d;
  4. s++;
  5. d++;
  6. }

設置一個循環將字符串d的每一個字符拷貝到字符串s的結束字符\0開始的空間中,實現連接功能。在該函數中,以下語句:

  1. return old;

返回字符串s的首字符地址。

注意:由於上述循環中,指針s已經發生了變化,所以不能直接返回。

上述代碼中,以下代碼:

  1. int main()
  2. {
  3. char str[100] = "This is ";
  4. printf("str的長度為:%d\n", mystrlen(str));

首先,在主函數中定義一個字符數組,用於存儲字符串"This is "。

然後,調用自定義函數mystrlen求得字符數組的長度,並輸出。

上述代碼中,以下代碼:

  1. char* str1 = "a string";
  2. mystrcat(str, str1);
  3. printf("連接後的字符串為:%s\n", str);

首先,在主函數中定義一個字符指針,用於指向字符串"a string"。

然後,調用自定義函數mystrcat將字符指針指向的字符串拼接到字符數組str中,並輸出。

最後,輸出連接後的字符數組str。

3.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2.  
  3. int mystrlen(char *str)
  4. {
  5. int count = 0;
  6. while (*str)
  7. {
  8. count++;
  9. str++;
  10. }
  11.  
  12. return count;
  13. }
  14.  
  15. char* mystrcat(char *s, char *d)
  16. {
  17. char* old = s;
  18. while(*s)
  19. s++;
  20. while(*d)
  21. {
  22. *s = *d;
  23. s++;
  24. d++;
  25. }
  26.  
  27. return old;
  28. }
  29.  
  30. int main()
  31. {
  32. char str[100] = "This is ";
  33. printf("str的長度為:%d\n", mystrlen(str));
  34.  
  35. char* str1 = "a string";
  36. mystrcat(str, str1);
  37. printf("連接後的字符串為:%s\n", str);
  38.  
  39. return 0;
  40. }

4 字符串函數的使用(續1)

4.1 問題

使用指針函數實現文件名和文件目錄的拼接。

4.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:字符串函數的使用(續1)

代碼如下所示:

  1. #include
  2.  
  3. char* filenamecat(char *path, char* name)
  4. {
  5. char* old = path;
  6. while(*path)
  7. path++;
  8. if (*(path - 1) != '/')
  9. {
  10. *path = '/';
  11. path++;
  12. }
  13. while(*name)
  14. {
  15. *path = *name;
  16. path++;
  17. name++;
  18. }
  19.  
  20. return path;
  21. }
  22.  
  23. int main()
  24. {
  25. char path[100] = "/home/tarena/";
  26. char* filename = "字符串函數的使用.c";
  27. filenamecat(path, filename);
  28. printf("帶路徑的文件名為:%s\n", path);
  29.  
  30. return 0;
  31. }

上述代碼中,下面代碼行:

  1. char* filenamecat(char *path, char* name)
  2. {
  3. char* old = path;
  4. while(*path)
  5. path++;
  6. if (*(path - 1) != '/')
  7. {
  8. *path = '/';
  9. path++;
  10. }
  11. while(*name)
  12. {
  13. *path = *name;
  14. path++;
  15. name++;
  16. }
  17.  
  18. return old;
  19. }

定義了一個函數filenamecat,用於拼接文件路徑和文件名的功能。該函數的兩個參數為將文件名字符串name連接到路徑字符串path的後面。在該函數中,以下語句:

  1. char* old = path;

首先保存路徑字符串的首地址,用於函數結束返回時作返回值用。在該函數中,以下語句:

  1. while(*path)
  2. path++;

設置一個循環找到路徑字符串的結束符\0,以便將文件名字符串連接到這個位置。在該函數中,以下語句:

  1. if (*(path - 1) != '/')
  2. {
  3. *path = '/';
  4. path++;
  5. }

判斷路徑字符串的最後一個字符是否是/,如果不是則首先在路徑字符串的最後添加字符/。在該函數中,以下語句:

  1. while(*name)
  2. {
  3. *path = *name;
  4. path++;
  5. name++;
  6. }

設置一個循環將文件名字符串name的每一個字符拷貝到路徑字符串path的結束字符/後面的空間中,實現連接功能。在該函數中,以下語句:

  1. return old;

返回路徑字符串path的首字符地址。

注意:由於上述循環中,指針path已經發生了變化,所以不能直接返回path。

上述代碼中,下面代碼行:

  1. int main()
  2. {
  3. char path[100] = "/home/tarena/";
  4. char* filename = "字符串函數的使用.c";

首先,定義一個數組path,用於保存路徑名。

然後,定義一個指針filename,用於指向文件名。

上述代碼中,下面代碼行:

  1. filenamecat(path, filename);

調用自定義函數filenamecat,將文件名filename連接到路徑名path的後面。

上述代碼中,下面代碼行:

  1. printf("帶路徑的文件名為:%s\n", path);

使用函數printf輸出連接後的路徑加文件名。

4.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2.  
  3. char* filenamecat(char *path, char* name)
  4. {
  5. char* old = path;
  6. while(*path)
  7. path++;
  8. if (*(path - 1) != '/')
  9. {
  10. *path = '/';
  11. path++;
  12. }
  13. while(*name)
  14. {
  15. *path = *name;
  16. path++;
  17. name++;
  18. }
  19.  
  20. return path;
  21. }
  22.  
  23. int main()
  24. {
  25. char path[100] = "/home/tarena/";
  26. char* filename = "字符串函數的使用.c";
  27. filenamecat(path, filename);
  28. printf("帶路徑的文件名為:%s\n", path);
  29.  
  30. return 0;
  31. }

5 字符串的基本操作

5.1 問題

測試不同類型的指針的算術運算。

5.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:字符串的基本操作

代碼如下所示:

  1. #include
  2. #include
  3.  
  4. int main()
  5. {
  6. char str[100];
  7. strcpy(str, "tarena");
  8. printf("字符串為:%s\n", str);
  9.  
  10. if (strcmp(str, "tarena"))
  11. printf("字符串str與tarena不同\n");
  12. else
  13. printf("字符串str與tarena相同\n");
  14.  
  15. printf("sizeof(str) = %ld\n", sizeof(str));
  16. printf("strlen(str) = %lu\n", strlen(str));
  17.  
  18. strcat(str, " C++方向");
  19. printf("字符串拼接後為:%s\n", str);
  20.  
  21. printf("字符串拆分的前一部分為:%s\n", strtok(str, " "));
  22. printf("字符串拆分的後一部分為:%s\n", strtok(NULL, " "));
  23.  
  24. char* p = strstr(str, "re");
  25. if (p)
  26. printf("子串re在字符串tarena中的位置為:%ld\n", p - str);
  27. else
  28. printf("子串re不在字符串tarena中\n");
  29.  
  30. strcpy(str, "a 10 13.5");
  31. int i;
  32. double d;
  33. char c;
  34. sscanf(str, "%c%d%lf\n", &c, &i, &d);
  35. printf("%c %d %lf\n", c, i, d);
  36. memset(str, 0, sizeof(str));
  37. sprintf(str, "%c %d %lf\n", c, i, d);
  38. printf("%s\n", str);
  39.  
  40. return 0;
  41. }

上述代碼中,以下代碼:

  1. char str[100];
  2. strcpy(str, "tarena");
  3. printf("字符串為:%s\n", str);

使用strcpy函數,將字符串"tarena"賦值到字符數組str中。

上述代碼中,以下代碼:

  1. if (strcmp(str, "tarena"))
  2. printf("字符串str與tarena不同\n");
  3. else
  4. printf("字符串str與tarena相同\n");

使用函數strcmp,逐個對比字符串"tarena"與字符數組str中的對應字符。如果所有對應字符均相同則返回0,否則返回非0值。

上述代碼中,以下代碼:

  1. printf("sizeof(str) = %ld\n", sizeof(str));
  2. printf("strlen(str) = %lu\n", strlen(str));

使用函數printf分別打印sizeof(str)和strlen(str)的值。從運行結果可以看出是不相同的。sizeof(str)輸出的是字符數組str中所有元素所占的字節數。strlen(str)輸出的是字符數組str中保存的字符串長度。

上述代碼中,以下代碼:

  1. strcat(str, " C++方向");
  2. printf("字符串拼接後為:%s\n", str);

使用函數strcat在字符串str的最後一個字符的後面連接上字符串" C++方向"。

上述代碼中,以下代碼:

  1. printf("字符串拆分的前一部分為:%s\n", strtok(str, " "));
  2. printf("字符串拆分的後一部分為:%s\n", strtok(NULL, " "));

使用函數strtok將剛拼接好的字符串str重新拆分成"tarena"和" C++方向"。

上述代碼中,以下代碼:

  1. char* p = strstr(str, "re");
  2. if (p)
  3. printf("子串re在字符串tarena中的位置為:%ld\n", p - str);
  4. else
  5. printf("子串re不在字符串tarena中\n");

首先,使用函數strstr在字符串str中查找子串"re"是否存在,如果存在則返回子串"re"的第一個字符r在字符串str的中的地址。然後,使用函數printf輸出字符r在字符串中的位置。如果不存在,則輸出子串不在字符串中。

上述代碼中,以下代碼:

  1. strcpy(str, "a 10 13.5");
  2. int i;
  3. double d;
  4. char c;
  5. sscanf(str, "%c%d%lf\n", &c, &i, &d);
  6. printf("%c %d %lf\n", c, i, d);

使用函數sscanf將字符串"a 10 13.5"中的字符a,整數10,雙精度浮點數13.5轉換到字符變量c,整型變量i,雙精度浮點型變量d中。

上述代碼中,以下代碼:

  1. memset(str, 0, sizeof(str));
  2. sprintf(str, "%c %d %lf\n", c, i, d);
  3. printf("%s\n", str);

首先,將字符數組str中的所有元素清0。

然後,使用sprintf將字符變量c,整型變量i,雙精度浮點型變量d中的值轉換成字符串,存儲到數組str中。

5.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2. #include
  3.  
  4. int main()
  5. {
  6. char str[100];
  7. strcpy(str, "tarena");
  8. printf("字符串為:%s\n", str);
  9.  
  10. if (strcmp(str, "tarena"))
  11. printf("字符串str與tarena不同\n");
  12. else
  13. printf("字符串str與tarena相同\n");
  14.  
  15. printf("sizeof(str) = %ld\n", sizeof(str));
  16. printf("strlen(str) = %lu\n", strlen(str));
  17.  
  18. strcat(str, " C++方向");
  19. printf("字符串拼接後為:%s\n", str);
  20.  
  21. printf("字符串拆分的前一部分為:%s\n", strtok(str, " "));
  22. printf("字符串拆分的後一部分為:%s\n", strtok(NULL, " "));
  23.  
  24. char* p = strstr(str, "re");
  25. if (p)
  26. printf("子串re在字符串tarena中的位置為:%ld\n", p - str);
  27. else
  28. printf("子串re不在字符串tarena中\n");
  29.  
  30. strcpy(str, "a 10 13.5");
  31. int i;
  32. double d;
  33. char c;
  34. sscanf(str, "%c%d%lf\n", &c, &i, &d);
  35. printf("%c %d %lf\n", c, i, d);
  36. memset(str, 0, sizeof(str));
  37. sprintf(str, "%c %d %lf\n", c, i, d);
  38. printf("%s\n", str);
  39.  
  40. return 0;
  41. }

6 字符串數組和命令行參數的使用

6.1 問題

定義三國五虎上將名單的數組,然後輸入人名,判斷是否是五虎上將。

6.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:定義五虎上將名單

使用字符指針數組作為名單。

代碼如下:

  1. #include
  2.  
  3. int main(int argc, const char * argv[])
  4. {
  5. char *tiger[5] = {"GuanYu", "ZhangFei", "ZhaoYun", "MaChao", "HuangZhong"};
  6.  
  7. return 0;
  8. }

步驟二:輸入一個名字

定義一個字符數組,用於存儲從控制台輸入的名字。

代碼如下:

  1. #include
  2.  
  3. int main(int argc, const char * argv[])
  4. {
  5. char *tiger[5] = {"GuanYu", "ZhangFei", "ZhaoYun", "MaChao", "HuangZhong"};
  6.  
  7. char name[20];
  8. printf("請輸入一個名字:");
  9. scanf("%s", name);
  10.  
  11. return 0;
  12. }

步驟三:遍歷數組

遍歷數組,逐個將數組元素與輸入的名字對比,查找是否為五虎上將之一。

  1. #include
  2. #include
  3.  
  4. int main(int argc, const char * argv[])
  5. {
  6. char *tiger[5] = {"GuanYu", "ZhangFei", "ZhaoYun", "MaChao", "HuangZhong"};
  7.  
  8. char name[20];
  9. printf("請輸入一個名字:");
  10. scanf("%s", name);
  11.  
  12. int i;
  13. for (i = 0; i < 5; i++)
  14. if (strcmp(name, tiger[i]) == 0)
  15. {
  16. printf("%s是五虎上將之一。\n", name);
  17. break;
  18. }
  19.  
  20. if (i == 5)
  21. printf("%s不是五虎上將之一。\n", name);
  22.  
  23. return 0;
  24. }

注意:strcmp函數需要包含string.h這個頭函數。

6.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2. #include
  3.  
  4. int main(int argc, const char * argv[])
  5. {
  6. char *tiger[5] = {"GuanYu", "ZhangFei", "ZhaoYun", "MaChao", "HuangZhong"};
  7.  
  8. char name[20];
  9. printf("請輸入一個名字:");
  10. scanf("%s", name);
  11.  
  12. int i;
  13. for (i = 0; i < 5; i++)
  14. if (strcmp(name, tiger[i]) == 0)
  15. {
  16. printf("%s是五虎上將之一。\n", name);
  17. break;
  18. }
  19.  
  20. if (i == 5)
  21. printf("%s不是五虎上將之一。\n", name);
  22.  
  23. return 0;
  24. }

1 #include指令的使用

1.1 問題

測試#include的用法,包括gcc –I指定目錄。

1.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:#include指令的使用

代碼如下所示:

  1. #include
  2. #include "print.c"
  3.  
  4. int main()
  5. {
  6. print();
  7.  
  8. return 0;
  9. }

上述代碼中,以下代碼:

  1. #include "print.c"

使用#include 指令將文件print.c中的內容添加到本程序的文件中。

上述代碼中,以下代碼:

  1. int main()
  2. {
  3. print();
  4.  
  5. return 0;
  6. }

在主程序中調用print.c中的函數print。

print.c代碼如下所示:

  1. void print()
  2. {
  3. printf("調用在文件print.c中的print函數\n");
  4. }

上述代碼中,以下代碼:

  1. printf("調用在文件print.c中的print函數\n");

使用函數printf輸出提示,該函數被調用了。

1.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2. #include "print.c"
  3.  
  4. int main()
  5. {
  6. print();
  7.  
  8. return 0;
  9. }

print.c代碼如下所示:

  1. void print()
  2. {
  3. printf("調用在文件print.c中的print函數\n");
  4. }

2 宏變量的使用

2.1 問題

測試宏變量的基本用法

2.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:宏變量的使用

代碼如下所示:

  1. #include
  2.  
  3. #define SIZE 10
  4. #define BEGIN int main() {
  5. #define END return 0; }
  6. #define LOOP for (int i = 0; i < SIZE; i++)
  7.  
  8. BEGIN
  9. int array[SIZE];
  10. printf("請輸入10個整數(空格分隔):");
  11. LOOP scanf("%d", &array[i]);
  12.  
  13. LOOP printf("array[%d] = %d\n", i, array[i]);
  14. END

上述代碼中,以下代碼:

  1. #define SIZE 10

定義一個宏變量SIZE,用於定義數組元素的個數。

上述代碼中,以下代碼:

  1. #define BEGIN int main() {

定義一個宏變量BEGIN,用於代替後面的主函數定義。

上述代碼中,以下代碼:

  1. #define END return 0; }

定義一個宏變量END,用於代替後面的主函數返回。

上述代碼中,以下代碼:

  1. #define LOOP for (int i = 0; i < SIZE; i++)

定義一個宏變量LOOP,用於代替設置一個循環。

上述代碼中,以下代碼:

  1. BEGIN

在預編譯階段,會被替代為以下語句:

  1. int main() {

上述代碼中,以下代碼:

  1. LOOP scanf("%d", &array[i]);

在預編譯階段,會被替代為以下語句:

  1. for (int i = 0; i < SIZE; i++) scanf("%d", &array[i]);

上述代碼中,以下代碼:

  1. LOOP printf("array[%d] = %d\n", i, array[i]);

在預編譯階段,會被替代為以下語句:

  1. for (int i = 0; i < SIZE; i++) printf("array[%d] = %d\n", i, array[i]);

上述代碼中,以下代碼:

  1. END

在預編譯階段,會被替代為以下語句:

  1. return 0; }

2.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2.  
  3. #define SIZE 10
  4. #define BEGIN int main() {
  5. #define END return 0; }
  6. #define LOOP for (int i = 0; i < SIZE; i++)
  7.  
  8. BEGIN
  9. int array[SIZE];
  10. printf("請輸入10個整數(空格分隔):");
  11. LOOP scanf("%d", &array[i]);
  12.  
  13. LOOP printf("array[%d] = %d\n", i, array[i]);
  14. END

3 宏函數的定義

3.1 問題

寫一個宏函數,用它來驗證一個日期是否合法。

3.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:宏函數的定義

  1. #define IS_DATE_VALID(year, month, day) \
  2. if ((year) > 2000 && (year) < 2020 && (month) > 0 && (month) < 13 && (day) > 0 && (day) < 32)\
  3. printf("日期合法\n");\
  4. else\
  5. printf("日期不合法\n");
  6.  
  7. int main()
  8. {
  9. IS_DATE_VALID(2015,3,15);
  10.  
  11. return 0;
  12. }

上述代碼中,以下代碼:

  1. #define IS_DATE_VALID(year, month, day) \
  2. if ((year) > 2000 && (year) < 2020 && (month) > 0 && (month) < 13 && (day) > 0 && (day) < 32)\
  3. printf("日期合法\n");\
  4. else\
  5. printf("日期不合法\n");

定義了一個宏函數IS_DATE_VALID,用於測試一個日期是否合法。上述代碼中,\ 代表換行,當宏函數中的字符串比較長時,可以用它來作為換行符,不能用回車,因為回車代表宏函數定義結束。

上述代碼中,以下代碼:

  1. IS_DATE_VALID(2015,3,15);

在預編譯階段,會被替代為以下語句:

  1. if ((year) > 2000 && (year) < 2020 && (month) > 0 && (month) < 13 && (day) > 0 && (day) < 32)\
  2. printf("日期合法\n");\
  3. else\
  4. printf("日期不合法\n");

3.3 完整代碼

本案例的完整代碼如下所示:

  1. #define IS_DATE_VALID(year, month, day) \
  2. if ((year) > 2000 && (year) < 2020 && (month) > 0 && (month) < 13 && (day) > 0 && (day) < 32)\
  3. printf("日期合法\n");\
  4. else\
  5. printf("日期不合法\n");
  6.  
  7. int main()
  8. {
  9. IS_DATE_VALID(2015,3,15);
  10.  
  11. return 0;
  12. }

4 條件編譯的使用

4.1 問題

寫一個頭文件,使用條件編譯實現避免重復include。

4.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:條件編譯的使用

main.c代碼如下所示:

  1. #include
  2. #include "print.h"
  3.  
  4. int main()
  5. {
  6. print();
  7.  
  8. return 0;
  9. }

上述代碼中,以下代碼:

  1. #include "print.h"

使用#include 指令將文件print.h中的內容添加到本程序的文件中。

print.h文件,代碼如下所示:

  1. #ifndef print_h
  2. #define print_h
  3.  
  4. void print();
  5.  
  6. #endif

上述代碼中,以下代碼:

  1. #ifndef print_h

使用條件編譯指令判斷宏名print_h是否已經定義,如果沒有定義繼續執行下面的語句,否則直接跳到#endif後面的語句執行。

上述代碼中,以下代碼:

  1. #define print_h

如果沒有定義宏名print_h,則執行此語句定義該宏名,這樣下一次再使用#ifndef判斷宏名print_h是否已經定義時,由於已經定義將跳過#endif之間的語句,防止重復include。

print.c文件,代碼如下所示:

  1. #include
  2. #include "print.h"
  3.  
  4. void print()
  5. {
  6. printf("避免重復include例題\n");
  7. }

上述代碼中,以下代碼:

  1. #include "print.h"

在main.c函數中已經有此語句,如果沒有條件編譯語句會多次包含print.h文件。

4.3 完整代碼

本案例的完整代碼如下所示:

main.c代碼如下所示:

  1. #include
  2. #include "print.h"
  3.  
  4. int main()
  5. {
  6. print();
  7.  
  8. return 0;
  9. }

print.h文件,代碼如下所示:

  1. #ifndef print_h
  2. #define print_h
  3.  
  4. void print();
  5.  
  6. #endif

print.c文件,代碼如下所示:

  1. #include
  2. #include "print.h"
  3.  
  4. void print()
  5. {
  6. printf("避免重復include例題\n");
  7. }

5 頭文件的使用

5.1 問題

寫一組頭文件,然後按照條件選擇一個進行編譯。

要求:實現避免重復導入並且測試static的作用。

5.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:short文件

short.h文件,代碼如下所示:

  1. #ifndef short_h
  2. #define short_h
  3.  
  4. short add(short a, short b);
  5. short sub(short a, short b);
  6.  
  7. #endif

上述代碼中,以下代碼:

  1. #ifndef short_h
  2. #define short_h
  3.  
  4.  
  5. #endif

為防止重復include而預設的條件編譯指令。

上述代碼中,以下代碼:

  1. short add(short a, short b);
  2. short sub(short a, short b);

聲明短整型的加法add、減法sub運算函數。

short.c文件,代碼如下所示:

  1. #include "short.h"
  2.  
  3. short add(short a, short b)
  4. {
  5. return a + b;
  6. }
  7.  
  8. short sub(short a, short b)
  9. {
  10. return a - b;
  11. }

上述代碼中,以下代碼:

  1. short add(short a, short b)
  2. {
  3. return a + b;
  4. }

短整型的加法add函數的定義。

上述代碼中,以下代碼:

  1. short sub(short a, short b)
  2. {
  3. return a - b;
  4. }

短整型的減法sub函數的定義。

步驟二:standard文件

standard.h文件,代碼如下所示:

  1. #ifndef int_h
  2. #define int_h
  3.  
  4. int add(int a, int b);
  5. int sub(int a, int b);
  6.  
  7. #endif

上述代碼中,以下代碼:

  1. int add(int a, int b);
  2. int sub(int a, int b);

聲明整型的加法add、減法sub運算函數。

standard.c文件,代碼如下所示:

  1. #include "standard.h"
  2.  
  3. int add(int a, int b)
  4. {
  5. return a + b;
  6. }
  7.  
  8. int sub(int a, int b)
  9. {
  10. return a - b;
  11. }

整型的加法add、減法sub運算函數的定義。

步驟三:long文件

long.h文件,代碼如下所示:

  1. #ifndef long_h
  2. #define long_h
  3.  
  4. long add(long a, long b);
  5. long sub(long a, long b);
  6.  
  7. #endif

上述代碼中,以下代碼:

  1. long add(long a, long b);
  2. long sub(long a, long b);

聲明長整型的加法add、減法sub運算函數。

long.c文件,代碼如下所示:

  1. #include "long.h"
  2.  
  3. long add(long a, long b)
  4. {
  5. return a + b;
  6. }
  7.  
  8. long sub(long a, long b)
  9. {
  10. return a - b;
  11. }

長整型的加法add、減法sub運算函數的定義。

步驟四:static文件

static.h文件,代碼如下所示:

  1. #ifndef int_h
  2. #define int_h
  3.  
  4. static void print();
  5. void call();
  6.  
  7. #endif

上述代碼中,以下代碼:

  1. static void print();

聲明了一個靜態函數。該函數只能在本文件內部使用,在其他的.c文件中無法使用。

上述代碼中,以下代碼:

  1. void call();

定義了一個普通函數。

static.c文件,代碼如下所示:

  1. #include
  2. #include "static.h"
  3.  
  4. static int ex = 10;
  5.  
  6. void print()
  7. {
  8. printf("這是靜態函數,只能在本文件中使用\n");
  9. }
  10.  
  11. void call()
  12. {
  13. print();
  14. printf("靜態變量:%d\n", ex);
  15. }

上述代碼中,以下代碼:

  1. static int ex = 10;

定義了一個靜態變量ex,該變量只能在本文件內部使用,在其他的.c文件中無法使用。

上述代碼中,以下代碼:

  1. void print()
  2. {
  3. printf("這是靜態函數,只能在本文件中使用\n");
  4. }

靜態函數print的定義。

上述代碼中,以下代碼:

  1. void call()
  2. {
  3. print();
  4. printf("靜態變量:%d\n", ex);
  5. }

普通函數call的定義。由於靜態函數print和靜態變量ex,都與函數call在同一個文件中,所以以下語句:

  1. print();
  2. printf("靜態變量:%d\n", ex);

對靜態函數print的調用和靜態變量ex的使用是合法的。

步驟五:main文件

main.h文件,代碼如下所示:

  1. #ifndef main_h
  2. #define main_h
  3.  
  4. #if defined(SHORT)
  5. #define FILE "short.h"
  6. #elif defined(STANDARD)
  7. #define FILE "standard.h"
  8. #elif defined(LONG)
  9. #define FILE "long.h"
  10. #endif
  11.  
  12. #include FILE
  13.  
  14. #endif

上述代碼中,以下代碼:

  1. #if defined(SHORT)
  2. #define FILE "short.h"

使用條件編譯語句#if判斷宏名SHORT是否定義,如果定義則定義宏名FILE為"short.h"。

上述代碼中,以下代碼:

  1. #elif defined(STANDARD)
  2. #define FILE "standard.h"

使用條件編譯語句#elif判斷宏名STANDARD是否定義,如果定義則定義宏名FILE為"standard.h"。

上述代碼中,以下代碼:

  1. #elif defined(LONG)
  2. #define FILE "long.h"

使用條件編譯語句#elif判斷宏名LONG是否定義,如果定義則定義宏名FILE為"long.h"。

上述代碼中,以下代碼:

  1. #include FILE

包含頭文件FILE。

main.c文件,代碼如下所示:

  1. #include
  2.  
  3. #define STANDARD
  4. #include "main.h"
  5. #include "static.h"
  6.  
  7. extern int ex;
  8.  
  9. int main()
  10. {
  11. printf("5 + 3 = %d\n", add(5, 3));
  12. printf("5 - 3 = %d\n", sub(5, 3));
  13.  
  14. //print();
  15. //printf("靜態變量:%d\n", ex);
  16. call();
  17.  
  18. return 0;
  19. }

上述代碼中,以下代碼:

  1. #define STANDARD
  2. #include "main.h"

定義宏名STANDARD,這樣在main.h中將執行#include "standard.h"。

上述代碼中,以下代碼:

  1. extern int ex;

聲明一個外部變量ex。變量ex定義在static.c中,但由於變量ex被定義成靜態變量,所以此語句沒有意義。

上述代碼中,以下代碼:

  1. printf("5 + 3 = %d\n", add(5, 3));
  2. printf("5 - 3 = %d\n", sub(5, 3));

調用的函數add和函數sub是被定義在standard.c中的函數add和函數sub。

上述代碼中,以下代碼:

  1. //print();

調用函數print是非法的。因為函數print是靜態函數,只能在static.c文件中被調用。

上述代碼中,以下代碼:

  1. //printf("靜態變量:%d\n", ex);

使用變量ex是非法的。因為變量ex是靜態變量,只能在static.c文件中被使用。

上述代碼中,以下代碼:

  1. call();

調用call函數是合法的,因為函數call不是靜態函數。

5.3 完整代碼

本案例的完整代碼如下所示:

short.h文件,代碼如下所示:

  1. #ifndef short_h
  2. #define short_h
  3.  
  4. short add(short a, short b);
  5. short sub(short a, short b);
  6.  
  7. #endif

short.c文件,代碼如下所示:

  1. #include "short.h"
  2.  
  3. short add(short a, short b)
  4. {
  5. return a + b;
  6. }
  7.  
  8. short sub(short a, short b)
  9. {
  10. return a - b;
  11. }

standard.h文件,代碼如下所示:

  1. #ifndef int_h
  2. #define int_h
  3.  
  4. int add(int a, int b);
  5. int sub(int a, int b);
  6.  
  7. #endif

standard.c文件,代碼如下所示:

  1. #include "standard.h"
  2.  
  3. int add(int a, int b)
  4. {
  5. return a + b;
  6. }
  7.  
  8. int sub(int a, int b)
  9. {
  10. return a - b;
  11. }

long.h文件,代碼如下所示:

  1. #ifndef long_h
  2. #define long_h
  3.  
  4. long add(long a, long b);
  5. long sub(long a, long b);
  6.  
  7. #endif

long.c文件,代碼如下所示:

  1. #include "long.h"
  2.  
  3. long add(long a, long b)
  4. {
  5. return a + b;
  6. }
  7.  
  8. long sub(long a, long b)
  9. {
  10. return a - b;
  11. }

static.h文件,代碼如下所示:

  1. #ifndef int_h
  2. #define int_h
  3.  
  4. static void print();
  5. void call();
  6.  
  7. #endif

static.c文件,代碼如下所示:

  1. #include
  2. #include "static.h"
  3.  
  4. static int ex = 10;
  5.  
  6. void print()
  7. {
  8. printf("這是靜態函數,只能在本文件中使用\n");
  9. }
  10.  
  11. void call()
  12. {
  13. print();
  14. printf("靜態變量:%d\n", ex);
  15. }

main.h文件,代碼如下所示:

  1. #ifndef main_h
  2. #define main_h
  3.  
  4. #if defined(SHORT)
  5. #define FILE "short.h"
  6. #elif defined(STANDARD)
  7. #define FILE "standard.h"
  8. #elif defined(LONG)
  9. #define FILE "long.h"
  10. #endif
  11.  
  12. #include FILE
  13.  
  14. #endif

main.c文件,代碼如下所示:

  1. #include
  2.  
  3. #define STANDARD
  4. #include "main.h"
  5. #include "static.h"
  6.  
  7. extern int ex;
  8.  
  9. int main()
  10. {
  11. printf("5 + 3 = %d\n", add(5, 3));
  12. printf("5 - 3 = %d\n", sub(5, 3));
  13.  
  14. //print();
  15. //printf("靜態變量:%d\n", ex);
  16. call();
  17.  
  18. return 0;
  19. }

6 makefile的使用

6.1 問題

分別使用靜態初始化和動態初始化的方式對數組進行賦值,並循環打印數組元素。

6.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:input文件

input.h,代碼如下所示:

  1. #ifndef input_h
  2. #define input_h
  3.  
  4. void input();
  5.  
  6. #endif

上述代碼中,以下代碼:

  1. void input();

聲明了一個函數input。

input.c,代碼如下所示:

  1. #include
  2.  
  3. extern int num;
  4.  
  5. void input()
  6. {
  7. printf("請輸入一個整數:");
  8. scanf("%d", &num);
  9. }

上述代碼中,以下代碼:

  1. extern int num;

聲明了一個外部變量num。該變量定義在main.c中。

上述代碼中,以下代碼:

  1. void input()
  2. {
  3. printf("請輸入一個整數:");
  4. scanf("%d", &num);
  5. }

定義了函數input。

步驟二:output文件

output.h,代碼如下所示:

  1. #ifndef output_h
  2. #define output_h
  3.  
  4. void output();
  5.  
  6. #endif

上述代碼中,以下代碼:

  1. void output();

聲明了一個函數output。

output.c,代碼如下所示:

  1. #include
  2.  
  3. extern int num;
  4.  
  5. void output()
  6. {
  7. printf("%d\n", num);
  8. }

上述代碼中,以下代碼:

  1. extern int num;

聲明了一個外部變量num。該變量定義在main.c中。

上述代碼中,以下代碼:

  1. void output()
  2. {
  3. printf("%d\n", num);
  4. }

定義了函數output。

步驟三:main文件

代碼如下所示:

  1. #include
  2. #include "input.h"
  3. #include "output.h"
  4.  
  5. int num;
  6.  
  7. int main()
  8. {
  9. input();
  10. output();
  11.  
  12. return 0;
  13. }

上述代碼中,以下代碼:

  1. int num;

定義了一個全局變量num。

上述代碼中,以下代碼:

  1. input();
  2. output();

調用函數input,對變量num進行輸入。

調用函數output,對變量num進行輸出。

步驟四:makefile文件

代碼如下所示:

  1. main:main.o input.o output.o
  2. gcc main.c input.c output.c
  3.  
  4. main.o:main.c
  5. gcc main.c -c
  6. input.o:input.c
  7. gcc input.c -c
  8. output.o:output.c
  9. gcc output.c -c

可以使用makefile文件來一次性執行多條命令(批處理命令)。makefile帶來的好處就是“自動化編譯”,一旦寫好,只需要一個make命令,整個工程完全自動編譯,極大的提高了軟件開發的效率。

6.3 完整代碼

本案例的完整代碼如下所示:

input.h,代碼如下所示:

  1. #ifndef input_h
  2. #define input_h
  3.  
  4. void input();
  5.  
  6. #endif

input.c,代碼如下所示:

  1. #include
  2.  
  3. extern int num;
  4.  
  5. void input()
  6. {
  7. printf("請輸入一個整數:");
  8. scanf("%d", &num);
  9. }

output.h,代碼如下所示:

  1. #ifndef output_h
  2. #define output_h
  3.  
  4. void output();
  5.  
  6. #endif

output.c,代碼如下所示:

  1. #include
  2.  
  3. extern int num;
  4.  
  5. void output()
  6. {
  7. printf("%d\n", num);
  8. }

main文件,代碼如下所示:

  1. #include
  2. #include "input.h"
  3. #include "output.h"
  4.  
  5. int num;
  6.  
  7. int main()
  8. {
  9. input();
  10. output();
  11.  
  12. return 0;
  13. }

makefile文件,代碼如下所示:

  1. main:main.o input.o output.o
  2. gcc main.c input.c output.c
  3.  
  4. main.o:main.c
  5. gcc main.c -c
  6. input.o:input.c
  7. gcc input.c -c
  8. output.o:output.c
  9. gcc output.c -c
Top


 

1 結構的聲明和初始化

1.1 問題

定義測試結構體,並進行聲明變量和初始化。

1.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:結構的聲明和初始化

代碼如下所示:

  1. #include
  2.  
  3. struct student
  4. {
  5. int id;
  6. char name[10];
  7. }stu1;
  8.  
  9. int main()
  10. {
  11. stu1.id = 110;
  12. strcpy(stu1.name, "zhangsan");
  13. printf("學號:%d, 姓名:%s", stu1.id, stu1.name);
  14.  
  15. struct student stu2 = {112, "lisi"};
  16. printf("學號:%d, 姓名:%s", stu2.id, stu2.name);
  17.  
  18. return 0;
  19. }

上述代碼中,以下代碼:

  1. struct student
  2. {
  3. int id;
  4. char name[10];
  5. }stu1;

定義學生結構體student。該結構體有兩個成員,第一個成員是學號id,第二個成員是姓名name。在定義結構體student的同時定義了結構體變量stu1。

上述代碼中,以下代碼:

  1. stu1.id = 110;
  2. strcpy(stu1.name, "zhangsan");
  3. printf("學號:%d, 姓名:%s", stu1.id, stu1.name);

首先,將結構體變量stu1的學號成員賦值為110。

然後,將結構體變量stu1的姓名成員賦值為"zhangsan"。

最後,輸出結構體變量stu1。

上述代碼中,以下代碼:

  1. struct student stu2 = {112, "lisi"};
  2. printf("學號:%d, 姓名:%s", stu2.id, stu2.name);

首先,定義了另一個結構體變量stu2,並對其進行初始化,將學號成員初始化為112,姓名成員初始化為"lisi"。

然後,輸出結構體變量stu2。

1.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2.  
  3. struct student
  4. {
  5. int id;
  6. char name[10];
  7. }stu1;
  8.  
  9. int main()
  10. {
  11. stu1.id = 110;
  12. strcpy(stu1.name, "zhangsan");
  13. printf("學號:%d, 姓名:%s", stu1.id, stu1.name);
  14.  
  15. struct student stu2 = {112, "lisi"};
  16. printf("學號:%d, 姓名:%s", stu2.id, stu2.name);
  17.  
  18. return 0;
  19. }

2 結構的聲明和初始化(續1)

2.1 問題

定義結構點point,計算每個點離(0,0)的距離。

再定義結構rect(矩形),由兩個點組成,計算矩形的面積。

2.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:結構的聲明和初始化(續1)

代碼如下所示:

  1. #include
  2. #include
  3. #include
  4.  
  5. struct point
  6. {
  7. int x;
  8. int y;
  9. };
  10.  
  11. struct rect
  12. {
  13. struct point left_top;
  14. struct point right_bottom;
  15. };
  16.  
  17. int main()
  18. {
  19. struct point dot = {10, 20};
  20. int dis = sqrt(dot.x * dot.x + dot.y * dot.y);
  21. printf("點(%d,%d)到原點(0,0)的距離是:%d\n", dot.x, dot.y, dis);
  22.  
  23. struct point a = {10, 10};
  24. struct point b = {50, 30};
  25. struct rect r = {a, b};
  26. int area = abs(r.left_top.x - r.right_bottom.x) * abs(r.left_top.y - r.right_bottom.y);
  27. printf("矩形的面積是:%d\n", area);
  28.  
  29.  
  30. return 0;
  31. }

上述代碼中,以下代碼:

  1. struct point
  2. {
  3. int x;
  4. int y;
  5. };

定義一個結構體point,該結構體有兩個成員,x軸坐標x,y軸坐標y。

上述代碼中,以下代碼:

  1. struct rect
  2. {
  3. struct point left_top;
  4. struct point right_bottom;
  5. };

定義一個結構體rect,該結構體有兩個成員,左上角點坐標left_top,右下角點坐標right_bottom。

上述代碼中,以下代碼:

  1. struct point dot = {10, 20};

定義一個結構體point的變量dot,並初始化為(10,20)。

上述代碼中,以下代碼:

  1. int dis = sqrt(dot.x * dot.x + dot.y * dot.y);

計算點dot到原點的距離。

上述代碼中,以下代碼:

  1. struct point a = {10, 10};
  2. struct point b = {50, 30};
  3. struct rect r = {a, b};

首先,定義兩個結構體point的變量a和b,並初始化為(10,10)和(50,30)。

然後,定義結構體rect的變量r,並用上述兩個結構體point的變量a和b初始化。

上述代碼中,以下代碼:

  1. int area = abs(r.left_top.x - r.right_bottom.x) * abs(r.left_top.y - r.right_bottom.y);

計算矩形r面積。

2.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2. #include
  3. #include
  4.  
  5. struct point
  6. {
  7. int x;
  8. int y;
  9. };
  10.  
  11. struct rect
  12. {
  13. struct point left_top;
  14. struct point right_bottom;
  15. };
  16.  
  17. int main()
  18. {
  19. struct point dot = {10, 20};
  20. int dis = sqrt(dot.x * dot.x + dot.y * dot.y);
  21. printf("點(%d,%d)到原點(0,0)的距離是:%d\n", dot.x, dot.y, dis);
  22.  
  23. struct point a = {10, 10};
  24. struct point b = {50, 30};
  25. struct rect r = {a, b};
  26. int area = abs(r.left_top.x - r.right_bottom.x) * abs(r.left_top.y - r.right_bottom.y);
  27. printf("矩形的面積是:%d\n", area);
  28.  
  29.  
  30. return 0;
  31. }

3 結構的聲明和初始化(續2)

3.1 問題

定義一個包含月份的名字和這個月天數的結構,用一個結構的數組保存一年中的所有月份和天數,在每個結構中保存一個月的名字和天數。

月份英文:January、February、March、April、May、June、July、August、September、October、November、December。

3.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:結構的聲明和初始化(續2)

代碼如下所示:

  1. #include
  2.  
  3. struct month
  4. {
  5. char name[10];
  6. int days;
  7. };
  8.  
  9. int main()
  10. {
  11. struct month m[12] = {
  12. {"January", 31},
  13. {"February", 28},
  14. {"March", 31},
  15. {"April", 30},
  16. {"May", 31},
  17. {"June", 30},
  18. {"July", 31},
  19. {"August", 31},
  20. {"September", 30},
  21. {"October", 31},
  22. {"November", 30},
  23. {"December", 31}};
  24.  
  25. for (int i = 0; i < 12; i++)
  26. printf("%d月的名字是:%s,天數是:%d\n", i + 1, m[i].name, m[i].days);
  27.  
  28. return 0;
  29. }

上述代碼中,以下代碼:

  1. struct month
  2. {
  3. char name[10];
  4. int days;
  5. };

定義一個結構體month,該結構體有兩個成員,該月的英文名字和該月的天數。

上述代碼中,以下代碼:

  1. struct month m[12] = {
  2. {"January", 31},
  3. {"February", 28},
  4. {"March", 31},
  5. {"April", 30},
  6. {"May", 31},
  7. {"June", 30},
  8. {"July", 31},
  9. {"August", 31},
  10. {"September", 30},
  11. {"October", 31},
  12. {"November", 30},
  13. {"December", 31}};

定義了一個結構體month的數組m,該數組有12個元素,每個元素代表一年中的一個月。定義數組m之後,對其進行了初始化。

注意:初始化時,每個數組元素的值用{}括起來。

3.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2.  
  3. struct month
  4. {
  5. char name[10];
  6. int days;
  7. };
  8.  
  9. int main()
  10. {
  11. struct month m[12] = {
  12. {"January", 31},
  13. {"February", 28},
  14. {"March", 31},
  15. {"April", 30},
  16. {"May", 31},
  17. {"June", 30},
  18. {"July", 31},
  19. {"August", 31},
  20. {"September", 30},
  21. {"October", 31},
  22. {"November", 30},
  23. {"December", 31}};
  24.  
  25. for (int i = 0; i < 12; i++)
  26. printf("%d月的名字是:%s,天數是:%d\n", i + 1, m[i].name, m[i].days);
  27.  
  28. return 0;
  29. }

4 結構做參數

4.1 問題

對比結構做參數的兩種方式,使用->操作成員。

4.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:結構做參數

代碼如下所示:

  1. #include
  2. #include
  3.  
  4. struct student
  5. {
  6. int id;
  7. char name[10];
  8. }stu;
  9.  
  10. void print1(struct student stu)
  11. {
  12. printf("學號:%d, 姓名:%s\n", stu.id, stu.name);
  13. }
  14.  
  15. void print2(struct student *p)
  16. {
  17. printf("學號:%d, 姓名:%s\n", p->id, p->name);
  18. }
  19.  
  20. int main()
  21. {
  22. stu.id = 110;
  23. strcpy(stu.name, "zhangsan");
  24. print1(stu);
  25. print2(&stu);
  26.  
  27. return 0;
  28. }

上述代碼中,以下代碼:

  1. struct student
  2. {
  3. int id;
  4. char name[10];
  5. }stu;

定義學生結構體student。該結構體有兩個成員,第一個成員是學號id,第二個成員是姓名name。在定義結構體student的同時定義了結構體變量stu。

上述代碼中,以下代碼:

  1. void print1(struct student stu)
  2. {
  3. printf("學號:%d, 姓名:%s\n", stu.id, stu.name);
  4. }

定義了一個函數print1,用於打印結構體student的變量的值。該函數有一個參數,是結構體student的變量stu。這是值傳遞的方法。結構體student的變量stu將是實參的副本。

上述代碼中,以下代碼:

  1. void print2(struct student *p)
  2. {
  3. printf("學號:%d, 姓名:%s\n", p->id, p->name);
  4. }

定義了一個函數print2,用於打印結構體student的變量的值。該函數有一個參數,是結構體student的指針變量p。這是地址傳遞的方法。結構體student的指針變量p將指向實參。該函數中,p->id是用指針p指向的結構體student的變量的id成員。

上述代碼中,以下代碼:

  1. stu.id = 110;
  2. strcpy(stu.name, "zhangsan");

首先,將結構體student的變量stu的id成員賦值為110。

然後,將結構體student的變量stu的name成員賦值為"zhangsan"。

上述代碼中,以下代碼:

  1. print1(stu);

調用值傳遞方法的print1函數,實參為結構體student的變量stu。

上述代碼中,以下代碼:

  1. print2(&stu);

調用地址傳遞方法的print2函數,實參為結構體student的變量stu的地址。

4.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2. #include
  3.  
  4. struct student
  5. {
  6. int id;
  7. char name[10];
  8. }stu;
  9.  
  10. void print1(struct student stu)
  11. {
  12. printf("學號:%d, 姓名:%s\n", stu.id, stu.name);
  13. }
  14.  
  15. void print2(struct student *p)
  16. {
  17. printf("學號:%d, 姓名:%s\n", p->id, p->name);
  18. }
  19.  
  20. int main()
  21. {
  22. stu.id = 110;
  23. strcpy(stu.name, "zhangsan");
  24. print1(stu);
  25. print2(&stu);
  26.  
  27. return 0;
  28. }

5 結構做返回值

5.1 問題

測試直接返回結構的問題,並實現用結構指針參數帶出數據。

5.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:結構做返回值

代碼如下所示:

  1. #include
  2.  
  3. struct student
  4. {
  5. int id;
  6. char name[10];
  7. };
  8.  
  9. struct student input1()
  10. {
  11. struct student stu;
  12. printf("輸入學號:");
  13. scanf("%d", &stu.id);
  14. printf("輸入姓名:");
  15. scanf("%s", stu.name);
  16.  
  17. return stu;
  18. }
  19.  
  20. void input2(struct student *p)
  21. {
  22. printf("輸入學號:");
  23. scanf("%d", &p->id);
  24. printf("輸入姓名:");
  25. scanf("%s", p->name);
  26. }
  27.  
  28. int main()
  29. {
  30. struct student stu;
  31. stu = input1();
  32. printf("學號:%d, 姓名:%s\n", stu.id, stu.name);
  33.  
  34. input2(&stu);
  35. printf("學號:%d, 姓名:%s\n", stu.id, stu.name);
  36.  
  37. return 0;
  38. }

上述代碼中,以下代碼:

  1. struct student
  2. {
  3. int id;
  4. char name[10];
  5. };

定義學生結構體student。該結構體有兩個成員,第一個成員是學號id,第二個成員是姓名name。

上述代碼中,以下代碼:

  1. struct student input1()
  2. {
  3. struct student stu;
  4. printf("輸入學號:");
  5. scanf("%d", &stu.id);
  6. printf("輸入姓名:");
  7. scanf("%s", stu.name);
  8.  
  9. return stu;
  10. }

定義一個函數input1,用於輸入。該函數中,以下語句:

  1. struct student stu;

定義了一個局部結構體student的變量stu。該函數中,以下語句:

  1. printf("輸入學號:");
  2. scanf("%d", &stu.id);
  3. printf("輸入姓名:");
  4. scanf("%s", stu.name);

輸入學號和姓名。該函數中,以下語句:

  1. return stu;

返回結構體student的變量stu。

上述代碼中,以下代碼:

  1. void input2(struct student *p)
  2. {
  3. printf("輸入學號:");
  4. scanf("%d", &p->id);
  5. printf("輸入姓名:");
  6. scanf("%s", p->name);
  7. }

定義一個函數input2,用於輸入,該函數有一個參數,是指向結構體student的指針變量p。該函數中,以下語句:

  1. printf("輸入學號:");
  2. scanf("%d", &p->id);
  3. printf("輸入姓名:");
  4. scanf("%s", p->name);

將學號和姓名輸入到結構體student的指針變量p指向的實參。

上述代碼中,以下代碼:

  1. int main()
  2. {
  3. struct student stu;
  4. stu = input1();
  5. printf("學號:%d, 姓名:%s\n", stu.id, stu.name);

在主函數中,定義結構體student的變量stu,用於接收函數input1的返回值。

上述代碼中,以下代碼:

  1. input2(&stu);
  2. printf("學號:%d, 姓名:%s\n", stu.id, stu.name);

在主函數中,將結構體student的變量stu的地址作為實參傳入input2,以輸入其值。

5.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2.  
  3. struct student
  4. {
  5. int id;
  6. char name[10];
  7. };
  8.  
  9. struct student input1()
  10. {
  11. struct student stu;
  12. printf("輸入學號:");
  13. scanf("%d", &stu.id);
  14. printf("輸入姓名:");
  15. scanf("%s", stu.name);
  16.  
  17. return stu;
  18. }
  19.  
  20. void input2(struct student *p)
  21. {
  22. printf("輸入學號:");
  23. scanf("%d", &p->id);
  24. printf("輸入姓名:");
  25. scanf("%s", p->name);
  26. }
  27.  
  28. int main()
  29. {
  30. struct student stu;
  31. stu = input1();
  32. printf("學號:%d, 姓名:%s\n", stu.id, stu.name);
  33.  
  34. input2(&stu);
  35. printf("學號:%d, 姓名:%s\n", stu.id, stu.name);
  36.  
  37. return 0;
  38. }

6 結構的對齊和補齊

6.1 問題

對齊是指由於內存分配會將結構中的變量分配到內存的邊界上,以方便訪問。每個成員放的位置是從本身長度的倍數位開始放。

補齊是指整個結構變量的長度要保持內部最長成員(超過4以4計)的倍數。如果不夠,則補齊。

6.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:結構的對齊和補齊

代碼如下所示:

  1. #include
  2.  
  3. struct size
  4. {
  5. char c;
  6. int i;
  7. };
  8.  
  9. int main()
  10. {
  11. printf("sizeof(size) = %ld\n", sizeof(struct size));
  12.  
  13. return 0;
  14. }

上述代碼中,以下代碼:

  1. struct size
  2. {
  3. char c;
  4. int i;
  5. };

定義一個結構體size,該結構體有兩個成員,字符型變量c和整型變量i。

上述代碼中,以下代碼:

  1. printf("sizeof(size) = %ld\n", sizeof(struct size));

輸出結構體size所占的字節數。從輸出結果可知是8個字節。為什麼不是5個字節呢?

原因是字符對齊的概念。當一個結構體被分配存儲空間時,分配的方法是這樣的:

首先,找到結構體中占字節數最多的成員,本案例中是整型變量i。

然後,以該成員所占的字節數為單位,為結構體的每個成員分配存儲空間。在本案例中,為第一個成員字符型變量c分配4個字節,該成員用掉1個字節,剩下3個字節。字符型變量c所占的那個字節的編號設為0,剩下的3個字節編號依次為1、2、3。

最後,為第二個成員整型變量i分配存儲空間,由於剩下的3個字節的編號依次為1、2、3,用這些編號對整型變量i所占字節數4求余,結果都不為0,所以剩下的3個字節都跳過。而再分配4個字節給整型變量i。

所以本案例的輸出結果為8個字節,而不是5個字節。因為有三個字節沒有用。

6.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2.  
  3. struct size
  4. {
  5. char c;
  6. int i;
  7. };
  8.  
  9. int main()
  10. {
  11. printf("sizeof(size) = %ld\n", sizeof(struct size));
  12.  
  13. return 0;
  14. }

7 聯合的基本用法

7.1 問題

聯合就是一塊內存對應不同的類型,並起了不同的名字,在使用時按照名字切換類型,而不是用類型轉換。

7.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:聯合的基本用法

代碼如下所示:

  1. #include
  2.  
  3. union data
  4. {
  5. int a;
  6. int b;
  7. int c;
  8. };
  9.  
  10. int main()
  11. {
  12. union data d;
  13. d.a = 10;
  14. printf("%d %d %d\n", d.a, d.b, d.c);
  15.  
  16. d.b = 20;
  17. printf("%d %d %d\n", d.a, d.b, d.c);
  18.  
  19. d.c = 30;
  20. printf("%d %d %d\n", d.a, d.b, d.c);
  21.  
  22. return 0;
  23. }

上述代碼中,以下代碼:

  1. union data
  2. {
  3. int a;
  4. int b;
  5. int c;
  6. };

定義了一個聯合data,該聯合中有三個成員,這三個成員共用4個字節。

上述代碼中,以下代碼:

  1. union data d;
  2. d.a = 10;
  3. printf("%d %d %d\n", d.a, d.b, d.c);

首先,定義一個聯合data的變量d。

然後,將聯合data的變量d的第一個成員a賦值為10。

最後,使用printf輸出聯合data的三個成員的值。從輸出結果可以看出,值都相同。而且,後兩個成員未賦值。原因是聯合data的三個成員共用4個字節。

上述代碼中,以下代碼:

  1. d.b = 20;
  2. printf("%d %d %d\n", d.a, d.b, d.c);

將聯合data的變量d的第二個成員b賦值為20。從輸出結果可以看出,聯合data的三個成員的值都相同。原因是聯合data的三個成員共用4個字節。

上述代碼中,以下代碼:

  1. d.c = 30;
  2. printf("%d %d %d\n", d.a, d.b, d.c);

將聯合data的變量d的第三個成員c賦值為30。從輸出結果可以看出,聯合data的三個成員的值還是都相同。原因還是聯合data的三個成員共用4個字節。

7.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2.  
  3. union data
  4. {
  5. int a;
  6. int b;
  7. int c;
  8. };
  9.  
  10. int main()
  11. {
  12. union data d;
  13. d.a = 10;
  14. printf("%d %d %d\n", d.a, d.b, d.c);
  15.  
  16. d.b = 20;
  17. printf("%d %d %d\n", d.a, d.b, d.c);
  18.  
  19. d.c = 30;
  20. printf("%d %d %d\n", d.a, d.b, d.c);
  21.  
  22. return 0;
  23. }

8 枚舉的基本用法

8.1 問題

枚舉是一個整型常量的列表,一般來說,值是有限個。每個值都是枚舉常量(整型)。可以定義時指定值,也可以多個枚舉名表示同一個值。枚舉常量可看成字面量。

8.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:枚舉的基本用法

代碼如下所示:

  1. #include
  2.  
  3. enum WEEK
  4. {
  5. Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday,
  6. };
  7.  
  8. int main()
  9. {
  10. int day;
  11. printf("請輸入今天是星期幾:");
  12. scanf("%d", &day);
  13.  
  14. switch(day)
  15. {
  16. case Monday:
  17. printf("星期一\n");
  18. break;
  19. case Tuesday:
  20. printf("星期二\n");
  21. break;
  22. case Wednesday:
  23. printf("星期三\n");
  24. break;
  25. case Thursday:
  26. printf("星期四\n");
  27. break;
  28. case Friday:
  29. printf("星期五\n");
  30. break;
  31. case Saturday:
  32. printf("星期六\n");
  33. break;
  34. case Sunday:
  35. printf("星期日\n");
  36. break;
  37. }
  38.  
  39. return 0;
  40. }

上述代碼中,以下代碼:

  1. enum WEEK
  2. {
  3. Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday,
  4. };

定義了一個枚舉WEEK,是一個整型常量的列表,Monday是1,後面的值依次加1。

上述代碼中,以下代碼:

  1. int day;
  2. printf("請輸入今天是星期幾:");
  3. scanf("%d", &day);

首先,定義一個整型變量day,用於存儲星期幾的整數。

然後,使用printf提示輸出輸入星期幾。

最後,使用scanf輸入星期幾到整型變量day中。

上述代碼中,以下代碼:

  1. switch(day)
  2. {
  3. case Monday:
  4. printf("星期一\n");
  5. break;
  6. case Tuesday:
  7. printf("星期二\n");
  8. break;
  9. case Wednesday:
  10. printf("星期三\n");
  11. break;
  12. case Thursday:
  13. printf("星期四\n");
  14. break;
  15. case Friday:
  16. printf("星期五\n");
  17. break;
  18. case Saturday:
  19. printf("星期六\n");
  20. break;
  21. case Sunday:
  22. printf("星期日\n");
  23. break;
  24. }

使用switch結構將整形星期幾轉換成字符串的星期幾。其中每個case後面為一個枚舉值。

8.3 完整代碼

本案例的完整代碼如下所示:

  1. #include
  2.  
  3. enum WEEK
  4. {
  5. Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday,
  6. };
  7.  
  8. int main()
  9. {
  10. int day;
  11. printf("請輸入今天是星期幾:");
  12. scanf("%d", &day);
  13.  
  14. switch(day)
  15. {
  16. case Monday:
  17. printf("星期一\n");
  18. break;
  19. case Tuesday:
  20. printf("星期二\n");
  21. break;
  22. case Wednesday:
  23. printf("星期三\n");
  24. break;
  25. case Thursday:
  26. printf("星期四\n");
  27. break;
  28. case Friday:
  29. printf("星期五\n");
  30. break;
  31. case Saturday:
  32. printf("星期六\n");
  33. break;
  34. case Sunday:
  35. printf("星期日\n");
  36. break;
  37. }
  38.  
  39. return 0;
  40. }
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved