未禾的C语言总结

2023-04-27 20:53:20 浏览数 (1)

**************************************************************************************************************************************************************************************************************** 操作符解释:     1,算术操作符:         ‘ ’、‘-’、‘*’、‘/’、‘%’         %取模操作符只能用于整数,         /除法操作符,两个操作数均是整数时为整数除法,有一个是浮点数则执行浮点数除法。         如:int a = 6/5;//->a==1             double b = 6/5;//->b==1.000000             double c = 6.0/5//->c==1.200000,即实际运算与定义的储存类型无关     2,移位操作符         左移‘<<’、右移‘>>’         左移操作符:             如:   int a=2;                 int b = a << 1;//a向左移动一位,结果存入变量b中,结果b为4             正整数2在内存中存放的补码为:                                00000000000000000000000000000010             向左移动一位,左边的首位0去掉,右边的缺一位补0:00000000000000000000000000000100 ->4(十进制)         右移操作符:             右移时分为算数右移和逻辑右移。             算数右移:右边丢弃,左边补符号位。             逻辑右移:右边丢弃,左边补0。             如:int a = -10;                    int b = a >> 1;//a向右移动一位,结果存入变量b中             正整数10在内存中的补码为11111111111111111111111111110110//若为负数则原码与补码不同。             算术右移:             11111111111111111111111111111011 ->-5             逻辑右移:             01111111111111111111111111111011 ->2,147,483,643         对移位操作符移动负数位,这时C语言未定义的,不要使用。     3,位操作符         按位与‘&’、按位或‘|’、按位异或‘^’         位解释为二进制的一位。         &按位与,全为1时结果才为1,其他情况结果均为0             如:int a = 3;//        00000000000000000000000000000011                    int b = 5;//        00000000000000000000000000000101                    int c = a & b;//    00000000000000000000000000000001->1(十进制)             eg:找出一个整数的二进制的1的个数。                 #include <stdio.h>                 int main(){                 int a=1;                 int cnt=0;                 for(int i=0; i<31; i ){                     if((a&1) == 1){//整数的二进制数的1的个数                          cnt ;                     }                     a=a >> 1;                 }                 printf("%dn",cnt);                 return 0;             }          |按位或,全为0时结果才为0,其他情况结果均为1             如:int a = 3;//    00000000000000000000000000000011                    int b = 5;//    00000000000000000000000000000101                    int c = a | b;//    00000000000000000000000000000111->7(十进制)         ^按位异或,不同为1,相同为0。一个数a与另一个数b异或两次结果仍是a本身,数a与0异或结果仍为数a。             如:int a = 3;//    00000000000000000000000000000011                    int b = 5;//    00000000000000000000000000000101                    int c = a ^ b//    00000000000000000000000000000110->6(十进制)         eg:交换两个数a=3,b=5,要求不使用第三个变量。             #include <stdio.h>//此法适用于a,b相加的结果不超过类型范围的情况,有缺点             int main(){                 int a=3;                 int b=5;                 a = a b;//变量a储存a与b的和                 b = a -b;//变量b储存原来a的值                 a = a - b;//变量a储存原来b的值             return 0;             }             #include <stdio.h>//此法适用于a,b相加的结果不超过类型范围的情况,有缺点             int main(){                 int a=3;                 int b=5;                 a = a ^ b;                 b = a ^ b;//3 ^ 5 ^ 5的结果3存入到b中                 a = a ^ b;//3 ^ 5 ^ 3的结果5存入到a中             return 0;             };     4,赋值操作符         =     =    -=    *=    /=    %=    <<=     >>=         ‘=’是赋值,‘==’是等号。         int  a = a 4;//等价于a =4;         连续赋值:         如:int b = a = a 1;//等价于a = a 1; b = a;         连续赋值不好进行调试,阅读不便。         5,单目操作符         !(逻辑反)    -(负值)     (正值)    ~(按位取反)         sizeof(操作数的类型长度,按字节计算)    --           &(取地址)    *(间接访问操作符或解引用操作符)    (类型名)强制类型转化         ‘i’一般用于条件判断,0的反是1,非0的反是0;             如:             #include <stdio.h>             int main(){                 int flag =0;                 if(flag){                     printf("Yesn");//条件为假,语句不执行                 }                 if(!flag){                     printf("YesYesn");//条件为真,语句执行                 }             return 0;             };         ‘~’对二进制位的操作,类比按位与、按位或、按位异或。最高位也参与取反。             如:int a = 13;//00000000000000000000000000001101                    int b = ~a; //11111111111111111111111111110010 -> b==-14;         ‘sizeof’是单目操作符,可求内存大小。             如:    int a =13;                 int b = sizeof(a);//结果为4,是一个int类型变量所占字节个数,也可写为int b = sizeof a; 不需要加括号                 int arr[10]={0};                 int c = sizeof(arr);//结果为40,是十个int类型变量所占字节个数                 int g = sizeof(int [10]);//结果为40,数组的类型实际上是去掉数组名(arr)之后留下的(int [10])。             如:             #include <stdio.h>             int main(){                 short s = 5;                 int a = 10;                 printf("%dn",sizeof(s = a 2));//输出为2,short占2字节,等价于printf("%dn", sizeof(s));。                 printf("%dn",s);//输出为5,上面表达式没有计算             return 0;             };         ‘ ’             int a = 13;              a;//前置 ,先 在使用             a ;//后置 ,先使用,在         ‘&’取地址操作符,单目操作符,与按位与操作符区分         ‘*’解引用操作符或间接引用操作符            如:#include <stdio.h>             int main(){                 int a =13;                 int *p = NULL;//定义int类型的指针变量,此时 * 是定义                 p = &a;//整型指针变量p中存放整型变量a的地址                 printf("%dn",*p);//此句输出为13,*p与a等价。此时 * 是解引用                 int a =1;                 char b=1;                 double c=1;                 float d=1;                 int *pa =&a;                 char *pb =&b;                 double *pc=&c;                 float *pd=&d;                 printf("%dn",sizeof(pa));                 printf("%dn",sizeof(pb));                 printf("%dn",sizeof(pc));                 printf("%dn",sizeof(pd));//输出相同,为4或8(与具体系统有关),求的是指针变量的大小,不论是那种类型的指针变量,储存的地址形式都相同,内存的地址(指针常量)形式是确定的             }         ‘(类型名)’,            如:#include <stdio.h>             int main(){                 int a = 3.14;//浮点型转换为int型会损失精度,产生警告。                 int b =(int)3.14;//强制类型转换,没有警告。             return 0;             }     6,关系操作符         =(赋值)    ==(相等)    <、>、<=、>=、!=(不等于)         字符串比较不能用==,要用字符串函数     7,逻辑操作符         &&(逻辑与)        ||(逻辑或)         首先和按位与(&)、按位或(|)区分开。         逻辑与:全真为1,其它为0。         逻辑或:全0为0,其它为1。         短路现象:对于逻辑与:         如:    #include <stdio.h>             int main(){                 int a=0,b=3,c=2,d=4;                 if(a && b && c && d)//先看a && b,a==0,则最终表达式结果一定为0,后面表达式不再计算                     printf("111n");                 else{                     printf("000n");//最后输出为000                 }             }         对于逻辑或:         如:    #include <stdio.h>             int main(){                 int a=5,b=3,c=2,d=4;                 if(a || b || c || d)//先看a || b,a == 5,则最终表达式结果一定为1,即为真,后面表达式不再计算,输出为111。                     printf("111n");                 else{                     printf("000n");                 }             }     8,条件操作符         ? : (三目操作符)         如:#include <stdio.h>             int main(){                 int a =2;                 int b = 4;                 printf("%dn", a>b?a:b);//如果a>b表达式成立,则表达式结果为a,否则为b,输出为4。             return 0;             }     9,逗号表达式         逗号表达式,从左向右依次计算,整个表达式的值是最后一个子表达式的值。         #include <stdio.h>             int main(){                 int a =2;                 int b = 4;                 printf("%dn", (a=a 3,b=b-2));//表达式a = a 3计算,但整个表达式(a=a 3,b=b-2)的值是表达式(b=b-2)的值,结果为2                     b = 4;                 printf("%dn", b=b-2);//结果为2             }     10,下标引用、函数调用和结构成员访问         [ ]下标引用操作符(运算符)             操作数:一个数组名 索引值,类比二元操作符,1 2。             如:    #include <stdio.h>                 int main(){                     int a[10];//创建数组                     a[0] = 10;//使用下标引用操作符为数组第一个单元赋值                 }         ( )函数调用操作符,接受一个或多个操作数,第一个操作数是函数名,剩余的操作数是函数的参数。         如:    #include <stdio.h>             int max(int a, int b){//函数定义                 return a > b ? a : b;             }             int main(){                 int a = 3;                 int b = 4;                 max(a, b);//函数调用,输出二者中较大的那个数。                 printf("%dn",t);                 return 0;             }         结构成员访问操作符:对于非指针变量使用圆点操作符,指针变量还可以使用箭头操作符         如:                 #include <stdio.h>             struct student{                 char name[20];                 int age;                 double mathscore;             };             int main(){                 struct student a = { "weihe", 20, 90};                 printf("%sn",a.name);//使用圆点操作符访问结构体成员name数组                 struct student *p = NULL;                 p = &a;                 printf("%dn", (*p).age);//使用指针解引用访问结构体成员age                 printf("%dn", p->age);//使用箭头操作符访问结构体成员age             return 0;             }     11,表达式求值         求值顺序由操作符的优先级和结合性决定。有些表达式的操作数再求值的时候可能要转换为其他类型。     12,隐式类型转换         C的整型算术运算是以缺省(sheng)整形类型的精度来进行的。         为了达到这个缺省(sheng)整形类型的精度,表达式中的字符和短整型操作数(2字节)在使用之前被转换为普通整型(int或unsigned int),这种转换称为整形提升。         整形提升的意义:             表达式的整型运算在CPU相应的运算器件内执行,CPU内整型运算器的操作数的字节长度一般是int的字节长度,同时也是CPU的通用寄存器的长度。             即使是两个字符型变量相加,CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。             通用CPU难以直接实现两个8bit字节的直接相加运算(虽然机器指令中可能有这种字节相加指令)。         整形提升过程:             按照变量数据类型的符号位提升。             正数:    char a = 1;//00000001(补码) ->(整形提升) 00000000000000000000000000000001             负数:    char b = -1//11111111 (补码)-> (整形提升)11111111111111111111111111111111             如:    #include <stdio.h>                 int main(){                 char a = 3;                         char b = 127;                 char c = a b;//    a: 00000011 -> 00000000000000000000000000000011                            //    b: 01111111 -> 00000000000000000000000001111111                             c:              00000000000000000000000010000010 ->(截断) 10000010                 printf("%dn", c);/    c: 10000010 -> 11111111111111111111111110000010(反码)->(求原码)10000000000000000000000001111110 即为-126                 return 0;//以int型输出是也会发生整型提升,对于unsigned char,整型提升时高位均补0                 }                 #include <stdio.h>                 int main(){                     char c =0;//sizeof返回类型为size _t,是unsigned int,打印时要用格式符%u                 printf("%un",sizeof(c));结果为1                 printf("%un",sizeof(-c));结果为4,sizeof运算符括号里的表达式(-c)虽然不参与运算,但有类型属性,为整形提升后的int                 printf("%un",sizeof( c));结果为4                 printf("%un",sizeof(!c));结果为4                 return 0;                 } **************************************************************************************************************************************************************************************************************** 字符串 相关函数 头文件#include <string.h> 求长度     char s[10] = "hello world";     strlen(s),返回字符的个数     sizeof(s),返回字符串大小,包括'' 复制函数     char s1[10];//字符数组     char s2[10] = "hello";     strcpy(s1,s2),把字符串s2整体复制到s1中,但s1中要有足够的内存     strncpy(s1,s2,n),对s2最多n个字符成立 比较函数     strcmp(s1,s2),相等返回0,s1>s2返回正整数,s1<s2返回负整数     strncmp(s1,s2,n),字符串s1中最多n个字符与字符串s2比较,同上 连接函数     char s1[10];//字符数组     char s2[10] = "hello";     strcat(s1,s2),把s2中字符添加到s1中有效字符之后,s1要有足够的内存     strncat(s1,s2,n),对s2最多n个字符成立 逆置函数(倒序)     char s[10] = "hello";     strrev(s), 输出函数     sprintf(s,格式字符串,输出项列表),输出到字符串s中,不在屏幕上显示 输入函数     sscanf(s,格式字符串,输出项列表),从字符数组s中读取,而不是从键盘读取,

