12天学好C语言——记录我的C语言学习之路
Day 12:
进入最后一天的学习,用这样一个程序来综合考量指针和字符串的关系,写完这个程序,你对字符串和指针的理解应该就不错了。
//输入一个字符串,内有数字和非数字字符,如:A123x456 17234?532tab32622,然后将,123,456,17234,532,32622这些被非数字字符分割开的数字找出来,输出这些数。
//此程序的关键点在于遇到需要输出的字符就记录下来,然后判断他的下一个字符是不是有效字符,有效则不做判定继续执行有效字符的记录工作,如果遇到无效字符,那么这时候就要输出 从记录的第一个字符开始到这个无效字符的前一个字符 之间的所有字符。我们记录的正是这一段有效字符的个数(用k记录),也正是这段字符的首、尾地址的差,然后用指针变量指向首地址,依次输出地址里面的值。
//当然,我输出的形式还是char,如果题目要求读者将分割开来的数用int型输出,那么不妨将每一个字符都做一个这样的处理,比方说第一个分割出来的数是123,这时的123是字符'1'字符'2'和字符'3',另外我们知道这时的 k=3 ,我们可以用
// ('1'-'0')*pow(10,k-1)+('2'-'0')*pow(10,k-2)+('3'-'0')*pow(10,k-3) 来表示,这里的重点在于字符型数字如何转化成整型的数字,用到的是 这个数字字符 和 数字字符'0' 之间的距离正好就是 这个数字字符 的 值。另外,这里的k-1,k-2,k-3可以用k-i来表示,i的范围是1~k
/*//program 12.1
#include<stdio.h>
#include<string.h>
int main()
{
char a[]="A123x456 17234?532tab32622";
void search(char *);
search(a);
return 0;
}
void search(char *a)
{
char *p1=a;
long length=strlen(a);
int i=0,k=0,sum=0;
for (;i<length; i++) {
p1=a+i;
if (*p1>48&&*p1<57) {
k++;
if (*(p1+1)<48||*(p1+1)>57) {
for (int j=0; j<k; j++) {//这个和下面的程序就略有不同了,这里每次分割完一个数字,就将k初始化为0,而且每次用到j的时候也都是从0开始使用的。所以结果也是正确的
printf("%c",*(p1-k+1+j));
}
k=0;
printf(" ");
sum++;
}
}
}
printf("\n共有%d个数字被分割",sum);
}
*/
如果你上面的程序会了,那么你试着做一做下面这个题。
//55234152349555098958788955584 分割这样一串数字,要求是用5分割,如将左边的一串数字分割成
//55 2341 5 2349 555 0989 5 87889 555 84 然后最后得到的结果为2341 2349 0989 87889 84
/*//program 12.2
#include <stdio.h>
#include <string.h>
int main()
{
char a[]="55234152349555098958788955584";
void search(char *);
search(a);
return 0;
}
void search(char *p){
long length=strlen(p);
int i=0,k=0,j=0,sum=0;
for (; i<length; i++) {
if (*(p+i)!='5') {
k++;
if (*(p+i+1)=='5'||*(p+i+1)=='\0') {//这里必须加上空值,因为上面不是5结尾的
for (; j<k; j++) {
printf("%c",*(p+i-k+1+j));//这个地方是一个比较逗B的巧合,因为我们在输出第一个分割出来的数字时,k和j都没有归0,那么如上面的一串数字,在输出第二个数字的时候,k是从5开始的(因为第一个分割出来的数字有4位,也就是k=4),那么等第二个数字遍历完毕时,k应该变成了8(同理,第二个分割出来的数字也是有4位的)。再看j,第一次分割结束的时候跳出for循环的时候j做了一次j++,那么j的值就和k当时的值是一样的,所以j在进入第二个分割数的for循环的时候j应该是4,而不是0,那么第二次分割出来的数字的首字符应该是*(p+10-8+1+4),也就是*(p+7),正好就是数字2349中2的地址。这个地方可以说是误打误撞,读者可能在看这个地方的时候看不懂是怎么得到的正确结果。
}
sum++;
printf(" ");
}
}
}
printf("\n共有%d个数字被分割",sum);
}
*/
好了指针部分也差不多结束了,敲了不少程序,希望大家能够准确理解指针~
接下来转入结构体,也是最后一个环节的学习。
//结构体类型事实上和int,char,float类型都大同小异,只不过结构体类型是我们自己定义的类型。结构体类型和结构体变量不是一回事,我们知道只能对变量赋值,存取或者运算,而不能对类型如此,类型是不需要分配空间的,只能对变量分配空间。
//定义结构体类型的格式: struct 结构体名{ 成员表列 }; 注意在声明结构体类型的时候要最后加上分号。
//当然在声明结构体类型的同时可以定义变量: struct 结构体名{ 成员表列 } 变量名表列;
//另外要注意的是结构体类型中的成员名和程序中的变量名如果相同,但二者不代表同一对象的,是两回事,互不干扰
//定义Student结构体类型,然后将一个同学信息(学号,姓名,性别,住址)放在一个结构体变量中,然后输出该学生的成绩。
/*//program 12.3
#include "stdio.h"
int main()
{
struct Student
{
int number;
char name[20];
char sex[20];//注意,如果在结构体类型中有成员是字符串形式的,那么这里要将成员定义成字符数组的形式
char addr[30];
};
struct Student a={123456,"wangzhongyao","man","shandongshengjinanshi"};//这里是先声明结构体类型,然后再定义结构体变量a,分开进行。下面给出在结构体类型声明的同时定义变量的情况。
printf("No.%d\nname:%s\nsex:%s\naddress:%s\n",a.number,a.name,a.sex,a.addr);//这里输出的并不是a,而是a的各个属性,我们输出的是a的详细信息,所以要用 a.变量名 来输出。这里很重要。
return 0;
}
*/
//还是上面的程序,在结构体类型声明的同时定义结构体变量。
/*//program 12.4
#include<stdio.h>
int main()
{
struct Student
{
int number;
char name[20];
char sex[10];
char addr[30];
}
a={123,"maxingze","man","jiningshilaozhaizhen"},b={1234,"yuetianhao","man","jiningshijiaxiangxian"};
//这里注意,在结构体类型声明的同时定义结构体变量的话,要把结构体变量定义在结构体类型声明时最后一个分号的前面!!!!!这里一定要注意哦!!!
printf("No.%d\nname:%s\nsex:%s\naddr:%s\n\n",a.number,a.name,a.sex,a.addr);
printf("No.%d\nname:%s\nsex:%s\naddr:%s\n\n",b.number,b.name,b.sex,b.addr);
return 0;
}
*/
/*//program 12.5
//对结构体类型中某一成员进行初始化(不完全初始化成员),其余未被初始化的成员是什么情况?下面给出解答。
#include<stdio.h>
int main()
{
struct Student
{
int card;
char name[10];
char sex[10];
char bumen[20];
}
a={.name="man"};//允许对结构体中的某一成员初始化,其他 未被初始化的 数值型成员 被初始化为0,未被初始化的 字符型成员 被初始化为'\0',未被初始化的 指针型成员 被初始化为NULL。这里必须要牢记!!!!!!!
printf("Card:%d\nname:%s\nsex:%s\nbumen:%s\n",a.card,a.name,a.sex,a.bumen);
return 0;
}
*/
/*//program 12.6
//结构体变量之间可以互相赋值
#include <stdio.h>
int main()
{
struct Student
{
int card;
char name[10];
char sex[10];
}
a={123,"a","man"},b={321,"b","woman"};//在结构体类型声明的时候定义变量,要注意定义多个变量的时候中间用','隔开,在最后的一个变量定义结束时加一个';'即可,当然最后加很多';'也没有错误(验证得到)。
a=b;//同类型结构体变量之间可以相互赋值(如: a=b;),同样同类型结构体变量中相同成员也可以互相赋值(如: a.card=b.card;)
printf("card:%d\nname:%s\nsex:%s\n",a.card,a.name,a.sex);
return 0;
}
*/
//注意不能用以下语句整体读入结构体变量
//scanf("%d,%s,%s\n",&a); 因为结构体变量的地址主要用作函数参数,传递结构体变量的地址。(这句话需要读者好好理解!!!)
//那应该怎么读入结构体变量呢? 显然要将结构体变量中每一个成员 分别 读入,如下:
//scanf("%d,%s,%s\n",&a.card,&a.name,&a.sex);
//输入两个学生的学号、姓名和成绩,输出成绩较高的学生的学号、姓名和成绩
//下面的题目中没有写两个学生成绩相等的情况,读者可以自行加上
/*//program 12.7
#include "stdio.h"
int main()
{
struct Student
{
int number;
char name[20];
int grade;//成绩是一个整数,这里不要错误的声明为数组类型
}
a,b;
printf("请输入两个学生的学号、姓名、成绩:\nNo.1:\n");
scanf("%d%s%d",&a.number,a.name,&a.grade);
//scanf(格式控制,地址表列); 这里的地址表列可以是变量的地址,也可以是字符串的首地址。(这句话很重要,在上面一句输入语句中,只有a.name没有加'&'号,这是因为name为数组名,代表了字符串数组的首地址,所以说a.name就是一个地址,所以不用再加'&'了)
printf("No.2:\n");
scanf("%d%s%d",&b.number,b.name,&b.grade);
if (a.grade>b.grade) {
printf("number:%d\nname:%s\ngrade:%d\n",a.number,a.name,a.grade);
}
else
{
printf("number:%d\nname:%s\ngrade:%d\n",b.number,b.name,b.grade);
}
return 0;
}
*/
/*//program 12.8
//有3个候选人,编一个统计选票的程序,先后输入备选人的名字,然后输出个人选票结果
#include <stdio.h>
struct Person
{
char name[20];
int count;
}lead[3]={"ma",0,"wang",0,"zheng",0};
int main()
{
char lead_name[20];//声明一个字符数组,用来存放下面10次投票时 每一次 投票的人选姓名
printf("请投票10次:\n");
for (int i=0; i<10; i++) {
scanf("%s",lead_name);//这里的lead_name就是数组名,表示的就是这个字符串的首地址。i=10,所以这里要输入10个字符串,分10次输入,下面调用strcmp函数就是将 每一次 投票的任选姓名和候选名单中的三个姓名比较,如果一样,那么结构体变量中的count成员就+1 。
for (int j=0; j<3; j++) {
if (strcmp(lead_name,lead[j].name)==0)//这里为什么能用lead_name呢?这个不是地址么,这里应该是比较两个字符串的值把? 记住就好了,字符数组,用数组名来比较即可
{
lead[j].count++;
}
}
}
for (int i=0; i<3; i++) {
printf("%s:%d\n",lead[i].name,lead[i].count);
}
return 0;
}
*/
//定义结构体数组的一般形式是
// struct 结构体名 { 成员表列 } 数组名[数组长度] ;
//或者是先声明一个结构体类型,然后再定义结构体数组,在已经声明好结构体类型的情况下我们可以这样定义:
//结构体类型 数组名[数组长度]={初值表列}; (如: struct Person a[3]={"ma",0,"wang",0,"zheng",0}; )
//有n个学生的信息(学号、姓名、成绩),要求按照成绩的高低顺序输出各学生的信息
/*//program 12.9
#include "stdio.h"
struct Student
{
int number;
char name[20];
int grade;
};
void change(struct Student *a,int n)
{
struct Student temp;//这里的temp和上面数组中的成员是一样的类型,用来在下面排序时作交换的。
int i,j,k;
for (i=0; i<n-1; i++) {
k=i;
for (j=i+1; j<n; j++) {
if (a[k].grade<a[j].grade) {
k=j;
}
}
temp=a[k];
a[k]=a[i];
a[i]=temp;
}
for (i=0; i<n; i++) {
printf("number:%d name:%s grade:%d\n",a[i].number,a[i].name,a[i].grade);
}
}
int main()
{
struct Student ss[]={1001,"wang",98,1002,"ma",99,1003,"zheng",87,1004,"yue",89,1005,"zhang",100};
void change(struct Student *a,int n);
change(ss,5);
return 0;
}
*/
//结构体指针。通过 指向 结构体变量 的指针 来访问 结构体变量 中的 成员。
//首先我们要知道,这个结构体指针是指向结构体变量的,然后再通过指针去访问结构体变量的成员。
//结构体指针其实和普通指针差不多,就是指向的结构体变量,而且多了一种形式(p->number)。
/*//program 12.10
#include "stdio.h"
#include "string.h"
struct Student
{
int number;
char name[30];
char sex[10];
int grade;
};
int main()
{
struct Student a;
a.number=1001;
strcpy(a.name,"Xingze Ma");//这里需要注意一下,如果不是直接对整个结构体变量初始化,而是对其中一个一个成员分别初始化,那么在初始化字符数组成员的时候(也就是需要初始化一个字符串),需要用到strcpy函数,这个函数是复制字符串的。对于字符串的赋值,不能说char a[10]; a=“123”; 这样错误。 对于字符串赋值,要么在声明的初始化(char a[10]=“123”;),要么用scanf函数给字符串输入值,要么就要用strcpy函数复制字符串,而也是本题中用的方法,也最为常用
strcpy(a.sex,"gay");
a.grade=59;
struct Student *p;
p=&a;
printf("number:%d\nname:%s\nsex:%s\ngrade:%d\n\n",(*p).number,(*p).name,(*p).sex,(*p).grade);
//'.'运算符优先于'*'运算符,所以这里必须加括号(*p)
printf("number:%d\nname:%s\nsex:%s\ngrade:%d\n",p->number,p->name,p->sex,p->grade);
//为了方便,允许把 (*p).number 用 p->number 来代替,含义是p所指向的 结构体变量 中的 number成员
//所以以下3种情况是等价的
//struct Student a; struct Student *p=&a;
//①a.number ②(*p).number ③p->number
return 0;
}
*/
//指向结构体数组的指针
//和指向一般数组的指针也别无二致,就是指向结构体数组的首地址即可
/*//program 12.11
#include "stdio.h"
struct Student
{
int card;
char name[20];
char sex[20];
}
a[]={{1001,"wang","man"},{1002,"ma","woman"},{1003,"zheng","gay"}};
int main()
{
struct Student *p=a;
for (; p<a+3; p++) {//这里无论是什么情况下在for循环中用指针,这是p<a+3,而不是p<p+3 , 牢记!!!!
printf("card:%d\nname:%s\nsex:%s\n\n",p->card,(*p).name,p->sex);
}
return 0;
}
*/
//用 结构体变量 和 结构体变量的指针 作函数参数
//有n个结构体变量,内含学生学号、姓名和3门课程的成绩。要求输出平均成绩最高的学生的信息。
/*//program 12.12
#include "stdio.h"
#define N 3
struct Student
{
int num;
char name[20];
float score[3];
float aver;
};
void scanf1(struct Student ss[])
{
printf("请输入各学生信息:\n");
for (int i=0; i<N; i++) {
scanf("%d%s%f%f%f",&ss[i].num,&ss[i].name,&ss[i].score[0],&ss[i].score[1],&ss[i].score[2]);
ss[i].aver=(ss[i].score[0]+ss[i].score[1]+ss[i].score[2])/3;
}
}
struct Student max(struct Student ss[])
{
float max=ss[0].aver;
int k=0;
for(int i=1;i<N;i++)
{
if(max<ss[i].aver)
{
max=ss[i].aver;
k=i;
}
}
return ss[k];
}
void print(struct Student s)
{
printf("成绩最好的学生是:\n%d %s %5.2f %5.2f %5.2f",s.num,s.name,s.score[0],s.score[1],s.score[2]);
}
int main()
{
void scanf1(struct Student ss[]);//这里要传入结构体数组中数组元素,因为我们比较好几个学生的平均成绩,自然要准备一个数组存放它们
struct Student max(struct Student ss[]);
void print(struct Student s);
struct Student s[N];
scanf1(s);//这里传进去的是数组s[N]的首地址,所以这里我们也可以用指针操作,可以定义一个结构体指针指向s[N],然后调用函数的时候用p来调用,其作用是一样的
print(max(s));
//struct Student q;
//q=max(p);
//print(q);
return 0;
}
*/
program 12.12 将我们学过的知识基本上汇合了一下,我们的学习也就到此结束了,短短12天,学到的东西很多,我只把C语言部分介绍到结构体,剩下还有一些结构体和链表、共用体类型、文件读写等等部分我就不一一介绍了。时间有限,由读者自行学习。希望读者能学习到一些知识,那么我写的这几篇连载博客也就有价值了。希望大家学习愉快!
版权声明:本文为博主原创文章,未经博主允许不得转载。