12天学好C语言——记录我的C语言学习之路(Day 12)

时间:2021-12-15 01:29:58

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语言部分介绍到结构体,剩下还有一些结构体和链表、共用体类型、文件读写等等部分我就不一一介绍了。时间有限,由读者自行学习。希望读者能学习到一些知识,那么我写的这几篇连载博客也就有价值了。希望大家学习愉快!

版权声明:本文为博主原创文章,未经博主允许不得转载。

12天学好C语言——记录我的C语言学习之路(Day 12)的更多相关文章

  1. 12天学好C语言——记录我的C语言学习之路(Day 11)

    12天学好C语言--记录我的C语言学习之路 Day 11: 因为指针部分比较的难,所以我们花费的时间也是最长的,希望大家耐的住性子,多多理解,多多打代码.好了,废话不多说,来看第11天的学习. //编 ...

  2. 12天学好C语言——记录我的C语言学习之路(Day 10)

    12天学好C语言--记录我的C语言学习之路 Day 10: 接着昨天的指针部分学习,有这么一个题目: //还是四个学生,四门成绩,只要有学生一门功课没及格就输出这个学生的所有成绩 /*//progra ...

  3. 12天学好C语言——记录我的C语言学习之路(Day 9)

    12天学好C语言--记录我的C语言学习之路 Day 9: 函数部分告一段落,但是我们并不是把函数完全放下,因为函数无处不在,我们今后的程序仍然会大量运用到函数 //转入指针部分的学习,了解指针是什么 ...

  4. 12天学好C语言——记录我的C语言学习之路(Day 8)

    12天学好C语言--记录我的C语言学习之路 Day 8: 从今天开始,我们获得了C语言中很有力的一个工具,那就是函数.函数的魅力不仅于此,一个程序到最后都是由众多函数组成的,我们一定要用好函数,用熟练 ...

  5. 12天学好C语言——记录我的C语言学习之路(Day 7)

    12天学好C语言--记录我的C语言学习之路 Day 7: 昨天进行了一天的数组学习,今天大家可以先写几个昨天的程序热热身,回顾回顾,然后今天第一个新程序也是关于数组的,比较难,准备好就开始啦! //输 ...

  6. 12天学好C语言——记录我的C语言学习之路(Day 6)

    12天学好C语言--记录我的C语言学习之路 Day 6: 今天,我们要开始学习数组了. //①数组部分,数组的大小不能够动态定义.如下: //int n;   scanf("%d,& ...

  7. 12天学好C语言——记录我的C语言学习之路(Day 5)

    12天学好C语言--记录我的C语言学习之路 Day 5: 第五天的学习开始了,今天我们主要对几个程序进行编写,让自己充分的熟练编程语言,大量的题目会让自己变的精炼.以一个程序(program 5.1) ...

  8. 12天学好C语言——记录我的C语言学习之路(Day 4)

    12天学好C语言--记录我的C语言学习之路 Day 4: 首先来看一段程序: //输出下面4*5的矩阵 /* 1  2  3   4   5 2  4  6   8   10 3  6  9   12 ...

  9. 12天学好C语言——记录我的C语言学习之路(Day 3)

    12天学好C语言--记录我的C语言学习之路 Day 3: 不知不觉到了第三天的学习,我们前两天学习的东西很杂乱,各个方面都有学习.我觉得这不是不系统,也不是学的不扎实,这种学习对于初学者而言我认为是很 ...

随机推荐

  1. 如何通过自定义注解实现AOP切点定义

    面向切面编程(Aspect Oriented Programming, AOP)是面向对象编程(Object Oriented Programming,OOP)的强大补充,通过横切面注入的方式引入其他 ...

  2. Bean 的作用域

    •在 Spring 中, 可以在 <bean> 元素的 scope 属性里设置 Bean 的作用域. 默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一一个实 ...

  3. 如何手动让HttpRequestBase&period;IsAuthenticated 和 HttpContext&period;User&period;Identity&period;IsAuthenticated 为true&period;

    今天为了重写权限验证这块需要重写AuthorizeAttribute 这个属性,看了官方文档:HttpContextBase.User.Identity.IsAuthenticated 这个必须是tr ...

  4. openwrt 中procd

    https://wiki.openwrt.org/doc/techref/procd Procd:Openwrt的进程管理守护进程(process management daemon),它与初始化脚本 ...

  5. Java并发-对象共享

    我们不仅希望防止某个线程正在使用对象状态而其他的线程正在修改该状态,而且希望当一个线程修改了对象状态后,其他的线程能够看到发生的状态变化. 可见性:当读操作和写操作在不同的线程中进行时,他们的动作是共 ...

  6. java随笔3 spring 的注入执行逻辑顺序

  7. SpringBoot系列&colon; 集成MyBatis

    本文主要修改自下面博客:http://www.ityouknow.com/springboot/2016/11/06/spring-boo-mybatis.htmlhttp://tengj.top/2 ...

  8. 数据库学习之数据库增删改查(另外解决Mysql在linux下不能插入中文的问题&rpar;&lpar;二&rpar;

    数据库增删改查 增加 首先我们创建一个数据库user,然后创建一张表employee create table employee( id int primary key auto_increment, ...

  9. Bootstrap-CSS

    ylbtech-Bootstrap-Plugin: 1.返回顶部 1.   2. 2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部 1.   2.   11.返回顶部   作者:yl ...

  10. 《&lbrack;MySQL技术内幕:SQL编程》读书笔记

    <[MySQL技术内幕:SQL编程>读书笔记 2019年3月31日23:12:11 严禁转载!!! <MySQL技术内幕:SQL编程>这本书是我比较喜欢的一位国内作者姜承尧, ...