欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C语言08字符串 & 预处理 & 结构体

程序员文章站 2022-08-13 20:46:28
项目开发中字符串模型建立 strstr的while dowhile模型 //int cltClient_rev(void *ha...

项目开发中字符串模型建立

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 指令将