字符串数组与函数

**************************************************************************************************************************************************************************************************************** 数组     &arr//指数组的地址,(&arr 1)加了整个数组的长度     arr//指数组首元素的地址,(arr 1)加了一个数组元素的长度     arr[0]//指数组首元素的地址

二维数组的函数调用

void pow(int a[][10])//一个调用二维数组的函数 int arr[10][10]; pow(arr);//只写数组名

**************************************************************************************************************************************************************************************************************** 刷新函数 memset(数组名,0,sieof(数组名));

****************************************************************************************************************************************************************************************************************

指针(间接引用)(地址) 指针常量:计算机内存中的事先实现好的编号即地址,不可改变。 指针变量:指针类型,储存地址的变量,可以改变,指针变量自身也占有一定内存。不与指针常量混淆时简称为指针。

指针的大小:     指针在32位系统中占4字节,在64位系统中占8字节,与地址占内存的大小有关。     而在同一系统中地址由多个相同的bit构成 变量(int,float,double,char等)占用内存中的字节,首个字节的地址是该变量的地址

初始化     声明指针时必须对其进行初始化(为0,NULL,已定义变量地址)。     如:     void *p = NULL;//可以指向任何类型的指针,未知指向变量的数据类型,不能进行间接寻址运算     int *p = NULL;//不指向任何对象     int *p = 0;     int a = 1;     char *p = &a;//指向变量a的地址

