zoukankan      html  css  js  c++  java
  • C语言 深入学习

    浮点数:

    x = Mx*2^Ex为一个规格化浮点数,Mx为x的尾数,Ex为x的阶码。
    1e-6:表示1 * 10 ^ (-6)。
    编译时执行:
    sizeof是运算符(而非函数),在编译时执行,不会导致额外的运行时间开销。
    三元运算符:是右结合运算。

    数据类型:

    char:占1个字节
    short:占2个字节
    int:占4个字节
    float:占4个字节
    double:占8个字节
    
    一个变量本身定义为常量const时,必须初始化
    常量指针:不能通过常量指针修改其指向的值(只是从p的角度来看)。
    const int *p;
    int const *p;
    指针常量:指针其本身就是常量(故定义时须初始化),而且也不能通过这个指针修改其指向:
    int * const p = &a;
    
    数组指针(指向一维数组的指针 / 行指针):char (*p)[10] —— 打括号就是说,先看括号里面的。故可以这样理解:
    举例, 二维数组char a[10][10], char (*p)[10];p = a。
    首先确定,char (*p)[10]只是将p定义为一个指针(其作用是指向某个数组整体,而不是这个数组中的某个元素);10就是指定了指向的数组的长度
    p = a就让p指向了a[0]这个数组;于是p++,就让p指向了下一个数组a[1];
    所以若p = a,那么*p就是获得a[0]这个数组。
    既然char (*p)[10]是指向数组的指针,那么通用的使用就是:把数组的地址给p,即char (*p)[10];char s[]="abcd";p=&s;
    而二维数组a[][]的数组名a的含义是:a == &a[0];
    
    指针数组(数组元素是数组):char *p[10] —— 没有括号,所以可以这样看:这是一个数组,其元素类型是char *p。这里是一个放了10个指针的数组。所以p[0]=arrary;是指向数组首元素,而不是整个数组

    标准输入输出格式:

    当数据的实际位宽大于printf中的指定位宽时,将按照数据的实际位宽输出数据

    //输出
    printf("%ld
    ", test);     /* 以长整型格式输出 */
    printf("%f
    ", test);       //输出单双精度浮点数
    printf("%4.2f
    ", test);       //输出数据共占4位(包括小数点),有2位小数;其他数据类型也是如此(自然有些是没有小数的)
    printf("%u", n);    //n是unsigned int
    printf("%s
    ", str);    //输出一个字符串
    printf("%p
    , p);   //输出地址
    
    //输入
    /*scanf:返回值为成功接收到的、输入的变量值个数。
    如scanf("%d%d%d",i,j,k,a,b)则只能返回3(因为只能接收三个)*/
    char *str = (char *)malloc(N * sizeof(char)); scanf("%s", str);        //输入一个字符串
    scanf("%lf", &test);       //输入双精度浮点数
    scanf("%d,%d", &a, &b);        //输入必须与指定的格式相同。比如这里有",",那么在Console中输入也需要","

    随机数:

    //#include <stdlib.h>:rand、srand
    //#include <time.h>:time
    srand(0);
    printf("%d
    ", rand());        //rand对应于srand,只要srand的种子不变,rand的随机值也不会变;rand的范围是0 - int
    srand(time(NULL));    //srand(unsigned)
    printf("%d
    ", rand());        //time函数返回当前时间(秒);参数param如果不为BULL,则time会将时间赋给param。故这样一来随机数就会一直改变(真正实现随机)
    printf("%d
    ", rand() % 100 + 1);        //生成1-100的随机数:rand() % 100是0-99

    指数函数:

    pow(x, y)        //表示x的y次方 —— math.h

    数组:

    初始化:

    int count[10] = {0};    //长度为10的数组,全都初始化为0;定义数组时,数组长度只能是常量,不能是变量或含变量的表达式

    二维数组:

    多维数组在内存中实际上都是一维存储的。例如二维数组,我们只是在逻辑上可以理解为二维的矩阵,但实际上二维数组是一维数组,每个元素还是一维数组,所以整个二维数组都是"一条线"
    1、因此int a[3][3]={1...9};int (*p)[3] = a;此时不仅可以*(*p+2),还可以*(*p+8)=*(*(p+2)+2),只要不越二维数组的界(这里是9);
    简单点就是:int a[3][3] = {1...9};int *p = &a[0][0];此时可以从头指到尾:头是*p,尾是*(p+8);
    2、所以二维数组a有m行n列,则在a[i][j]之前的元素个数为i * n + j —— 因为a[i][j]是第i + 1行,第j + 1列,而前i行都是在a[i][j]之前的

    求数组大小:

    char s[][20] = { "first", "second", "Third" };
    char (*p)[20] = s;
    printf("%d %d
    ", sizeof(s) / 20, sizeof(p));    //3、4:因为p要找"",即'' —— {"...", "...", "...", ""}
    //用指针数组
    char *p[] = {"How", "are", "you"};
    printf("%d
    ", sizeof(p) / sizeof(char *));

    函数

    函数返回值:

    printf("%d
    ", func(-1));        //main函数
    
    int func(int i)
    {
        if (i == 0)
        {
            return i;
        }
        else
        {
            printf("h
    ");        //这种情况,会返回printf输出的字符个数(包括转义符):此时return 2
        }
    }

    数组作为函数参数,形参数组与实参数组实际上是同一个数组,即传址调用;数组作为实参,只需要写数组名(无论是几维数组)。

    变量的生命周期与作用域:

    #include <stdio.h>
    
    void Incre();
    
    int main()
    {
        Incre();
        Incre();
        return 0;
    }
    
    void Incre()
    {
        static int x = 1;        //静态:第二次就输出上次,保存的x的值;此外这还是一个局部var,因此作用域还是Incre
        printf("%d
    ", ++x);
    }

    字符串:

    字符常量与字符串常量的区别:

    • 字符串常量:1、字符串里面包含的字符是连续存储的。2、每个字符串都有结束标记(""),这是一个特殊的字符,即ASCII码为0的字符。3、C语言用字符数组(没有字符串变量)来动态存储字符串,例如char s[10] = {'a', 'b', ''}是一个字符串,而char s[10] = {'a', 'b'}不是。或者写为char s[] = "abc"(在初始化的情况下可以省略数组大小)。存储多个字符串(用二维数组):char s[][10] = {"星期一", "星期二"}(第一个大小可省略,由字符串的个数,即二维数组中包含数组的个数决定)。
    • 字符常量:char s = 'a'。

    用指针来访问字符串:

    #include <stdio.h>
    
    int main()
    {
        char *p = NULL;
        char s[] = "abc";
        p = s;    //反过来就不行了,因为数组名相当于是一个指针常量
        printf("%c
    ", *p);        //现在只是指向字符串的第一个字符
        //printf("%s
    ", *p);    //这样是不行的,应该是printf("%s
    ", p);输出的是这个指针指向字符串的某个字符以及后面剩下的字符,所以p在此时可以用s替代
        return 0;
    }

    输入输出字符串:

    char s[] = "adjshd";
    char s1[] = "casn";char *p = s;
    char *p1 = s1;
    gets(p);        //可以输入空格
    puts(p);
    scanf("%s", p1);
    printf("%s
    ", p1);

    但是gets是存在安全隐患的(它没有限制输入的大小,即输入可能超出字符数组的大小,此时就可能把输入存到了指定的字符数组之外的地方):

    char s2[] = "sdfjhasjd";
    char *p2 = s2;
    char n = 3;
    //fgets限制输入的长度
    fgets(p2, n, stdin);    //最多只能接收n - 1个字符
    puts(p2);

    getchar函数:

    用处1:

    #include <stdio.h>
    #include <math.h>
    
    int main()
    {
        int n = 0;
        char c = 'c';
        int result = scanf("%d", &n);
        if(result != 1)        //输入与scanf指定的类型不符,则不能接收到。未能成功接收的字符会暂时放在缓冲区
        {
            c = getchar();        //此时getchar就是将缓冲区的字符一次取走一个,并返回
        }
        printf("%d %c
    ", n, c);
        return 0;
    }

    用处2:

    #include <stdio.h>
    #include <math.h>
    
    int main()
    {
        char c = 'c';
        //getchar直接从stdin读取一个字符,putchar从stdout输出
        c = getchar();
        putchar(c);
        return 0;
    }

    字符串处理函数:

    //需要#include <string.h> -- 字符串处理函数strcmp、strlen、strcpy、strcat
    strcmp(s1, s2); //两个字符串自左向右,逐个字符相比(比较ASCII码),直到出现不同字符或''为止,此时若:s1==s2;return 0;s1 > s2;return 1;否则return -1.
    strlen(s1); //返回字符串s1的长度,例如:char s1[10] = "abcde";printf("返回字符串的长度:%d,返回数组的长度%d
    ", strlen(s), sizeof(s));
    char source[] = "hello kit";char destination[] = "world";
    puts(strcpy(destination, source));puts(destination);//source->destinations
    char source[] = "hello kit";char destination[] = "world";
    puts(strcat(destination, source));puts(destination);//即destination + source

    函数库:

    字符处理函数#include <ctype.h>:
    函数的参数皆为int,返回也为int
    int isdigit(int c); //判断是否为数字字符,例如:如果是'3',return 1;是'a',return 0;
    int toupper(int c);
    
    实用函数#include <stdlib.h>
    double atoi(const char *s);
    double atof(const char *s); //例如: //printf("%6.2f ", atof("1e2"));输出:100.00——还要算上小数点 //printf("%6.2f ", atof("y3")); 输出: 0.00;就算是e3也不会当成是科学计数,而是和y3一样

    枚举类型:

    #include <stdio.h>
    
    int main()
    {
        //定义枚举类型,集合{}中的元素,是枚举元素 —— 供枚举变量进行选择
        //枚举元素的值:如果没有指定具体值,编译器会把第一个元素处理成0,后面元素以此+1:因此枚举元素是常量
        //当然也可以自定义枚举元素的值:例如指定Tuesday = 100,那么Wednesday也遵循+1的原则,因此Wednesday = 101
        enum Date { Monday, Tuesday, Wednesday };
        //定义枚举变量
        //1、直接在定义类型时,顺便把变量定义了
        //enum Date { Monday, Tuesday, Wednesday } date;
        //2、或者只定义变量
        //enum { Monday, Tuesday, Wednesday } date;
        //枚举变量选择具体的枚举值
        enum Date date = Tuesday;
        date = Wednesday;
        printf("%d
    ", date);
        return 0;
    }

    联合union:

    编译器处理union时,一个union所有成员共用同一段内存空间(同一时刻,只有一个成员使用内存空间,存放成员值),因此内存空间的大小=最长的成员大小。具体使用如下:

    #include <stdio.h>
    int main()
    {  
        union
        { 
            int i[2];
            int k;
            int c;
        } t, *s = &t;
        //给哪个成员赋值,内存空间就被这个成员使用
        s->i[0] = 10;
        s->i[1] = 20;
        printf("%d
    ", s->c);
        
        s->k=30;
        printf("%d
    ", s->c);
        
        s->c = 1000;
        printf("%d
    ", s->c);
        printf("%d
    ", s->i[1]);//始终为20
        return 0;
    }

    使用联合的一些注意事项:

    1、联合不能作为函数参数传递。2、不能整体初始化或者整体赋值,只能对其成员一个一个赋值。3、不能作为函数返回值。

    结构体:

    #include <stdio.h>
    
    typedef struct student
    {   
        int number;
        char name[20];
        char sex;
    } S;//此时S是别名
    struct
    {   
        int year;
        int month;
        int day;
    } birth;//此时birth是结构体变量
    
    int main()
    {
        S s;
        s.number = 1000;
        birth.year = 250;
        printf("%d %d
    ", birth.year, s.number);
        return 0;
    }

    文件操作

    <stdio.h>中的一些变量类型、宏定义:

    • 文件结束符:#define EOF     (-1)
    • 存储文件流信息的类型:typedef struct _iobuf FILE;
    • 类型的大小,即sizeof运算符的结果:typedef unsigned int size_t;

    打开已存在文件、或新建一个文件:

    函数原型:FILE *fopen(const char *filename, const char *mode);//用FILE的指针变量操纵文件
    根据打开模式(mode)的不同决定:新建或打开文件
    1、文本文件:
    mode的值:r(打开已有文件,只读)、w(打开文件,只写、覆盖写入,即打开后删除原有内容,重新写入。若文件不存在,则新建)、a(打开文件,只写、追加写入。若文件不存在,则新建)
    可读写:r+(打开已有文件,覆盖写入)、w+(新建文件)、a+(打开文件。若文件不存在,则新建。写:追加写入)
    2、二进制文件mode:形如ab、ab+
    =>每次读写都会从文件游标开始读(第一次读,游标在文件开头),游标属于fp指向的 FILE 变量:因此,对于同一个FILE变量,fgetc的调用也会影响到fgets的读取位置

    清空缓冲区数据,并关闭文件:

    函数原型:int fclose(FILE *fp);
    成功关闭,释放掉文件占用的内存,return 0;发生错误,return EOF(常量,在stdio.h中定义);

    写入文件:

    写入一个字符:int fputc(int c, FILE *fp);
    如果成功,return 刚写入的c;如果失败,return EOF;
    写入一个字符串:int fputs(const char *s, FILE *fp);
    如果成功,return 一个非负值;失败,return EOF;

    格式化写入文件:

    //与fputs同理,函数原型:int fprintf(FILE *fp, const char *formatSting, ...);
    //像printf一样,接受可变长参数,如:
    fprintf(fp, "%d != %d
    ", 1, 2);//即写入1 != 2

    读取文件:

    //与写入同理:int fgetc(FILE *fp)
    printf("%c
    ", fgetc(fp));
    fgetc(fp);//每调用一次,读取文件的游标,就会向后移动一个char
    printf("%c
    ", fgetc(fp));
    //读取字符串:char *fgets(char *buf, int n, FILE *fp);
    //读取n - 1个字符。并将读取到的字符串,复制到字符串变量buf中,最后以结束 —— buf的长度应不少于n
    //返回的字符串与buf的值相等
    char str[7];
    char *buf = str;
    printf("%s
    ", fgets(buf, 7, fp));//如果还未读取n个char,就遇到了
    或者EOF,则直接结束本次读取(包含
    )

    直接读取一个单词(从游标开始,到遇到的第一个空格为止,认为是一个单词;游标是读到了这个空格的,因此调用下面的函数后,游标指向这个空格之后):

    char buff[255];
    //与fprintf不同:%s作为sourceString(不加修饰),buff作为destString
    fscanf(fp, "%s", buff);
    fscanf(fp, "%s", buff);
    printf("%s
    ", buff);//读到第二个单词

    检测当前游标是否指向文件结尾(EOF):

    int feof(FILE *fp);//文件结束,return 1;否则return 0;
  • 相关阅读:
    DDD中的聚合和UML中的聚合以及组合的关系
    服务端高并发分布式架构演进之路
    互联网架构的演变,那些神奇的东西怎么来的?
    WPF 之 创建继承自Window 基类的自定义窗口基类
    IIS 之 在IIS7、IIS7.5中应用程序池最优配置方案
    性能测试工具 之 性能计数器
    IIS 之 线程池最大线程数
    WebService 之 已超过传入消息(65536)的最大消息大小配额。若要增加配额,请使用相应绑定元素上的 MaxReceivedMessageSize 属性。
    IIS 之 Web 服务器上的 ASP.NET 进程模型设置
    ADO.Net 之 数据库连接池(二)
  • 原文地址:https://www.cnblogs.com/quanxi/p/6553872.html
Copyright © 2011-2022 走看看