项目开发中字符串模型建立
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(){//字符数组初始化//指定长度 如果定义的长度剩余部分补充0char buf1[100] = {'a', 'b', 'c'};//不指定长度char buf2[] = {'a', 'b', 'c'};char buf3[] = {'a', 'b', 'c','\0'};//通过字符串初始化字符数组 并且追加\0char buf4[] = "abcdefg";printf("%s\n", buf4 );system("pause");}//sizeofvoid main12(){//字符数组初始化//指定长度 如果定义的长度剩余部分补充0char buf1[100] = {'a', 'b', 'c'};//不指定长度char buf2[] = {'a', 'b', 'c'};char buf3[] = {'a', 'b', 'c','\0'};//通过字符串初始化字符数组 并且追加\0char buf4[] = "abcd";printf("%s\n", buf4 );//注意sizeof是对数组类型进行大小测量 包括了\0printf("sizeof(buf4): %d\n ", sizeof(buf4)); //strlen是求字符串的长度不包括\0printf("strlen(buf4): %d \n", strlen(buf4));system("pause");}//操作数组的方法//下标法和指针法void main(){int i = 0;char *p = NULL;//通过字符串初始化字符数组 并且追加\0char buf4[] = "abcd";for (i=0; i<strlen(buf4); 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<strlen(buf4); i++){printf("%c", *(p+i)); //*p }system("pause");}2.自定义字符串拷贝基本模型#include "stdlib.h"#include "stdio.h"#include "string.h"//自定义:字符串copy函数,完成字符串from ,到to的copyvoid 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<stdio.h>#include<string.h>#include<stdlib.h>//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++;//找到了就,计数加1p = 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<p2,将其所指向的字符交换{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,/*abcdefacccd 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<num; 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<iNum; 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<iNum; i++){for (j=i+1; j<iNum; 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<iNum; 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<iNum; 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<iNum; i++){printf("%s \n", ArrayStr[i]);}return 0;}int printfArr2_23(char myArray[10][100], int iNum){int i = 0;for (i=0; i<iNum; 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<iNum; i++){for (j=i+1; j<iNum; 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); //第二种打印不适合 errsortArrayStr03(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; //给数组指针赋值 需要。。。&a1MyArr5 *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 <stdio.h>#include <string.h>//演示:指针数组的用法//演示:找错误 注意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<size; i++){if( strcmp(key, table[i]) == 0 ){*pos = i;//break;return rv; }}//没有找到返回-1if (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<argc; 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(){//声明指针变量的时候nullchar *p = NULL;//不初始化会产生野指针p = (char *)malloc(100);//分配堆内存//此处执行业务myfree(p);//业务执行完毕释放内存/*if (p != NULL){free(p);p = NULL;}若重复释放内存也会产生野指针,导致程序崩溃 */system("pause");}
1 字符串地址的测试
1.1 问题
测试字符串常量和字符数组 类型的变量地址是否相同。
1.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:字符串地址的测试
代码如下所示:
- #include <stdio.h>
- #include <string.h>
- 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 <stdio.h>
- #include <string.h>
- 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 <stdio.h>
- int main()
- {
- char str[5] = {};
- scanf("%4s", str);
- printf("%s\n", str);
-
- return 0;
- }
上述代码中,以下代码:
定义了一个字符数组str,该数组有5个元素。
上述代码中,以下代码:
使用scanf函数输入一个字符串。其中,%4s是限定输入的字符串中字符的个数不能大于4,否则将只输入前4个字符。指定值为4是因为字符数组str的长度为5,多出来的一个需要存储\0。
上述代码中,以下代码:
使用函数printf输出字符串。字符数组所对应的格式控制符是%s。
2.3 完整代码
本案例的完整代码如下所示:
- #include <stdio.h>
- int main()
- {
- char str[5] = {};
- scanf("%4s", str);
- printf("%s\n", str);
-
- return 0;
- }
3 字符串函数的使用
3.1 问题
使用指针实现字符串的函数strlen()、strcat()的功能,可以自定义两个函数。
3.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:字符串函数的使用
代码如下所示:
- #include <stdio.h>
- 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的功能。该函数的参数为求长度的字符串。在该函数中,以下语句:
首先定义一个整型变量count,用于存储字符串中字符的个数。在该函数中,以下语句:
- while (*str)
- {
- count++;
- str++;
- }
设置一个循环,逐个计算字符串中字符的个数,当*str不为\0时,代表该字符串没有结束。在该函数中,以下语句:
返回字符串的长度。
上述代码中,以下代码:
- char* mystrcat(char *s, char *d)
- {
- char* old = s;
- while(*s)
- s++;
- while(*d)
- {
- *s = *d;
- s++;
- d++;
- }
-
- return old;
- }
定义了一个函数mystrcat,用于模拟库函数strcat的功能。该函数的两个参数为将字符串d连接到字符串s的后面。在该函数中,以下语句:
首先保存被连接字符串的首地址,用于函数结束返回时作返回值用。在该函数中,以下语句:
设置一个循环找到被连接字符串的结束符\0,以便将另一个字符串连接到这个位置。在该函数中,以下语句:
- while(*d)
- {
- *s = *d;
- s++;
- d++;
- }
设置一个循环将字符串d的每一个字符拷贝到字符串s的结束字符\0开始的空间中,实现连接功能。在该函数中,以下语句:
返回字符串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 <stdio.h>
- 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 <stdio.h>
- 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的后面。在该函数中,以下语句:
首先保存路径字符串的首地址,用于函数结束返回时作返回值用。在该函数中,以下语句:
设置一个循环找到路径字符串的结束符\0,以便将文件名字符串连接到这个位置。在该函数中,以下语句:
- if (*(path - 1) != '/')
- {
- *path = '/';
- path++;
- }
判断路径字符串的最后一个字符是否是/,如果不是则首先在路径字符串的最后添加字符/。在该函数中,以下语句:
- while(*name)
- {
- *path = *name;
- path++;
- name++;
- }
设置一个循环将文件名字符串name的每一个字符拷贝到路径字符串path的结束字符/后面的空间中,实现连接功能。在该函数中,以下语句:
返回路径字符串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 <stdio.h>
- 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 <stdio.h>
- #include <string.h>
- 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 <stdio.h>
- #include <string.h>
- 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 <stdio.h>
- int main(int argc, const char * argv[])
- {
- char *tiger[5] = {"GuanYu", "ZhangFei", "ZhaoYun", "MaChao", "HuangZhong"};
-
- return 0;
- }
步骤二:输入一个名字
定义一个字符数组,用于存储从控制台输入的名字。
代码如下:
- #include <stdio.h>
- 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 <stdio.h>
- #include <string.h>
- 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 <stdio.h>
- #include <string.h>
- 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 <stdio.h>
- #include "print.c"
- int main()
- {
- print();
- return 0;
- }
上述代码中,以下代码:
使用#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 <stdio.h>
- #include "print.c"
- int main()
- {
- print();
- return 0;
- }
print.c代码如下所示:
- void print()
- {
- printf("调用在文件print.c中的print函数\n");
- }
2 宏变量的使用
2.1 问题
测试宏变量的基本用法
2.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:宏变量的使用
代码如下所示:
- #include <stdio.h>
- #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
上述代码中,以下代码:
定义一个宏变量SIZE,用于定义数组元素的个数。
上述代码中,以下代码:
- #define BEGIN int main() {
定义一个宏变量BEGIN,用于代替后面的主函数定义。
上述代码中,以下代码:
定义一个宏变量END,用于代替后面的主函数返回。
上述代码中,以下代码:
- #define LOOP for (int i = 0; i < SIZE; i++)
定义一个宏变量LOOP,用于代替设置一个循环。
上述代码中,以下代码:
在预编译阶段,会被替代为以下语句:
上述代码中,以下代码:
- 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]);
上述代码中,以下代码:
在预编译阶段,会被替代为以下语句:
2.3 完整代码
本案例的完整代码如下所示:
- #include <stdio.h>
- #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 <stdio.h>
- #include "print.h"
- int main()
- {
- print();
- return 0;
- }
上述代码中,以下代码:
使用#include 指令将文件print.h中的内容添加到本程序的文件中。
print.h文件,代码如下所示:
- #ifndef print_h
- #define print_h
- void print();
- #endif
上述代码中,以下代码:
使用条件编译指令判断宏名print_h是否已经定义,如果没有定义继续执行下面的语句,否则直接跳到#endif后面的语句执行。
上述代码中,以下代码:
如果没有定义宏名print_h,则执行此语句定义该宏名,这样下一次再使用#ifndef判断宏名print_h是否已经定义时,由于已经定义将跳过#endif之间的语句,防止重复include。
print.c文件,代码如下所示:
- #include <stdio.h>
- #include "print.h"
- void print()
- {
- printf("避免重复include例题\n");
- }
上述代码中,以下代码:
在main.c函数中已经有此语句,如果没有条件编译语句会多次包含print.h文件。
4.3 完整代码
本案例的完整代码如下所示:
main.c代码如下所示:
- #include <stdio.h>
- #include "print.h"
- int main()
- {
- print();
- return 0;
- }
print.h文件,代码如下所示:
- #ifndef print_h
- #define print_h
- void print();
- #endif
print.c文件,代码如下所示:
- #include <stdio.h>
- #include "print.h"
- void print()
- {
- printf("避免重复include例题\n");
- }
5 头文件的使用
5.1 问题
写一组头文件,然后按照条件选择一个进行编译。
要求:实现避免重复导入并且测试static的作用。
5.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:short文件
short.h文件,代码如下所示:
- #ifndef short_h
- #define short_h
- short add(short a, short b);
- short sub(short a, short b);
- #endif
上述代码中,以下代码:
- #ifndef short_h
- #define short_h
- #endif
为防止重复include而预设的条件编译指令。
上述代码中,以下代码:
- short add(short a, short b);
- short sub(short a, short b);
声明短整型的加法add、减法sub运算函数。
short.c文件,代码如下所示:
- #include "short.h"
- short add(short a, short b)
- {
- return a + b;
- }
- short sub(short a, short b)
- {
- return a - b;
- }
上述代码中,以下代码:
- short add(short a, short b)
- {
- return a + b;
- }
短整型的加法add函数的定义。
上述代码中,以下代码:
- short sub(short a, short b)
- {
- return a - b;
- }
短整型的减法sub函数的定义。
步骤二:standard文件
standard.h文件,代码如下所示:
- #ifndef int_h
- #define int_h
- int add(int a, int b);
- int sub(int a, int b);
- #endif
上述代码中,以下代码:
- int add(int a, int b);
- int sub(int a, int b);
声明整型的加法add、减法sub运算函数。
standard.c文件,代码如下所示:
- #include "standard.h"
- int add(int a, int b)
- {
- return a + b;
- }
- int sub(int a, int b)
- {
- return a - b;
- }
整型的加法add、减法sub运算函数的定义。
步骤三:long文件
long.h文件,代码如下所示:
- #ifndef long_h
- #define long_h
- long add(long a, long b);
- long sub(long a, long b);
- #endif
上述代码中,以下代码:
- long add(long a, long b);
- long sub(long a, long b);
声明长整型的加法add、减法sub运算函数。
long.c文件,代码如下所示:
- #include "long.h"
- long add(long a, long b)
- {
- return a + b;
- }
- long sub(long a, long b)
- {
- return a - b;
- }
长整型的加法add、减法sub运算函数的定义。
步骤四:static文件
static.h文件,代码如下所示:
- #ifndef int_h
- #define int_h
- static void print();
- void call();
- #endif
上述代码中,以下代码:
声明了一个静态函数。该函数只能在本文件内部使用,在其他的.c文件中无法使用。
上述代码中,以下代码:
定义了一个普通函数。
static.c文件,代码如下所示:
- #include <stdio.h>
- #include "static.h"
- static int ex = 10;
- void print()
- {
- printf("这是静态函数,只能在本文件中使用\n");
- }
- void call()
- {
- print();
- printf("静态变量:%d\n", ex);
- }
上述代码中,以下代码:
定义了一个静态变量ex,该变量只能在本文件内部使用,在其他的.c文件中无法使用。
上述代码中,以下代码:
- void print()
- {
- printf("这是静态函数,只能在本文件中使用\n");
- }
静态函数print的定义。
上述代码中,以下代码:
- void call()
- {
- print();
- printf("静态变量:%d\n", ex);
- }
普通函数call的定义。由于静态函数print和静态变量ex,都与函数call在同一个文件中,所以以下语句:
- print();
- printf("静态变量:%d\n", ex);
对静态函数print的调用和静态变量ex的使用是合法的。
步骤五:main文件
main.h文件,代码如下所示:
- #ifndef main_h
- #define main_h
- #if defined(SHORT)
- #define FILE "short.h"
- #elif defined(STANDARD)
- #define FILE "standard.h"
- #elif defined(LONG)
- #define FILE "long.h"
- #endif
- #include FILE
- #endif
上述代码中,以下代码:
- #if defined(SHORT)
- #define FILE "short.h"
使用条件编译语句#if判断宏名SHORT是否定义,如果定义则定义宏名FILE为"short.h"。
上述代码中,以下代码:
- #elif defined(STANDARD)
- #define FILE "standard.h"
使用条件编译语句#elif判断宏名STANDARD是否定义,如果定义则定义宏名FILE为"standard.h"。
上述代码中,以下代码:
- #elif defined(LONG)
- #define FILE "long.h"
使用条件编译语句#elif判断宏名LONG是否定义,如果定义则定义宏名FILE为"long.h"。
上述代码中,以下代码:
包含头文件FILE。
main.c文件,代码如下所示:
- #include <stdio.h>
- #define STANDARD
- #include "main.h"
- #include "static.h"
- extern int ex;
- int main()
- {
- printf("5 + 3 = %d\n", add(5, 3));
- printf("5 - 3 = %d\n", sub(5, 3));
-
- //print();
- //printf("静态变量:%d\n", ex);
- call();
-
- return 0;
- }
上述代码中,以下代码:
- #define STANDARD
- #include "main.h"
定义宏名STANDARD,这样在main.h中将执行#include "standard.h"。
上述代码中,以下代码:
声明一个外部变量ex。变量ex定义在static.c中,但由于变量ex被定义成静态变量,所以此语句没有意义。
上述代码中,以下代码:
- printf("5 + 3 = %d\n", add(5, 3));
- printf("5 - 3 = %d\n", sub(5, 3));
调用的函数add和函数sub是被定义在standard.c中的函数add和函数sub。
上述代码中,以下代码:
调用函数print是非法的。因为函数print是静态函数,只能在static.c文件中被调用。
上述代码中,以下代码:
- //printf("静态变量:%d\n", ex);
使用变量ex是非法的。因为变量ex是静态变量,只能在static.c文件中被使用。
上述代码中,以下代码:
调用call函数是合法的,因为函数call不是静态函数。
5.3 完整代码
本案例的完整代码如下所示:
short.h文件,代码如下所示:
- #ifndef short_h
- #define short_h
- short add(short a, short b);
- short sub(short a, short b);
- #endif
short.c文件,代码如下所示:
- #include "short.h"
- short add(short a, short b)
- {
- return a + b;
- }
- short sub(short a, short b)
- {
- return a - b;
- }
standard.h文件,代码如下所示:
- #ifndef int_h
- #define int_h
- int add(int a, int b);
- int sub(int a, int b);
- #endif
standard.c文件,代码如下所示:
- #include "standard.h"
- int add(int a, int b)
- {
- return a + b;
- }
- int sub(int a, int b)
- {
- return a - b;
- }
long.h文件,代码如下所示:
- #ifndef long_h
- #define long_h
- long add(long a, long b);
- long sub(long a, long b);
- #endif
long.c文件,代码如下所示:
- #include "long.h"
- long add(long a, long b)
- {
- return a + b;
- }
- long sub(long a, long b)
- {
- return a - b;
- }
static.h文件,代码如下所示:
- #ifndef int_h
- #define int_h
- static void print();
- void call();
- #endif
static.c文件,代码如下所示:
- #include <stdio.h>
- #include "static.h"
- static int ex = 10;
- void print()
- {
- printf("这是静态函数,只能在本文件中使用\n");
- }
- void call()
- {
- print();
- printf("静态变量:%d\n", ex);
- }
main.h文件,代码如下所示:
- #ifndef main_h
- #define main_h
- #if defined(SHORT)
- #define FILE "short.h"
- #elif defined(STANDARD)
- #define FILE "standard.h"
- #elif defined(LONG)
- #define FILE "long.h"
- #endif
- #include FILE
- #endif
main.c文件,代码如下所示:
- #include <stdio.h>
- #define STANDARD
- #include "main.h"
- #include "static.h"
- extern int ex;
- int main()
- {
- printf("5 + 3 = %d\n", add(5, 3));
- printf("5 - 3 = %d\n", sub(5, 3));
-
- //print();
- //printf("静态变量:%d\n", ex);
- call();
-
- return 0;
- }
6 makefile的使用
6.1 问题
分别使用静态初始化和动态初始化的方式对数组进行赋值,并循环打印数组元素。
6.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:input文件
input.h,代码如下所示:
- #ifndef input_h
- #define input_h
- void input();
- #endif
上述代码中,以下代码:
声明了一个函数input。
input.c,代码如下所示:
- #include <stdio.h>
- extern int num;
- void input()
- {
- printf("请输入一个整数:");
- scanf("%d", &num);
- }
上述代码中,以下代码:
声明了一个外部变量num。该变量定义在main.c中。
上述代码中,以下代码:
- void input()
- {
- printf("请输入一个整数:");
- scanf("%d", &num);
- }
定义了函数input。
步骤二:output文件
output.h,代码如下所示:
- #ifndef output_h
- #define output_h
- void output();
- #endif
上述代码中,以下代码:
声明了一个函数output。
output.c,代码如下所示:
- #include <stdio.h>
- extern int num;
- void output()
- {
- printf("%d\n", num);
- }
上述代码中,以下代码:
声明了一个外部变量num。该变量定义在main.c中。
上述代码中,以下代码:
- void output()
- {
- printf("%d\n", num);
- }
定义了函数output。
步骤三:main文件
代码如下所示:
- #include <stdio.h>
- #include "input.h"
- #include "output.h"
- int num;
- int main()
- {
- input();
- output();
-
- return 0;
- }
上述代码中,以下代码:
定义了一个全局变量num。
上述代码中,以下代码:
调用函数input,对变量num进行输入。
调用函数output,对变量num进行输出。
步骤四:makefile文件
代码如下所示:
- main:main.o input.o output.o
- gcc main.c input.c output.c
- main.o:main.c
- gcc main.c -c
- input.o:input.c
- gcc input.c -c
- output.o:output.c
- gcc output.c -c
可以使用makefile文件来一次性执行多条命令(批处理命令)。makefile带来的好处就是“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
6.3 完整代码
本案例的完整代码如下所示:
input.h,代码如下所示:
- #ifndef input_h
- #define input_h
- void input();
- #endif
input.c,代码如下所示:
- #include <stdio.h>
- extern int num;
- void input()
- {
- printf("请输入一个整数:");
- scanf("%d", &num);
- }
output.h,代码如下所示:
- #ifndef output_h
- #define output_h
- void output();
- #endif
output.c,代码如下所示:
- #include <stdio.h>
- extern int num;
- void output()
- {
- printf("%d\n", num);
- }
main文件,代码如下所示:
- #include <stdio.h>
- #include "input.h"
- #include "output.h"
- int num;
- int main()
- {
- input();
- output();
-
- return 0;
- }
makefile文件,代码如下所示:
- main:main.o input.o output.o
- gcc main.c input.c output.c
- main.o:main.c
- gcc main.c -c
- input.o:input.c
- gcc input.c -c
- output.o:output.c
- gcc output.c -c
1 结构的声明和初始化
1.1 问题
定义测试结构体,并进行声明变量和初始化。
1.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:结构的声明和初始化
代码如下所示:
- #include <stdio.h>
- struct student
- {
- int id;
- char name[10];
- }stu1;
- int main()
- {
- stu1.id = 110;
- strcpy(stu1.name, "zhangsan");
- printf("学号:%d, 姓名:%s", stu1.id, stu1.name);
-
- struct student stu2 = {112, "lisi"};
- printf("学号:%d, 姓名:%s", stu2.id, stu2.name);
- return 0;
- }
上述代码中,以下代码:
- struct student
- {
- int id;
- char name[10];
- }stu1;
定义学生结构体student。该结构体有两个成员,第一个成员是学号id,第二个成员是姓名name。在定义结构体student的同时定义了结构体变量stu1。
上述代码中,以下代码:
- stu1.id = 110;
- strcpy(stu1.name, "zhangsan");
- printf("学号:%d, 姓名:%s", stu1.id, stu1.name);
首先,将结构体变量stu1的学号成员赋值为110。
然后,将结构体变量stu1的姓名成员赋值为"zhangsan"。
最后,输出结构体变量stu1。
上述代码中,以下代码:
- struct student stu2 = {112, "lisi"};
- printf("学号:%d, 姓名:%s", stu2.id, stu2.name);
首先,定义了另一个结构体变量stu2,并对其进行初始化,将学号成员初始化为112,姓名成员初始化为"lisi"。
然后,输出结构体变量stu2。
1.3 完整代码
本案例的完整代码如下所示:
- #include <stdio.h>
- struct student
- {
- int id;
- char name[10];
- }stu1;
- int main()
- {
- stu1.id = 110;
- strcpy(stu1.name, "zhangsan");
- printf("学号:%d, 姓名:%s", stu1.id, stu1.name);
-
- struct student stu2 = {112, "lisi"};
- printf("学号:%d, 姓名:%s", stu2.id, stu2.name);
- return 0;
- }
2 结构的声明和初始化(续1)
2.1 问题
定义结构点point,计算每个点离(0,0)的距离。
再定义结构rect(矩形),由两个点组成,计算矩形的面积。
2.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:结构的声明和初始化(续1)
代码如下所示:
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- struct point
- {
- int x;
- int y;
- };
- struct rect
- {
- struct point left_top;
- struct point right_bottom;
- };
- int main()
- {
- struct point dot = {10, 20};
- int dis = sqrt(dot.x * dot.x + dot.y * dot.y);
- printf("点(%d,%d)到原点(0,0)的距离是:%d\n", dot.x, dot.y, dis);
-
- struct point a = {10, 10};
- struct point b = {50, 30};
- struct rect r = {a, b};
- int area = abs(r.left_top.x - r.right_bottom.x) * abs(r.left_top.y - r.right_bottom.y);
- printf("矩形的面积是:%d\n", area);
-
- return 0;
- }
上述代码中,以下代码:
- struct point
- {
- int x;
- int y;
- };
定义一个结构体point,该结构体有两个成员,x轴坐标x,y轴坐标y。
上述代码中,以下代码:
- struct rect
- {
- struct point left_top;
- struct point right_bottom;
- };
定义一个结构体rect,该结构体有两个成员,左上角点坐标left_top,右下角点坐标right_bottom。
上述代码中,以下代码:
- struct point dot = {10, 20};
定义一个结构体point的变量dot,并初始化为(10,20)。
上述代码中,以下代码:
- int dis = sqrt(dot.x * dot.x + dot.y * dot.y);
计算点dot到原点的距离。
上述代码中,以下代码:
- struct point a = {10, 10};
- struct point b = {50, 30};
- struct rect r = {a, b};
首先,定义两个结构体point的变量a和b,并初始化为(10,10)和(50,30)。
然后,定义结构体rect的变量r,并用上述两个结构体point的变量a和b初始化。
上述代码中,以下代码:
- int area = abs(r.left_top.x - r.right_bottom.x) * abs(r.left_top.y - r.right_bottom.y);
计算矩形r面积。
2.3 完整代码
本案例的完整代码如下所示:
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- struct point
- {
- int x;
- int y;
- };
- struct rect
- {
- struct point left_top;
- struct point right_bottom;
- };
- int main()
- {
- struct point dot = {10, 20};
- int dis = sqrt(dot.x * dot.x + dot.y * dot.y);
- printf("点(%d,%d)到原点(0,0)的距离是:%d\n", dot.x, dot.y, dis);
-
- struct point a = {10, 10};
- struct point b = {50, 30};
- struct rect r = {a, b};
- int area = abs(r.left_top.x - r.right_bottom.x) * abs(r.left_top.y - r.right_bottom.y);
- printf("矩形的面积是:%d\n", area);
-
- return 0;
- }
3 结构的声明和初始化(续2)
3.1 问题
定义一个包含月份的名字和这个月天数的结构,用一个结构的数组保存一年中的所有月份和天数,在每个结构中保存一个月的名字和天数。
月份英文:January、February、March、April、May、June、July、August、September、October、November、December。
3.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:结构的声明和初始化(续2)
代码如下所示:
- #include <stdio.h>
- struct month
- {
- char name[10];
- int days;
- };
- int main()
- {
- struct month m[12] = {
- {"January", 31},
- {"February", 28},
- {"March", 31},
- {"April", 30},
- {"May", 31},
- {"June", 30},
- {"July", 31},
- {"August", 31},
- {"September", 30},
- {"October", 31},
- {"November", 30},
- {"December", 31}};
-
- for (int i = 0; i < 12; i++)
- printf("%d月的名字是:%s,天数是:%d\n", i + 1, m[i].name, m[i].days);
- return 0;
- }
上述代码中,以下代码:
- struct month
- {
- char name[10];
- int days;
- };
定义一个结构体month,该结构体有两个成员,该月的英文名字和该月的天数。
上述代码中,以下代码:
- struct month m[12] = {
- {"January", 31},
- {"February", 28},
- {"March", 31},
- {"April", 30},
- {"May", 31},
- {"June", 30},
- {"July", 31},
- {"August", 31},
- {"September", 30},
- {"October", 31},
- {"November", 30},
- {"December", 31}};
定义了一个结构体month的数组m,该数组有12个元素,每个元素代表一年中的一个月。定义数组m之后,对其进行了初始化。
注意:初始化时,每个数组元素的值用{}括起来。
3.3 完整代码
本案例的完整代码如下所示:
- #include <stdio.h>
- struct month
- {
- char name[10];
- int days;
- };
- int main()
- {
- struct month m[12] = {
- {"January", 31},
- {"February", 28},
- {"March", 31},
- {"April", 30},
- {"May", 31},
- {"June", 30},
- {"July", 31},
- {"August", 31},
- {"September", 30},
- {"October", 31},
- {"November", 30},
- {"December", 31}};
-
- for (int i = 0; i < 12; i++)
- printf("%d月的名字是:%s,天数是:%d\n", i + 1, m[i].name, m[i].days);
- return 0;
- }
4 结构做参数
4.1 问题
对比结构做参数的两种方式,使用->操作成员。
4.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:结构做参数
代码如下所示:
- #include <stdio.h>
- #include <string.h>
- struct student
- {
- int id;
- char name[10];
- }stu;
- void print1(struct student stu)
- {
- printf("学号:%d, 姓名:%s\n", stu.id, stu.name);
- }
- void print2(struct student *p)
- {
- printf("学号:%d, 姓名:%s\n", p->id, p->name);
- }
- int main()
- {
- stu.id = 110;
- strcpy(stu.name, "zhangsan");
- print1(stu);
- print2(&stu);
-
- return 0;
- }
上述代码中,以下代码:
- struct student
- {
- int id;
- char name[10];
- }stu;
定义学生结构体student。该结构体有两个成员,第一个成员是学号id,第二个成员是姓名name。在定义结构体student的同时定义了结构体变量stu。
上述代码中,以下代码:
- void print1(struct student stu)
- {
- printf("学号:%d, 姓名:%s\n", stu.id, stu.name);
- }
定义了一个函数print1,用于打印结构体student的变量的值。该函数有一个参数,是结构体student的变量stu。这是值传递的方法。结构体student的变量stu将是实参的副本。
上述代码中,以下代码:
- void print2(struct student *p)
- {
- printf("学号:%d, 姓名:%s\n", p->id, p->name);
- }
定义了一个函数print2,用于打印结构体student的变量的值。该函数有一个参数,是结构体student的指针变量p。这是地址传递的方法。结构体student的指针变量p将指向实参。该函数中,p->id是用指针p指向的结构体student的变量的id成员。
上述代码中,以下代码:
- stu.id = 110;
- strcpy(stu.name, "zhangsan");
首先,将结构体student的变量stu的id成员赋值为110。
然后,将结构体student的变量stu的name成员赋值为"zhangsan"。
上述代码中,以下代码:
调用值传递方法的print1函数,实参为结构体student的变量stu。
上述代码中,以下代码:
调用地址传递方法的print2函数,实参为结构体student的变量stu的地址。
4.3 完整代码
本案例的完整代码如下所示:
- #include <stdio.h>
- #include <string.h>
- struct student
- {
- int id;
- char name[10];
- }stu;
- void print1(struct student stu)
- {
- printf("学号:%d, 姓名:%s\n", stu.id, stu.name);
- }
- void print2(struct student *p)
- {
- printf("学号:%d, 姓名:%s\n", p->id, p->name);
- }
- int main()
- {
- stu.id = 110;
- strcpy(stu.name, "zhangsan");
- print1(stu);
- print2(&stu);
-
- return 0;
- }
5 结构做返回值
5.1 问题
测试直接返回结构的问题,并实现用结构指针参数带出数据。
5.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:结构做返回值
代码如下所示:
- #include <stdio.h>
- struct student
- {
- int id;
- char name[10];
- };
- struct student input1()
- {
- struct student stu;
- printf("输入学号:");
- scanf("%d", &stu.id);
- printf("输入姓名:");
- scanf("%s", stu.name);
-
- return stu;
- }
- void input2(struct student *p)
- {
- printf("输入学号:");
- scanf("%d", &p->id);
- printf("输入姓名:");
- scanf("%s", p->name);
- }
- int main()
- {
- struct student stu;
- stu = input1();
- printf("学号:%d, 姓名:%s\n", stu.id, stu.name);
- input2(&stu);
- printf("学号:%d, 姓名:%s\n", stu.id, stu.name);
-
- return 0;
- }
上述代码中,以下代码:
- struct student
- {
- int id;
- char name[10];
- };
定义学生结构体student。该结构体有两个成员,第一个成员是学号id,第二个成员是姓名name。
上述代码中,以下代码:
- struct student input1()
- {
- struct student stu;
- printf("输入学号:");
- scanf("%d", &stu.id);
- printf("输入姓名:");
- scanf("%s", stu.name);
-
- return stu;
- }
定义一个函数input1,用于输入。该函数中,以下语句:
定义了一个局部结构体student的变量stu。该函数中,以下语句:
- printf("输入学号:");
- scanf("%d", &stu.id);
- printf("输入姓名:");
- scanf("%s", stu.name);
输入学号和姓名。该函数中,以下语句:
返回结构体student的变量stu。
上述代码中,以下代码:
- void input2(struct student *p)
- {
- printf("输入学号:");
- scanf("%d", &p->id);
- printf("输入姓名:");
- scanf("%s", p->name);
- }
定义一个函数input2,用于输入,该函数有一个参数,是指向结构体student的指针变量p。该函数中,以下语句:
- printf("输入学号:");
- scanf("%d", &p->id);
- printf("输入姓名:");
- scanf("%s", p->name);
将学号和姓名输入到结构体student的指针变量p指向的实参。
上述代码中,以下代码:
- int main()
- {
- struct student stu;
- stu = input1();
- printf("学号:%d, 姓名:%s\n", stu.id, stu.name);
在主函数中,定义结构体student的变量stu,用于接收函数input1的返回值。
上述代码中,以下代码:
- input2(&stu);
- printf("学号:%d, 姓名:%s\n", stu.id, stu.name);
在主函数中,将结构体student的变量stu的地址作为实参传入input2,以输入其值。
5.3 完整代码
本案例的完整代码如下所示:
- #include <stdio.h>
- struct student
- {
- int id;
- char name[10];
- };
- struct student input1()
- {
- struct student stu;
- printf("输入学号:");
- scanf("%d", &stu.id);
- printf("输入姓名:");
- scanf("%s", stu.name);
-
- return stu;
- }
- void input2(struct student *p)
- {
- printf("输入学号:");
- scanf("%d", &p->id);
- printf("输入姓名:");
- scanf("%s", p->name);
- }
- int main()
- {
- struct student stu;
- stu = input1();
- printf("学号:%d, 姓名:%s\n", stu.id, stu.name);
- input2(&stu);
- printf("学号:%d, 姓名:%s\n", stu.id, stu.name);
-
- return 0;
- }
6 结构的对齐和补齐
6.1 问题
对齐是指由于内存分配会将结构中的变量分配到内存的边界上,以方便访问。每个成员放的位置是从本身长度的倍数位开始放。
补齐是指整个结构变量的长度要保持内部最长成员(超过4以4计)的倍数。如果不够,则补齐。
6.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:结构的对齐和补齐
代码如下所示:
- #include <stdio.h>
- struct size
- {
- char c;
- int i;
- };
- int main()
- {
- printf("sizeof(size) = %ld\n", sizeof(struct size));
- return 0;
- }
上述代码中,以下代码:
- struct size
- {
- char c;
- int i;
- };
定义一个结构体size,该结构体有两个成员,字符型变量c和整型变量i。
上述代码中,以下代码:
- 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 完整代码
本案例的完整代码如下所示:
- #include <stdio.h>
- struct size
- {
- char c;
- int i;
- };
- int main()
- {
- printf("sizeof(size) = %ld\n", sizeof(struct size));
- return 0;
- }
7 联合的基本用法
7.1 问题
联合就是一块内存对应不同的类型,并起了不同的名字,在使用时按照名字切换类型,而不是用类型转换。
7.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:联合的基本用法
代码如下所示:
- #include <stdio.h>
- union data
- {
- int a;
- int b;
- int c;
- };
- int main()
- {
- union data d;
- d.a = 10;
- printf("%d %d %d\n", d.a, d.b, d.c);
-
- d.b = 20;
- printf("%d %d %d\n", d.a, d.b, d.c);
-
- d.c = 30;
- printf("%d %d %d\n", d.a, d.b, d.c);
- return 0;
- }
上述代码中,以下代码:
- union data
- {
- int a;
- int b;
- int c;
- };
定义了一个联合data,该联合中有三个成员,这三个成员共用4个字节。
上述代码中,以下代码:
- union data d;
- d.a = 10;
- printf("%d %d %d\n", d.a, d.b, d.c);
首先,定义一个联合data的变量d。
然后,将联合data的变量d的第一个成员a赋值为10。
最后,使用printf输出联合data的三个成员的值。从输出结果可以看出,值都相同。而且,后两个成员未赋值。原因是联合data的三个成员共用4个字节。
上述代码中,以下代码:
- d.b = 20;
- printf("%d %d %d\n", d.a, d.b, d.c);
将联合data的变量d的第二个成员b赋值为20。从输出结果可以看出,联合data的三个成员的值都相同。原因是联合data的三个成员共用4个字节。
上述代码中,以下代码:
- d.c = 30;
- printf("%d %d %d\n", d.a, d.b, d.c);
将联合data的变量d的第三个成员c赋值为30。从输出结果可以看出,联合data的三个成员的值还是都相同。原因还是联合data的三个成员共用4个字节。
7.3 完整代码
本案例的完整代码如下所示:
- #include <stdio.h>
- union data
- {
- int a;
- int b;
- int c;
- };
- int main()
- {
- union data d;
- d.a = 10;
- printf("%d %d %d\n", d.a, d.b, d.c);
-
- d.b = 20;
- printf("%d %d %d\n", d.a, d.b, d.c);
-
- d.c = 30;
- printf("%d %d %d\n", d.a, d.b, d.c);
- return 0;
- }
8 枚举的基本用法
8.1 问题
枚举是一个整型常量的列表,一般来说,值是有限个。每个值都是枚举常量(整型)。可以定义时指定值,也可以多个枚举名表示同一个值。枚举常量可看成字面量。
8.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:枚举的基本用法
代码如下所示:
- #include <stdio.h>
- enum WEEK
- {
- Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday,
- };
- int main()
- {
- int day;
- printf("请输入今天是星期几:");
- scanf("%d", &day);
-
- switch(day)
- {
- case Monday:
- printf("星期一\n");
- break;
- case Tuesday:
- printf("星期二\n");
- break;
- case Wednesday:
- printf("星期三\n");
- break;
- case Thursday:
- printf("星期四\n");
- break;
- case Friday:
- printf("星期五\n");
- break;
- case Saturday:
- printf("星期六\n");
- break;
- case Sunday:
- printf("星期日\n");
- break;
- }
- return 0;
- }
上述代码中,以下代码:
- enum WEEK
- {
- Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday,
- };
定义了一个枚举WEEK,是一个整型常量的列表,Monday是1,后面的值依次加1。
上述代码中,以下代码:
- int day;
- printf("请输入今天是星期几:");
- scanf("%d", &day);
首先,定义一个整型变量day,用于存储星期几的整数。
然后,使用printf提示输出输入星期几。
最后,使用scanf输入星期几到整型变量day中。
上述代码中,以下代码:
- switch(day)
- {
- case Monday:
- printf("星期一\n");
- break;
- case Tuesday:
- printf("星期二\n");
- break;
- case Wednesday:
- printf("星期三\n");
- break;
- case Thursday:
- printf("星期四\n");
- break;
- case Friday:
- printf("星期五\n");
- break;
- case Saturday:
- printf("星期六\n");
- break;
- case Sunday:
- printf("星期日\n");
- break;
- }
使用switch结构将整形星期几转换成字符串的星期几。其中每个case后面为一个枚举值。
8.3 完整代码
本案例的完整代码如下所示:
- #include <stdio.h>
- enum WEEK
- {
- Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday,
- };
- int main()
- {
- int day;
- printf("请输入今天是星期几:");
- scanf("%d", &day);
-
- switch(day)
- {
- case Monday:
- printf("星期一\n");
- break;
- case Tuesday:
- printf("星期二\n");
- break;
- case Wednesday:
- printf("星期三\n");
- break;
- case Thursday:
- printf("星期四\n");
- break;
- case Friday:
- printf("星期五\n");
- break;
- case Saturday:
- printf("星期六\n");
- break;
- case Sunday:
- printf("星期日\n");
- break;
- }
- return 0;
- }
posted on 2017-07-14 15:46
silvercell 阅读(111)
评论(0) 编辑 收藏 引用 所属分类:
c raise