间接寻址运算(运算符*,&)     *:解引用操作符,访问指针p所指的变量a。     &:取(返回)变量a的地址。     int a = 1;     int *p = &a;//此时*为指针声明符     有*p与a等价,p与&a等价

指针的算术运算 加法运算:(得到另一个地址)     int a[4]={4,5,3,1};     int *p = a;//或p = &a[0];     有(p 1) == &a[1];.......(p i) == &a[i]; 减法运算: (得到地址之间的距离,用元素的个数表示)     int a[4]={4,5,3,1};     int *p = &a[0];     int *q = &a[3];     则p - q == 3.//结果可以为负整数,即地址相减后除以类型所占的字节     地址之间的距离==sizeof(int)*3. 指针比较:(指向相同数组时才有意义)     int a[4] = {5, 4, 3, 2, 1};     int *p = &a[0];     int *q = &a[4];     for(; p<=q; p ){         printf("%dn", *p);//循环输出数组各元素     } 指针与数组:     int a[4];     由数组名a可知数组a的内存大小并得到数组a的首元素的第一个字节的地址(即数组名a是指向a[0]的一个指针常量,,指针常量,不可更改)。     int *p = a;     int i;     一个指针p与数组a关联之后数组a中的元素表示方法可以为:(以指针p指向数组首元素为例)         数组下标表示: a[i];         数组偏移量表示: *(a i);//偏移量,即i         指针下标表示: p[i];         指针偏移量表示: *(p i);     数组作为函数的参数:          形参数组(定义的函数中,非main函数)本质上是一个相应类型的指针变量,不是指针常量.         例如             int a[4];//实参             函数头void sum(int a[], int n)//形参a[]获得了数组的首元素的指针(地址),可以访问和修改数组a[4]中的所有元素             与void sum(int *a, int n)等价 指针与const限定符: (减小函数的在主函数的权限等)     const修饰后,为常量,不可修改。     定义函数时     声明为从const的指针要在声明时就初始化,若为定义的函数参数则由相应主函数的实参初始化。     可变指针指向可变(可修改的)数据:         void sum(char *p,int n)//权限最大,无const约束指针或类型数据(char).     可变指针指向常量(不可修改的)数据:         void sum(const char * p, int n)//应从右往左理解const char * p,p是一个指针,指向字符常量,可进行指针运算。     常量指针指向可变数据:          void sum (char const * p, int n)//从右往左char const * p,p是一个指针常量,指向字符型数据,可改变指针指向数据的值。     常量指针指向常量数据:          void sum(const char const * p,int n)//权限最小,指针(地址)的值不能改变,其指向的数据也不能改变

