C语言08字符串 & 预处理 & 结构体
项目开发中字符串模型建立
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 步骤
实现此案例需要按照如下步骤进行。
步骤一:字符串地址的测试
代码如下所示:
- #include
- #include
- int main()
- {
- char *str = "This is a string.";
- char array[100];
- strcpy(array, str);
- printf("字符串常量的地址:%p\n", str);
- printf("字符数组的地址:%p\n", array);
- return 0;
- }
上述代码中,以下代码:
- char *str = "This is a string.";
定义了一个字符型指针str,用于指向一个字符串常量。
上述代码中,以下代码:
- printf("字符串常量的地址:%p\n", str);
- printf("字符数组的地址:%p\n", array);
使用printf函数分别输出字符串常量的地址和字符数组的地址。从输出结果可见,它们是不相同的。
1.3 完整代码
本案例的完整代码如下所示:
- #include
- #include
- int main()
- {
- char *str = "This is a string.";
- char array[100];
- strcpy(array, str);
- printf("字符串常量的地址:%p\n", str);
- printf("字符数组的地址:%p\n", array);
- return 0;
- }
2 字符串的定义和使用
2.1 问题
定义一个int类型的指针,指向一个整型变量,然后分别使用&和*取得地址或者数据。
2.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:字符串的定义和使用
代码如下所示:
- #include
- int main()
- {
- char str[5] = {};
- scanf("%4s", str);
- printf("%s\n", str);
- return 0;
- }
上述代码中,以下代码:
- char str[5] = {};
定义了一个字符数组str,该数组有5个元素。
上述代码中,以下代码:
- scanf("%4s", str);
使用scanf函数输入一个字符串。其中,%4s是限定输入的字符串中字符的个数不能大于4,否则将只输入前4个字符。指定值为4是因为字符数组str的长度为5,多出来的一个需要存储\0。
上述代码中,以下代码:
- printf("%s\n", str);
使用函数printf输出字符串。字符数组所对应的格式控制符是%s。
2.3 完整代码
本案例的完整代码如下所示:
- #include
- int main()
- {
- char str[5] = {};
- scanf("%4s", str);
- printf("%s\n", str);
- return 0;
- }
3 字符串函数的使用
3.1 问题
使用指针实现字符串的函数strlen()、strcat()的功能,可以自定义两个函数。
3.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:字符串函数的使用
代码如下所示:
- #include
- int mystrlen(char *str)
- {
- int count = 0;
- while (*str)
- {
- count++;
- str++;
- }
- return count;
- }
- char* mystrcat(char *s, char *d)
- {
- char* old = s;
- while(*s)
- s++;
- while(*d)
- {
- *s = *d;
- s++;
- d++;
- }
- return old;
- }
- int main()
- {
- char str[100] = "This is ";
- printf("str的长度为:%d\n", mystrlen(str));
- char* str1 = "a string";
- mystrcat(str, str1);
- printf("连接后的字符串为:%s\n", str);
- return 0;
- }
上述代码中,以下代码:
- int mystrlen(char *str)
- {
- int count = 0;
- while (*str)
- {
- count++;
- str++;
- }
- return count;
- }
定义了一个函数mystrlen,用于模拟库函数strlen的功能。该函数的参数为求长度的字符串。在该函数中,以下语句:
- int count = 0;
首先定义一个整型变量count,用于存储字符串中字符的个数。在该函数中,以下语句:
- while (*str)
- {
- count++;
- str++;
- }
设置一个循环,逐个计算字符串中字符的个数,当*str不为\0时,代表该字符串没有结束。在该函数中,以下语句:
- return count;
返回字符串的长度。
上述代码中,以下代码:
- char* mystrcat(char *s, char *d)
- {
- char* old = s;
- while(*s)
- s++;
- while(*d)
- {
- *s = *d;
- s++;
- d++;
- }
- return old;
- }
定义了一个函数mystrcat,用于模拟库函数strcat的功能。该函数的两个参数为将字符串d连接到字符串s的后面。在该函数中,以下语句:
- char* old = s;
首先保存被连接字符串的首地址,用于函数结束返回时作返回值用。在该函数中,以下语句:
- while(*s)
- s++;
设置一个循环找到被连接字符串的结束符\0,以便将另一个字符串连接到这个位置。在该函数中,以下语句:
- while(*d)
- {
- *s = *d;
- s++;
- d++;
- }
设置一个循环将字符串d的每一个字符拷贝到字符串s的结束字符\0开始的空间中,实现连接功能。在该函数中,以下语句:
- return old;
返回字符串s的首字符地址。
注意:由于上述循环中,指针s已经发生了变化,所以不能直接返回。
上述代码中,以下代码:
- int main()
- {
- char str[100] = "This is ";
- printf("str的长度为:%d\n", mystrlen(str));
首先,在主函数中定义一个字符数组,用于存储字符串"This is "。
然后,调用自定义函数mystrlen求得字符数组的长度,并输出。
上述代码中,以下代码:
- char* str1 = "a string";
- mystrcat(str, str1);
- printf("连接后的字符串为:%s\n", str);
首先,在主函数中定义一个字符指针,用于指向字符串"a string"。
然后,调用自定义函数mystrcat将字符指针指向的字符串拼接到字符数组str中,并输出。
最后,输出连接后的字符数组str。
3.3 完整代码
本案例的完整代码如下所示:
- #include
- int mystrlen(char *str)
- {
- int count = 0;
- while (*str)
- {
- count++;
- str++;
- }
- return count;
- }
- char* mystrcat(char *s, char *d)
- {
- char* old = s;
- while(*s)
- s++;
- while(*d)
- {
- *s = *d;
- s++;
- d++;
- }
- return old;
- }
- int main()
- {
- char str[100] = "This is ";
- printf("str的长度为:%d\n", mystrlen(str));
- char* str1 = "a string";
- mystrcat(str, str1);
- printf("连接后的字符串为:%s\n", str);
- return 0;
- }
4 字符串函数的使用(续1)
4.1 问题
使用指针函数实现文件名和文件目录的拼接。
4.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:字符串函数的使用(续1)
代码如下所示:
- #include
- char* filenamecat(char *path, char* name)
- {
- char* old = path;
- while(*path)
- path++;
- if (*(path - 1) != '/')
- {
- *path = '/';
- path++;
- }
- while(*name)
- {
- *path = *name;
- path++;
- name++;
- }
- return path;
- }
- int main()
- {
- char path[100] = "/home/tarena/";
- char* filename = "字符串函数的使用.c";
- filenamecat(path, filename);
- printf("带路径的文件名为:%s\n", path);
- return 0;
- }
上述代码中,下面代码行:
- char* filenamecat(char *path, char* name)
- {
- char* old = path;
- while(*path)
- path++;
- if (*(path - 1) != '/')
- {
- *path = '/';
- path++;
- }
- while(*name)
- {
- *path = *name;
- path++;
- name++;
- }
- return old;
- }
定义了一个函数filenamecat,用于拼接文件路径和文件名的功能。该函数的两个参数为将文件名字符串name连接到路径字符串path的后面。在该函数中,以下语句:
- char* old = path;
首先保存路径字符串的首地址,用于函数结束返回时作返回值用。在该函数中,以下语句:
- while(*path)
- path++;
设置一个循环找到路径字符串的结束符\0,以便将文件名字符串连接到这个位置。在该函数中,以下语句:
- if (*(path - 1) != '/')
- {
- *path = '/';
- path++;
- }
判断路径字符串的最后一个字符是否是/,如果不是则首先在路径字符串的最后添加字符/。在该函数中,以下语句:
- while(*name)
- {
- *path = *name;
- path++;
- name++;
- }
设置一个循环将文件名字符串name的每一个字符拷贝到路径字符串path的结束字符/后面的空间中,实现连接功能。在该函数中,以下语句:
- return old;
返回路径字符串path的首字符地址。
注意:由于上述循环中,指针path已经发生了变化,所以不能直接返回path。
上述代码中,下面代码行:
- int main()
- {
- char path[100] = "/home/tarena/";
- char* filename = "字符串函数的使用.c";
首先,定义一个数组path,用于保存路径名。
然后,定义一个指针filename,用于指向文件名。
上述代码中,下面代码行:
- filenamecat(path, filename);
调用自定义函数filenamecat,将文件名filename连接到路径名path的后面。
上述代码中,下面代码行:
- printf("带路径的文件名为:%s\n", path);
使用函数printf输出连接后的路径加文件名。
4.3 完整代码
本案例的完整代码如下所示:
- #include
- char* filenamecat(char *path, char* name)
- {
- char* old = path;
- while(*path)
- path++;
- if (*(path - 1) != '/')
- {
- *path = '/';
- path++;
- }
- while(*name)
- {
- *path = *name;
- path++;
- name++;
- }
- return path;
- }
- int main()
- {
- char path[100] = "/home/tarena/";
- char* filename = "字符串函数的使用.c";
- filenamecat(path, filename);
- printf("带路径的文件名为:%s\n", path);
- return 0;
- }
5 字符串的基本操作
5.1 问题
测试不同类型的指针的算术运算。
5.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:字符串的基本操作
代码如下所示:
- #include
- #include
- int main()
- {
- char str[100];
- strcpy(str, "tarena");
- printf("字符串为:%s\n", str);
- if (strcmp(str, "tarena"))
- printf("字符串str与tarena不同\n");
- else
- printf("字符串str与tarena相同\n");
- printf("sizeof(str) = %ld\n", sizeof(str));
- printf("strlen(str) = %lu\n", strlen(str));
- strcat(str, " C++方向");
- printf("字符串拼接后为:%s\n", str);
- printf("字符串拆分的前一部分为:%s\n", strtok(str, " "));
- printf("字符串拆分的后一部分为:%s\n", strtok(NULL, " "));
- char* p = strstr(str, "re");
- if (p)
- printf("子串re在字符串tarena中的位置为:%ld\n", p - str);
- else
- printf("子串re不在字符串tarena中\n");
- strcpy(str, "a 10 13.5");
- int i;
- double d;
- char c;
- sscanf(str, "%c%d%lf\n", &c, &i, &d);
- printf("%c %d %lf\n", c, i, d);
- memset(str, 0, sizeof(str));
- sprintf(str, "%c %d %lf\n", c, i, d);
- printf("%s\n", str);
- return 0;
- }
上述代码中,以下代码:
- char str[100];
- strcpy(str, "tarena");
- printf("字符串为:%s\n", str);
使用strcpy函数,将字符串"tarena"赋值到字符数组str中。
上述代码中,以下代码:
- if (strcmp(str, "tarena"))
- printf("字符串str与tarena不同\n");
- else
- printf("字符串str与tarena相同\n");
使用函数strcmp,逐个对比字符串"tarena"与字符数组str中的对应字符。如果所有对应字符均相同则返回0,否则返回非0值。
上述代码中,以下代码:
- printf("sizeof(str) = %ld\n", sizeof(str));
- printf("strlen(str) = %lu\n", strlen(str));
使用函数printf分别打印sizeof(str)和strlen(str)的值。从运行结果可以看出是不相同的。sizeof(str)输出的是字符数组str中所有元素所占的字节数。strlen(str)输出的是字符数组str中保存的字符串长度。
上述代码中,以下代码:
- strcat(str, " C++方向");
- printf("字符串拼接后为:%s\n", str);
使用函数strcat在字符串str的最后一个字符的后面连接上字符串" C++方向"。
上述代码中,以下代码:
- printf("字符串拆分的前一部分为:%s\n", strtok(str, " "));
- printf("字符串拆分的后一部分为:%s\n", strtok(NULL, " "));
使用函数strtok将刚拼接好的字符串str重新拆分成"tarena"和" C++方向"。
上述代码中,以下代码:
- char* p = strstr(str, "re");
- if (p)
- printf("子串re在字符串tarena中的位置为:%ld\n", p - str);
- else
- printf("子串re不在字符串tarena中\n");
首先,使用函数strstr在字符串str中查找子串"re"是否存在,如果存在则返回子串"re"的第一个字符r在字符串str的中的地址。然后,使用函数printf输出字符r在字符串中的位置。如果不存在,则输出子串不在字符串中。
上述代码中,以下代码:
- strcpy(str, "a 10 13.5");
- int i;
- double d;
- char c;
- sscanf(str, "%c%d%lf\n", &c, &i, &d);
- printf("%c %d %lf\n", c, i, d);
使用函数sscanf将字符串"a 10 13.5"中的字符a,整数10,双精度浮点数13.5转换到字符变量c,整型变量i,双精度浮点型变量d中。
上述代码中,以下代码:
- memset(str, 0, sizeof(str));
- sprintf(str, "%c %d %lf\n", c, i, d);
- printf("%s\n", str);
首先,将字符数组str中的所有元素清0。
然后,使用sprintf将字符变量c,整型变量i,双精度浮点型变量d中的值转换成字符串,存储到数组str中。
5.3 完整代码
本案例的完整代码如下所示:
- #include
- #include
- int main()
- {
- char str[100];
- strcpy(str, "tarena");
- printf("字符串为:%s\n", str);
- if (strcmp(str, "tarena"))
- printf("字符串str与tarena不同\n");
- else
- printf("字符串str与tarena相同\n");
- printf("sizeof(str) = %ld\n", sizeof(str));
- printf("strlen(str) = %lu\n", strlen(str));
- strcat(str, " C++方向");
- printf("字符串拼接后为:%s\n", str);
- printf("字符串拆分的前一部分为:%s\n", strtok(str, " "));
- printf("字符串拆分的后一部分为:%s\n", strtok(NULL, " "));
- char* p = strstr(str, "re");
- if (p)
- printf("子串re在字符串tarena中的位置为:%ld\n", p - str);
- else
- printf("子串re不在字符串tarena中\n");
- strcpy(str, "a 10 13.5");
- int i;
- double d;
- char c;
- sscanf(str, "%c%d%lf\n", &c, &i, &d);
- printf("%c %d %lf\n", c, i, d);
- memset(str, 0, sizeof(str));
- sprintf(str, "%c %d %lf\n", c, i, d);
- printf("%s\n", str);
- return 0;
- }
6 字符串数组和命令行参数的使用
6.1 问题
定义三国五虎上将名单的数组,然后输入人名,判断是否是五虎上将。
6.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:定义五虎上将名单
使用字符指针数组作为名单。
代码如下:
- #include
- int main(int argc, const char * argv[])
- {
- char *tiger[5] = {"GuanYu", "ZhangFei", "ZhaoYun", "MaChao", "HuangZhong"};
- return 0;
- }
步骤二:输入一个名字
定义一个字符数组,用于存储从控制台输入的名字。
代码如下:
- #include
- int main(int argc, const char * argv[])
- {
- char *tiger[5] = {"GuanYu", "ZhangFei", "ZhaoYun", "MaChao", "HuangZhong"};
- char name[20];
- printf("请输入一个名字:");
- scanf("%s", name);
- return 0;
- }
步骤三:遍历数组
遍历数组,逐个将数组元素与输入的名字对比,查找是否为五虎上将之一。
- #include
- #include
- int main(int argc, const char * argv[])
- {
- char *tiger[5] = {"GuanYu", "ZhangFei", "ZhaoYun", "MaChao", "HuangZhong"};
- char name[20];
- printf("请输入一个名字:");
- scanf("%s", name);
- int i;
- for (i = 0; i < 5; i++)
- if (strcmp(name, tiger[i]) == 0)
- {
- printf("%s是五虎上将之一。\n", name);
- break;
- }
- if (i == 5)
- printf("%s不是五虎上将之一。\n", name);
- return 0;
- }
注意:strcmp函数需要包含string.h这个头函数。
6.3 完整代码
本案例的完整代码如下所示:
- #include
- #include
- int main(int argc, const char * argv[])
- {
- char *tiger[5] = {"GuanYu", "ZhangFei", "ZhaoYun", "MaChao", "HuangZhong"};
- char name[20];
- printf("请输入一个名字:");
- scanf("%s", name);
- int i;
- for (i = 0; i < 5; i++)
- if (strcmp(name, tiger[i]) == 0)
- {
- printf("%s是五虎上将之一。\n", name);
- break;
- }
- if (i == 5)
- printf("%s不是五虎上将之一。\n", name);
- return 0;
- }
1 #include指令的使用
1.1 问题
测试#include的用法,包括gcc –I指定目录。
1.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:#include指令的使用
代码如下所示:
- #include
- #include "print.c"
- int main()
- {
- print();
- return 0;
- }
上述代码中,以下代码:
- #include "print.c"
使用#include 指令将文件print.c中的内容添加到本程序的文件中。
上述代码中,以下代码:
- int main()
- {
- print();
- return 0;
- }
在主程序中调用print.c中的函数print。
print.c代码如下所示:
- void print()
- {
- printf("调用在文件print.c中的print函数\n");
- }
上述代码中,以下代码:
- printf("调用在文件print.c中的print函数\n");
使用函数printf输出提示,该函数被调用了。
1.3 完整代码
本案例的完整代码如下所示:
- #include
- #include "print.c"
- int main()
- {
- print();
- return 0;
- }
print.c代码如下所示:
- void print()
- {
- printf("调用在文件print.c中的print函数\n");
- }
2 宏变量的使用
2.1 问题
测试宏变量的基本用法
2.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:宏变量的使用
代码如下所示:
- #include
- #define SIZE 10
- #define BEGIN int main() {
- #define END return 0; }
- #define LOOP for (int i = 0; i < SIZE; i++)
- BEGIN
- int array[SIZE];
- printf("请输入10个整数(空格分隔):");
- LOOP scanf("%d", &array[i]);
- LOOP printf("array[%d] = %d\n", i, array[i]);
- END
上述代码中,以下代码:
- #define SIZE 10
定义一个宏变量SIZE,用于定义数组元素的个数。
上述代码中,以下代码:
- #define BEGIN int main() {
定义一个宏变量BEGIN,用于代替后面的主函数定义。
上述代码中,以下代码:
- #define END return 0; }
定义一个宏变量END,用于代替后面的主函数返回。
上述代码中,以下代码:
- #define LOOP for (int i = 0; i < SIZE; i++)
定义一个宏变量LOOP,用于代替设置一个循环。
上述代码中,以下代码:
- BEGIN
在预编译阶段,会被替代为以下语句:
- int main() {
上述代码中,以下代码:
- LOOP scanf("%d", &array[i]);
在预编译阶段,会被替代为以下语句:
- for (int i = 0; i < SIZE; i++) scanf("%d", &array[i]);
上述代码中,以下代码:
- LOOP printf("array[%d] = %d\n", i, array[i]);
在预编译阶段,会被替代为以下语句:
- for (int i = 0; i < SIZE; i++) printf("array[%d] = %d\n", i, array[i]);
上述代码中,以下代码:
- END
在预编译阶段,会被替代为以下语句:
- return 0; }
2.3 完整代码
本案例的完整代码如下所示:
- #include
- #define SIZE 10
- #define BEGIN int main() {
- #define END return 0; }
- #define LOOP for (int i = 0; i < SIZE; i++)
- BEGIN
- int array[SIZE];
- printf("请输入10个整数(空格分隔):");
- LOOP scanf("%d", &array[i]);
- LOOP printf("array[%d] = %d\n", i, array[i]);
- END
3 宏函数的定义
3.1 问题
写一个宏函数,用它来验证一个日期是否合法。
3.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:宏函数的定义
- #define IS_DATE_VALID(year, month, day) \
- if ((year) > 2000 && (year) < 2020 && (month) > 0 && (month) < 13 && (day) > 0 && (day) < 32)\
- printf("日期合法\n");\
- else\
- printf("日期不合法\n");
- int main()
- {
- IS_DATE_VALID(2015,3,15);
- return 0;
- }
上述代码中,以下代码:
- #define IS_DATE_VALID(year, month, day) \
- if ((year) > 2000 && (year) < 2020 && (month) > 0 && (month) < 13 && (day) > 0 && (day) < 32)\
- printf("日期合法\n");\
- else\
- printf("日期不合法\n");
定义了一个宏函数IS_DATE_VALID,用于测试一个日期是否合法。上述代码中,\ 代表换行,当宏函数中的字符串比较长时,可以用它来作为换行符,不能用回车,因为回车代表宏函数定义结束。
上述代码中,以下代码:
- IS_DATE_VALID(2015,3,15);
在预编译阶段,会被替代为以下语句:
- if ((year) > 2000 && (year) < 2020 && (month) > 0 && (month) < 13 && (day) > 0 && (day) < 32)\
- printf("日期合法\n");\
- else\
- printf("日期不合法\n");
3.3 完整代码
本案例的完整代码如下所示:
- #define IS_DATE_VALID(year, month, day) \
- if ((year) > 2000 && (year) < 2020 && (month) > 0 && (month) < 13 && (day) > 0 && (day) < 32)\
- printf("日期合法\n");\
- else\
- printf("日期不合法\n");
- int main()
- {
- IS_DATE_VALID(2015,3,15);
- return 0;
- }
4 条件编译的使用
4.1 问题
写一个头文件,使用条件编译实现避免重复include。
4.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:条件编译的使用
main.c代码如下所示:
- #include
- #include "print.h"
- int main()
- {
- print();
- return 0;
- }
上述代码中,以下代码:
- #include "print.h"
使用#include 指令将