指针数组:是一个数组,数组元素时一个个指针变量     char* arr[4];//一级字符指针数组     char** arr[4];//二级字符指针数组     如:    #include <stdio.h>         int main() {             int a = 10;             int b = 20;             int c = 30;             int *arr[3] = { &a,&b,&c };//注意[ ]优先级比*高             int i = 0;             for(i=0; i<3; i ){                 printf("%dn", *arr[i]);             }             return 0;             }

        #include <stdio.h>         int main() {         int a[5] = { 1,2,3,4,5 };         int b[] = { 1,3,5,7,89 };         int c[] = { 2,3,4,5,6 };         int* arr[3] = { a,b,c };//先是一个数组,数组中的元素为int*,即整型指针。         int i = 0;         for (i = 0; i < 3; i ) {             int j = 0;             for (j = 0; j < 5; j ) {                 //printf("%d ", *(arr[i] j));//arr[i]是指针数组第一个元素储存的地址即a数组首元素的地址,(arr[i] j)是a数组中第j个元素的地址                 printf("%d ", arr[i][j]);//等价于二维数组             }             printf("n");         }         return 0;         } 数组指针: 如:    #include <stdio.h>     int main() {         int a = 10;         int* pa = &a;//整型指针         char ch = 'w';         char* pch = &ch;//字符指针         int arr[10] = { 0 };         int (*parr)[10] = &arr;//取出的是数组arr的地址,不是数组首元素的地址。先是是一个指针,再指向具有10个元素的数组,数组中的元素为int。         double* b[5];//指针数组         double* (*p)[5] = &b;//数组指针,即指向指针数组的指针。先是一个指针,再指向具有5个元素的数组,数组中的元素为double*。         return 0;     }     (&数组名)与数组名(首元素的地址)区别:         #include <stdio.h>         int main() {             int arr[10] = { 0 };             printf("%pn", arr);             printf("%pn", &arr);//输出arr与&arr地址的值相同,意义不同(类型不同)。             //             int* pa = arr;//类型为int             int(*pb)[10] = &arr;//类型为int [10]或int []。             printf("%pn", pa);//指针加一跳过指向对象的大小。             printf("%pn", pa 1);//指针加一跳过一个int大小,为4字节。             printf("%pn", pb);             printf("%pn", pb 1);//指针加一跳过一个int [10]大小,为40字节。             return 0;         }         数组名是首元素的地址,但有两个例外:             1:sizeof(数组名)    -    数组名表示整个数组,计算的是整个数组大小,单位是字节。             2:&数组名 - 数组名表示整个数组,取出的是整个数组的地址。 数组指针的使用:数组指针中存放数组的地址    如:用于一维数组,一般不使用数组指针,使用一级指针就可以了,使用数组指针反而麻烦。     #include <stdio.h>     int main() {         int arr[5] = { 1,2,3,4,5 };         int(*pa)[5] = &arr;//指向含有五个整型元素数组的指针,储存的是整个数组的地址         for (int i = 0; i < 5; i ) {             printf("%d " ,*((*pa) i));             //首先*pa是数组arr,而数组arr是数组首元素的地址,故*pa是数组首元素的地址             //接着*pa j是数组中下标为j的元素的地址,*((*pa) j)是下标为j的元素         }         return 0;     }     用于二维数组     #include <stdio.h>     //void print(int arr[3][4], int m, int n) {//常规写法     //    for (int i = 0; i < m; i ) {     //        for (int j = 0; j < n; j ) {     //            printf("%d ", arr[i][j]);     //        }     //        printf("n");     //    }     void print2(int(*pa)[4],int m, int n) {//定义了指向一维数组的指针,     for (int i = 0; i < m; i ) {         for (int j = 0; j < n; j ) {             printf("%d ", *(*(pa i) j));             //*(pa i)首先是二维数组第i-1行的地址,*(pa i) j是第i-1行的第j-1个元素的地址             //*(*(pa i) j)是第i-1行的第j-1个元素         }         printf("n");      }     }     int main() {         int arr[3][4] = { {1,2,3,0},{4,5,6,0},{7,8,9,0} };         //print1(arr, 3, 4);         print2(arr, 3, 4);         return 0;     }     int arr[5];//一维整型数组     int a[3][4];//二维整型数组     int* parr1[10];//指针数组,该指针指向存放10个整型指针的数组     int(*parr2)[10];//数组指针,指向存放10个整型元素的数组     int(*parr3[10])[5];//存放10个数组指针的数组,每个数组指针指向存放5个整型变量的数组 函数参数传递方式:按值传递和按引用传递 C中均为按值传递:被调函数的形参为主调函数的副本(拷贝),一般不影响主调函数变量的值。当传入指针时(类似按引用传递),主调函数 向被调函数传入了地址,可以改变主调函数中的相应变量的值。 如:void swap(int *p, int *q)//函数定义       int a=5, b=6;       swap(&a, &b);//函数调用

    数组参数与指针参数         一维数组传参:         #include <stdio.h>         void test1(int arr[10]) {//1一维数组接收,可以         }         void test1(int arr[]) {//1一维数组接收,可以         }         void test1(int* arr) {//1一级指针接收可以         }         void test2(int* pa[10]) {//2一维指针数组接收,可以         }         void test2(int* pa[]) {//2一维指针数组接收,可以         }         void test2(int** pa) {//2可以         }         int main() {             int arr1[10] = {0};             int* arr2[20] = {0};             test1(arr1);//传的是首元素的地址,此指第一个元素int的地址             test2(arr2);//此指第一个元素int*的地址,即是二级指针             return 0;         }         二维数组传参:         #include <stdio.h>         void test3(int arr[3][4]) {//3二维数组接收,可以         }         void test3(int arr[][4]) {//3二维数组接收,可以         }         void test3(int arr[][]) {//3二维数组接收,列元素必须写,不可以         }         void test3(int* arr) {//一级指针接收,类型不匹配,不可以         }         void test3(int* arr[4]) {//一维指针数组接收,类型不匹配,不可以         }         void test3(int(*pa)[4]) {//一个数组指针接收,可以         }         void test3(int** arr) {//二级指针接收,与一维数组的地址不匹配,不可以         }         int main() {             int arr[3][4] = { 0 };             test3(arr);//传的是二维数组的首元素的地址,此指第一个元素一维数组的地址             return 0;         }

函数指针 指针函数 ****************************************************************************************************************************************************************************************************************

结构体(构造类型)     struct关键字用于结构体定义。     结构是同一名字下的一组相关变量的集合。可以包含不同的数据类型。(当然包括结构类型)     结构体定义(声明)形式:         struct 结构标识符{                如:struct student{             数据类型 成员1;                       char name[20];             数据类型 成员2;                int age;             ......                        double mathscore;         };                                        };         定义之后,struct student便成为了自己定义的新的一种数据类型,与char、int、float、double使用基本相同。编译器不对数据类型分配内存,         当定义了相应类型的变量时编译器会为该类型的变量分配内存。自定义结构类型也是这样。         typedef关键字:为任意数据类型起一个别名,便于使用和理解。             关于结构体使用:             如:typedef struct student STU,即STU成为struct student 数据类型的另一个名字。             或如:typedef struct student{             char name[20];             int age;             double mathscore;             }STU;此STU不是struct student类型的结构变量,而是struct student 数据类型的另一个名字。     结构变量的声明(定义):         a.先声明结构类型,在定义结构变量。             如:struct student a;         b.定义结构类型的同时,定义结构变量。(此时结构标识符可以省略,且只能在此处定义结构变量,少使用)             如:struct student{             char name[20];             int age;             double mathscore;             }a;         结构变量的内存用sizeof运算符计算出,一般大于结构成员所占字节的和。         结构类型可以作为另一个结构的成员:             struct date{                 int year;                 int month;                 int day;             }             struct student{             char name[20];             int age;             double mathscore;             struct date born;             };     结构变量的初始化:         与普通变量一样,不同成员用逗号隔开,字符串用双引号,单个字符用单引号。         如:struct student a = { "weihe", 20, 90};     结构成员的访问方法:C规定结构变量不能整体进行输入输出比较等操作,只能对具体的成员进行输入输出比较等操作。                    相同类型的结构变量可以直接进行赋值操作,等价于结构变量成员依次进行赋值操作。         使用成员选择运算符(圆点运算符):             struct date{                 int year;                 int month;                 int day;             }             struct student{             char name[20];             int age;             double mathscore;             struct date born;             };             struct student a = { "weihe", 20, 90, {2000,4,24}};             a.name == "weihe";//成员引用             a.age == 20;             a.date.year == 2000;//嵌套结构体的级联引用     结构数组:数组中元素均为结构类型。(定义和初始化)与普通数组相同。         结构指针:指向结构的指针。         成员访问运算符对于指针:圆点运算符和箭头运算符         如:struct student{             char name[20];             int age;             double mathscore;             };             struct student a[20]={ {"weihe",20,90},                              {"齐天大圣",1000,95}};//初始化,未初始化的赋值为0。             struct student b;             a[4].age = 20;//对结构数组第5个元素中的一个变量赋值(引用)。             struct student *p = NULL;//定义结构指针。             p = &b;//得到结构类型b的地址用用取地址运算符。             p = a;//数组名就是数组的地址故不需要取地址运算符,等价于 p = &a[0];.             (*p).mathscore = 89;//同时使用解引用运算符与圆点运算符,等价于a[0].mathscore = 89;             *(p 1).mathscore = 79;//同时使用解引用运算符与圆点运算符,等价于a[1].mathscore = 79;,指针 1则跳过相应类型的一个元素,再此为一个结构元素。             p->mathscore = 99;//箭头运算符,等价于 a[0].mathscore = 99;             当p定义为指向结构类型的指针时就只能指向定义的类型了,不能指向结构类型中的成员,             但可以通过成员访问运算符(圆点或箭头)访问成员。对于结构指针有两种(圆点和箭头),对于结构名只有圆点运算符。     结构与函数:             struct student{             char name[20];             int age;             double mathscore;             };             void max(int n, struct student a);//结构作为函数的参数,是按值传递,在max函数新建一个结构体(形参),不影响main函数里传参的的结构体(实参)。不常用。             void max(int n,struct student *a);//结构指针作函数参数,传入的是main函数里实参(再此为结构体)的地址,影响实参数值。常用。             void max(int n, struct student a[]);//结构数组作函数参数,与结构指针作用相同,传入的是数组的首元素字节的首地址。             struct student max(int n);//结构作函数返回值,max函数最终返回一个结构(其中一般包含多个结构成员,可一次性返回),类似返回其他类型数据。     联合:C语言中多个不同变量共享同一内存区的功能。         关键字:union         定义:(类比结构)             union student {//该联合的三个成员共享一个声明联合的内存单元,须有,同一时间内有且只有一个成员有意义。不能为联合的所有成员都初始化,只能用相应类型的常量为第一个成员初始化。                 int n;//4字节                 double a;//8字节                 char ch;//1字节             }u;//定义的同时可以声明一个联合u。             union student u1;//也可在定义之后再声明一个联合u1。             在为声明的一个联合u分配内存大小时,编译器按成员中最长的类型double分配储存单元。         联合指针:             union student {                 int n;//4字节                 double a;//8字节                 char ch;//1字节             }u,u1;             union student *p = NULL;             p = &u;             u1.n = p->n;//p->n等价于*p.n。 类比结构。圆点运算符与箭头运算符。         联合与结构:结构可以是联合的成员,联合也可以是结构的成员,能互相嵌套。             如:    struct yes{//有对象问名字与年龄                     name[20];                     int age;                 };                 struct no {//无对象问希望什么时候找与喜欢类型                     int hopeseektime;                     char liketype[50];                 };                 union otherhalf{定义一个联合是否有对象,成员为两个结构分别表示有或没有                     struct yes a;                     struct no b;                 };                 struct student {//定义学生的结构,包括姓名、年龄与有无对象。                     char name[20];                     int age;                     union otherhalf;                 };     枚举:一种值由程序员列出的类型,而且程序员必须为每个值命名(枚举常量)。         关键字:enum(类比结构)         在枚举类型声明语句中,花括号内的标识符都是整型常量,称为枚举常量。一般第一个枚举常量是0,依次增加1。         如:    enum weekday{                 Sun;//0                 Mon;//1                 Tue;                 Wed;                 Thu;                 Fri;                 Sat;//6......             }someday0;//定义枚举类型同时声明枚举变量someday0。             enum weekday someday;//先定义枚举类型,再声明枚举变量someday             someday = Mon;//枚举变量someday被定义的枚举常量赋值。 time()和localtime() ****************************************************************************************************************************************************************************************************************

int a[10];//数组定义 void array(int a[]) 等价于void array(int *a)//函数定义

动态内存分配     void *malloc(unsigned size)//函数原型

    int *p = NULL;     p = (int*)malloc(sizeof(int));//使用,按字节分配内存,用于数组个数不定时

动态内存分配之后的释放函数     void free(void *p)//函数原型

    int *p = NULL;     p = (int*)malloc(sizeof(int));     free(p);//使用

****************************************************************************************************************************************************************************************************************

void *calloc(unsigned n,unsigned size)//函数原型 为n个数组分配size字节大小的内存,并均初始化为0

****************************************************************************************************************************************************************************************************************

void realloc(void* p,unsigned size);//函数原型 重新为指针p所指的内存块分配适合的内存 若指针p指向NULL,则作用与malloc()相同

**************************************************************************************************************************************************************************************************************** EOF(End  OF File) 表示文件结束符,用于while循环中,如while(scanf("%d",&n) != EOF),当在控制台输入ctrl z时结束程序进行

****************************************************************************************************************************************************************************************************************

数据的存储     程序的版本:Debug版本和Release版本         Debug版本即调试版本,包含调试信息,利于去调试程序,无优化。         Release版本即发布版本,对程序进行了多种优化如代码大小和运行速度,便于使用,无调试信息。     数据类型:         类型的意义:确定开辟空间的大小与看待内存空间的视角。         基本类型:         char            字符型//char C语言没有规定是signed char 还是unsigned char 类型,由具体的编译器决定,多数编译器默认为 signed char类型         short            短整型         int            整型//int C语言规定为signed int类型         long            长整型         long long        更长的整型         float            单精度浮点型         double        双精度浮点型         整形家族:             char                 unsigned char    0~255(2^8-1)                 signed char        -128~127             short                 unsigned short int                         signed short int             int                 unsigned int    0~4,294,967,295(2^32-1)                 signed int(默认)    -2,147,483,648~2,147,483,647             long                 unsigned long int                 signed long int         浮点家族:             float             double         构造类型(自定义类型):             数组类型        a[]             结构体类型        struct             枚举类型        enum             联合类型        union         指针类型:             int *p             float *p             double *p             char *p             void *p         空类型:函数返回,函数参数,指针     数据的截断与整型提升(指不同的数据类型之间    ):         如:int a = 10;               char ch = 10;//10的二进制:00000000 00000000 00000000 00001010 最高位为0,原码反码补码相同         10为整型,占内存的四个字节,由字符类型(一个字节)ch储存时发生截断,只保留最后一个字节(00001010)储存。         ch转化为整型时从前补24个最高位即0,得补码00000000 00000000 00000000 00001010,最高位为0原码反码补码相同,即得原码00000000 00000000 00000000 00001010即10。     堆栈     局部变量储存在栈区,栈区地址从下到上逐渐增大,即上为高地址,下为低地址。栈区先使用高地址,在使用低地址     整型在内存中的储存:         已知数据在内存中以二进制储存,         有符号数的二进制表示方式有三种:原码,反码,补码。,每一种均分为符号位和数值位。         对于正整数:原码,反码,补码三者相同。         对于负整数:             数据储存时的二进制序列最高位为1,而正整数二进制序列最高位为0。             对于signed前缀类型,最高位为符号位无数值表示,而unsigned前缀类型最高位为数值表示。             原码:由数据的数值直接写出的二进制序列,补码取反再加一又得到原码或补码减去1再取反得到原码。             反码:原码符号位(即1)不变,其它位按位取反。             补码:先取反码再 1得到。         如    int a = -10;             内存中存放(16进制): F6 FF FF FF(此储存为小端字节序)             原码:10000000 00000000 00000000 00001010(四个字节)             反码:11111111 11111111 11111111 11110101             补码:11111111 11111111 11111111 11110110             16进制:FF FF FF F6             int b = 10             内存中存放(16进制):0a 00 00 00(此储存为小端字节序)             原码:00000000 00000000 00000000 00001010             反码:00000000 00000000 00000000 00001010             补码:00000000 00000000 00000000 00001010             16进制:00 00 00 0a         整型在内存中以补码的形式储存,表示和计算,原因是可以将符号位和数值域统一处理,加法和减法可以统一处理(cpu中只有加法器),原码与补码相互转换运算过程相同,不需要额外硬件电路。             数据数值的二进制的储存形式:大端字节序和小端字节序             如    int a = 0x11223344;//(16进制表示)其中11为高位,44为低位,类比十进制数字             大端字节序:把数据的低位字节序的内容存放在高地址处,高位字节序的内容存放在低地址处。                 低地址    11 22 33 44        高地址             小端字节序:把数据的地位字节序的内容存放在低地址处,高位字节序的内容存放在高地址处。                 低地址    44 33 22 11        高地址             想知道自己计算机数据的储存形式,可以采用如下代码简单判断:                 用字符指针(只看一个字节)指向整型a的第一个字节,若为小端则为(16进制)01 00 00 00,若为大端则为 00 00 00 01。                 #include <stdio.h>

                int main(){                 int a=1;                 char *p=(char*)&a;                 if(*p==1)                     printf("小端n");                 else                     printf("大端n");                 return 0;                 }          浮点型在内存中的存储:float(四字节),double(八字节),long double             浮点数在内存中以补码的形式储存。             C语言用二进制储存浮点数的标准:IEEE 754。                 任意一个二进制浮点数V均可以化为一个形式:                 (-1)^S*M*2^E    其中 ^ 表示指数运算。                 S表示符号位,S为0时V为正数,S为1时V为负数。                 M表示有效数字,范围大于等于1,小于2。                 2^E表示指数位。                         例如:9.0(十进制)->1001.0(二进制)->1.001*2^3->0 10000010 00100000000000000000000                             5.5(十进制)->101.1(二进制)->1.011*2^2->  0 10000001 01100000000000000000000                 对于double类型:0 00000000000 0000000000000000000000000000000000000000000000000000 首位为符号位,接下来11位存放指数,余下52位存放小数部分。                 对于float而言共四个字节32位:0 00000000 00000000000000000000000 首位1或0表示符号位,接着8位存放E即指数(二进制形式),余下的23位储存M(又称小数部分),M不够就补0.                     对于1.XXXXXXXXX的二进制有效数字,实际储存时舍去1和小数点,只保留小数点后的0和1,等到取出已经储存好的浮点数时,M部分取出时在开头添加上1和小数点。                     对于E指数,看做无符号整型(unsigned int),float中占8位,范围为0~255,考虑到指数E可能为负数,实际储存时要存入正数就需要修正,为指数E加上一个中间值,                     127(float)或1023(double)。实际储存的是(E 127)的二进制形式,double占11位范围为0~2047,实际储存的是(E 1023)的二进制形式。                 取出时:                     E全为0时:                         这时浮点数的指数E等于(1-127)或(1-1023)作为真实值,有效数字M不在加上第一位的1,而是还原为0.xxxxxx的小数,以此表示正负0或接近于0很小的数。                         00000000八个位为0 ->实际的E的值为0 - 127 == -127,2^(-127)是很小的一个数,正负接近于0。                     E全为1时:                         这时,如果有效数字M全为0(还原之后为1.000.....),表示无穷大,符号确定正负。                         11111111八个位为1 -> 实际的值为255 - 127 == 128,2^(128)是很大的数字 ,表示无穷大。                     E不为全0或全1时:(最多)                          指数E二进制的计算值减去127(或1023)得到指数位真实值,有效数字M前加上第一位的1,                         5.5(十进制)->101.1(二进制)->1.011*2^2->  0 10000001 01100000000000000000000 ***************************************************************************************************************************************************************************************************************

0 人点赞