怎样建设尧都水果网站,区块链企业解决方案,模板之家官网,永久免费建站程序自定义函数 #xff08;1#xff09;在函数使用之前定义函数 #xff08;2#xff09;先声明这个函数#xff0c;然后使用#xff0c;使用的代码后面定义这个函数 include stdio.h void syahello(){ println(helloo); }int main(){ sayhello(); // 调…自定义函数 1在函数使用之前定义函数 2先声明这个函数然后使用使用的代码后面定义这个函数 include stdio.h void syahello(){ println(helloo); }int main(){ sayhello(); // 调用的函数要提前写出来如果要写在后面需要先在前面声明 } void syahello(); //提前声明没有实现 int main(){ sayhello(); // 调用的函数要提前写出来如果要写在后面需要先在前面声明 } void syahello(){ println(helloo); } mytest1(); //如果函数没有明确标明函数的返回值类型则默认为返回int不要这样写 print(%d\n,mytest1()); 2.形参和实参是值传递v是单向传递只能由实参传递给形参不能由形参传递给实参 入股哦函数的参数是数组则可以通过形参修改实参的值 void testarr(char s[]){ s[0] a; s[1]b; } int main(){ char chs[100] hello world testarr(chs); printf(%d,chs); // 数组变为abllo world } void mergearr(char arr1[],char arr2[]){ int len1 0; while(arr1[len1]); len1--; // 记录数组一的长度 int len20;
while(arrp[len21]);
len2--;int i;
for(i0;ilen2;i){arr1[len1i] arr2[i];
} } int main(){ char arr1[100]asdad; char arr2[100]1111; mergearr(arr1,arr2); printf(%s\n,arr1); // 发现数组2已经合并了 printf(%s\n,arr2); } 二. 多文件编译 stdio.h : 尖括号表示文件在系统路径中 abc/myhead.h表示abc目录下的myhead.h ------------------------- myhead.h: #define MAX 300 // #define就是简单的字符串替换main.c: include stdio.h include abc/myhead.h int main(){ int c MAX; printf(%d,c) } 三. 指针 计算机内存的最小单位使BYTE 每个BYTE的内存都有一个唯一的内存编号这个编号就是内存地址 编号在32为系统下是一个32位的整数编号在64位系统下是一个64位的整数 用指针型变量来表示这个内存地址号。指针变量指向的内容。指针型变量不能向int变量一样显示的声明出来只能用变量名来声明一个int值则该变量是指针型变量*变量名是一个int值得到变量对应的指针变量内存地址void main{ int a3; int p; // p是int型变量p是指针型变量 p a; // 指针型变量就是内存号所以符号取得a的内存号 int b p; printf(%d,b);p 100; printf(%d,a) // 通过内存号修改变量值 char chs[10];
printf(%u,%u,%u,%u,chs,chs[0],chs[1],chs[2]) // %uunsigned无符号整形数组首地址第一个元素的地址第二个元素的地址int ints[10];
printf(%u,%u,%u,%u,ints,ints[0],ints[1],ints[2]) // %uunsigned无符号整形数组首地址第一个元素 } 无类型指针 void *p说明p只是一个指针比那辆而不去指向任何一个变量 ----------------------------------- include stdio.h void main(){ int a 100; int p; // int p是声明写法整体代表一个地址号这个地址号上存着整数。单独一个p定义写法也是内存号 int q; p a; //int p 1; // p指向的地址号是1声明定义写在了一起 printf(%u,p); // 3852910012 printf(%u,*p); // 100 printf(%d\n,sizeof(p)); //8指针在64位系统下就是一个64位的整数所以占8字节。无论指针指向什么类型的数据64位下都占8字节 printf(%d\n,sizeof(a)); //4int型占4字节 int p; //声明指针没有指向就是野指针。野指针使导致程序崩溃的主要原因p 1; // 为地址上赋值1会出现错误 [1] 6285 segmentation fault (core dumped) a.out int *p NULL; // 空指针使合法的野指针是非法的} /** int p 与p一致/ include stdio.h void main(){ int a 100; int p a; int q; q a; printf(p:%u,q:%u\n,p,q); // p:2373644580,q:2373644580 printf(p:%d,q:%d,p,q);// p:100,q:100 } 指针的兼容性 include stdio.h void main(){ int a 0X1013; char b 13; int p; pa; printf(%x,p); // 1013 pb; // 10130d 用int指针指向char类型变量因为int指针指向了连续4字节的地址所以除了1013外后面还有3个字节的数据当做一体来指向 printf(%x,*p); int q; char buf[] {0x12,0x34,0x56,0x78,0x90,6,7,8,9,10}; q buf; printf(%x\n,q); //指针不兼容的情况 float i 3.14; int p i; printf(%d,p); // 此时并不能打印出3这就是指针类型不兼容 }指向常量的指针和指针常量 void main(){ int a 100; const int p a; // 指向常量的指针只能读内存但可以改变指向 printf(%d\n,p); // 100 int const q a; // 常量指针可以读写指向的内存但不能改变指向q 200; printf(%d\n,*q); //200 printf(%d\n,a); //200 }数组与指针 void printarr(char s[]){ int i; for(i0;i10;i){ printf(s[%d]\n, %d); } } void main(){ char buf[10] {1,2,3,4,5,6,7,8,9,0}; char p buf; char p1 buf[0]; char *p2 buf[1]; printf(%d\n, p); //1 printf(%d\n, p1); //1 printf(%d\n, *p2); //2 p2 ; // 指针是地址号p1 *p2 100; // 更改为100 printarr(buf); } ------------------------------------- ip地址在网络中不是以字符串传输字符串太长而是以DWORD传输(4字节)飙戏那位一个int数值 includestdio.h void change2char(int i){ unsigned char p i; printf(%d.%d.%d.%d,p,(p1),(p2),(p3)); } void main(){ int a 0; unsigned char p1 a; // 无符号使得最大值为255 *p1 192; /**(p1) 168;(p2) 0;(p3) 1;/ p1;p1 168; p1;p10; p1;p11; printf(ip:%d,ip); // a已经被改变为一个ip地址 change2char(a); } ------------------ int s2ip(char s[]){ int a 0; int b 0; int c 0; int d 0; sscanf(s,%d.%d.%d.%d,a,b,c,d); printf(a%d,b%d,c%d,d%d\n, a,b,c,d); int ip0; char p ip; p;p a; p;pb; p;pc; p; *pd; } void main(){ char s[] 192.168.0.1; printf(%d\n, s); }eg:用指针合并数组 void main(){ char s1[] hello; char s2[]world; char p1 s1; char p2 s2; while(p1){ //p1指向的元素为0时跳出循环 p1 ; } while(p2){p1 *p2; // 先指向后指针移位 } } 指针运算不是简单地数值加减法而是指针指向的数据类型在内存中所占字节数为倍数的运算 void main(){ int buf[10]; int *p buf; printf(%d\n, p); //-1670667696 p3;// 实际上内存地址好涨了12 printf(%d\n, p); p (int)p3; // 此时把内存地址号强制转为int型此后加3就是数值运算-1670667684 printf(%d\n, p); // -1670667681 char *p2 buf;
p2 4;
printf(%d\n, *p2); // 0short *pp1 buf[1];
short *pp2 buf[3];
printf(%d\n, pp2 - pp1); // buf3和buf1差8个字节但是一个short指针变量指向2个字节的连续块所以值位4 } 二维数组的指针 void main(){ int buf[2][3] arr {{1,2,3},{4,5,6}}; // int p[3] ; //定义一个指针数组 int (p)[3]; // 定义了一个指针指向int[3]这种数据类型也叫作指向二维数组的指针 printf(%d\n,sizeof(p)) ; //8 因为指针在64位系统都是占8位 printf(%d,%d\n,p,p1); //相差12字节 p buf; //p指向了二维数组的第一行
p; //p指向了二维数组的第二行// 指针遍历
int i,j;
for(i0;i2;i){for(j0;j3;j){//printf(%d\n, *(*(pi))); //打印结果111,444printf(%d\n, *(*(pi)j); // 遍历每个元素printf(%d\n, p[i][j]); // 每个元素,与上面相等}
} } 指针作为函数参数 void test(int n){ n; } void test2(int p){ (p); } void main(){ int i 100; test(i); //c语言是值传递所以普通函数参数的改变是不能传回给参数的但如果参数是地址改变地址上的值 printf(%d\n, i); test2(i);
printf(%d\n, i); } 一维数组作为参数的指针 void swap(int a,int b){ int tmp a;a b;b tmp; } // 当数组名作为参数传递时数组名解析为数组首地址指针所以多写为void setarray(int buf) void setarray(int buf[]){ printf(占%d位\n, sizeof(buf)); //864位系统指针占8字节 buf[0] 100; buf[1]200; int i; for(i0;i10;i){ printf(%d\n, buf[i]); } } void setarray(int buf,int n){ // n为数组的长度 buf[0] 100; buf[1]200; int i; for(i0;in;i){ printf(%d\n, buf[i]); } } void main(){ int a 10; int b 20; swap(a,b); printf(%d,%d\n, a,b); // 因为数组名是数组的首地址所以数组名作为行参传递的时候就相当于传递的指针
int buf[] {1,2,3,4,5,6,7,8,9,0};
printf(%d\n, sizeof(buf)); //40
setarray(buf,sizeof(buf)/sizeof(int)); // 数组长度写成sizeof(buf)/sizeof(type) } 二维数组的指针作为函数参数 void printarr2(const int (*p)[4],int m,int n){//mn分别是二维数组的第一个和第二个角标。通过const标识保护函数不会改变数组中的值 int i,j; for(i0;im;i){ for(j0;jn;j){ printf(p[%d][%d] %d\n, i,j,p[i][j]); } } } int main{ int buf[][4] {{1,2,3,4},{5,6,7,8}}; printarr2(buf,sizeof(buf)/sizeof(buf[0]),sizeof(buf[0])/sizeof(int)); return 1; } 33 min 18 s --------------计算二维数组每一列的平均值---------------- includestdio.h void main(){ int buf[2][4] {{1,2,3,4},{5,6,7,8}}; for(int i0;i4;i){ int sum 0; for (int j 0; j 2;j) { sum buf[j][i]; } printf(%d\n, sum); } } 函数指针 函数也有地址这个地址存放的是代码 int getmax(int x, int y){ // 也可以写为int getmax(int x, int y) 意思一样函数名同数组名一样都是即表示本身又表示指向自身开头的指针 return xy?x:y; } int getmin(int x, int y){ return xy?x:y; } int main(){ int (p)(int,int) ; //定义一个指针p指向函数该函数反获知是int2个输入参数是(int,int) int fun 0; scanf(%d,fun); if(fun1){ p getmax; //函数名就是指针 }else{ p getmin; //函数名就是指针 } int i p(2,4); // 通过函数指针调用函数 printf(%d\n, i); } 31min 函数指针是指向函数的指针变量 void p(int,char) // 定义一个函数函数名为p参数为int和char类型返回值为void类型 void (p)(int,char) // 定义一个指针该指针指向函数。返回值为void, 参数为int和char类型 ----------------------------------------------- 将一块内存初始化为0最常见的方法memset(buf,值size(buf))要设置的内存地址设置的值内存大小(单位字节) memcpy(buf2,buf1,sizeof(buf1))将buf1的内容全部拷贝到buf2 memmove (buf2,buf1,sizeof(buf1)); include string.h include stdio.h void main(){ int buf[10] {1}; memset (buf,0,sizeof(buf)); int buf2[] {1,2,3,4,5,6,7,8,9,0};
int buf3[];
memcpy(buf3,buf2,sizeof(buf2));
for (int i 0; i 10; i)
{printf(%d\n, buf2[i]);
} } 指针数组与多级指针 int main(){ int a[10]; //一个数组数组内有10个元素64为系统中指针站8字节64位 printf(%d,%d\n, sizeof(a),sizeof(a[0])); // 40,8 short b[10]; printf(%d,%d\n, sizeof(b),sizeof(b[0])); // 40,8 } int main(){ int a 10; int p a; int pp p; // pp指向p的地址pp 100; //修改a的值 如果p100则是把p这个地址号改为100 printf(a%d\n,a); int ppp pp; a ppp; println(%d,%d,ppp,pp); // 三级指针的内容二级指针的地址 } 指针完成字符串操作 int mian(){ char buf[100] hello world; char p buf; p 5;p c; printf(%s\n, buf); // hellocworld return 1; } 如果字符串中包含0字符则打印到此位置就结束了。泪库里面的函数都是有\0识别字符串结尾的 c语言主函数也是有输入参数的而且有2个第一个表示输入参数的个数第二个是一个指针数组每个指针指向char类型 输入参数个数永远大于1因为程序名本身作为一个输入参数 指针数组这个指针数组的长度是第一个参数每个元素指向一个输入参数 int main(int argc,char *args[]){ if(argc!4){ printf(请输入完整的数学表达式以空格分开 ); return 0; } int a atoi(args[1]);
int b atoi(args[3]);switch(args[2][0]){case :printf(%d\n, ab);break;case -:printf(%d\n, a-b);break;case *:printf(%d\n, a*b);break;case /:if(b){printf(%d\n, a/b);}break;
}
return 0; } 内存管理 作用域 1文件作用域全局变量定义在函数外面的变量 int a10; void main(){ int a 20; // 函数内部可以再次定义和全局变量同名的变量定以后a为20没有定义为10 printf(%d\n, a); } 2extern关键字 include c.h #在这个文件中定义了age10 extern int age ;// 该变量在其他文件中定义了连接时使用就可以了。这个另一个文件需要时.c文件不能是.h文件。gcc编译时后面加上两个文件名 setage(int n){ age n; } getage(){ printf(%d\n, age); } void main(){ setage(11); getage(); // 11 } 3auto自动变量不写auto就默认为auto变量 4register 变量建议变量放到空闲的寄存器中 寄存器变量不能取地址操作 5static 变量只初始化一次程序运行期间一直存在 。static只是增大了变量的存在时间却没增大变量的作用域 一旦全局变量被static修饰则这个变量的作用域被限制在该文件内部其他文件不能用extern使用 void mystatic(){ static int a 0; // 不加static循环打印每次打印都是0加上static每次打印1 printf(%d\n, a); a; } void main(){ for (int i 0; i 10; i) { mystatic(); } }c语言中函数都是全局的。 1如果函数前面加了static则函数被限制在文件内部使用 2函数前面加不加extern一样。而变量前面的extern是可以省略的比如int a; 如果其他文件中定义了int a10则此处的变量是声明如果其他文件中没有定义a则此处是定义 此处也是说明c语言并不严谨c语言内存管理 程序在内存中分为4个区域 1堆 2栈此部分的内存表现为先进后出。所有自动变量函数行参都有编译器自动放到栈中。当一个自动变量超出其作用域时自动从栈中弹出。先进入栈中的变量放到大内存号中 3静态区所有的全局变量以及程序中的静态变量都存储在静态区 4代码区程序在被操作系统加载到内存中时所有可执行代码加载到代码段这块内存不能再程序运行期间修改 int c 0; void main(){ int a1; int b2; static int d 3; printf(%d,%d,%d,%d,%d\n, a,b,c,d,main); // 1321929276,1321929272,6295612,6295604,4195632 } 上述程序的a和b在栈区所以地址号紧挨着1321929276,1321929272 发现a所在的内存号在高位。 c和d在静态区地址号紧挨着 main在代码段二进制文件读写 fscanf读文件时可以根据固定格式读取 fprintf写文件和printf一样可以定义输出格式只是输出到文件中include stdio.h include string.h include stdlib.h void main(){ FILE *p fopen(a.txt,r); while(!feof(p)){ int a,b; fscanf(p,%d %d ,a,b); //文本格式为a b ,从中截取a,b printf(%d,%d,a,b); } } void main(){ FILE *p fopen(a.txt,w); char buf[100] hello world fuck ; int a1,b2; fprintf(p,%s,%d,%d,buf,a,b); fclose(p); } fread与fwrite读写二进制文件 上面的函数只能操作字符文件,字符文件每次只能读一行 void main(){ FILE *p fopen(a.txt,rb); // 以二进制方式读取 char buf[100] {0}; fread(buf,sizeof(char),1,p); // 读取字节的缓冲区读取单位一次读取几个单位文件指针 printf(%s\n, buf); fclose(p); }指针数组与多级指针 int main(){ int a[10]; //一个数组数组内有10个元素64为系统中指针站8字节64位 printf(%d,%d\n, sizeof(a),sizeof(a[0])); // 40,8 short b[10]; printf(%d,%d\n, sizeof(b),sizeof(b[0])); // 40,8 } int main(){ int a 10; int p a; int pp p; // pp指向p的地址pp 100; //修改a的值 如果p100则是把p这个地址号改为100. pp就是地址号的内容相当于改变p的内容pp就是地址号中记录的地址号的内容 printf(a%d\n,a); int ppp pp; a ppp; println(%d,%d,**ppp,pp); // 三级指针的内容二级指针的地址 } 指针完成字符串操作 int mian(){ char buf[100] hello world; char p buf; p 5;p c; printf(%s\n, buf); // hellocworld return 1; } 如果字符串中包含0字符则打印到此位置就结束了。泪库里面的函数都是有\0识别字符串结尾的 c语言主函数也是有输入参数的而且有2个第一个表示输入参数的个数第二个是一个指针数组每个指针指向char类型 输入参数个数永远大于1因为程序名本身作为一个输入参数 指针数组这个指针数组的长度是第一个参数每个元素指向一个输入参数 int main(int argc,char *args[]){ if(argc!4){ printf(请输入完整的数学表达式以空格分开 ); return 0; } int a atoi(args[1]);
int b atoi(args[3]);switch(args[2][0]){case :printf(%d\n, ab);case -:printf(%d\n, a-b);case *:printf(%d\n, a*b);case /:if(b){printf(%d\n, a/b);}
}
return 0; } 栈不会很大栈空间是操作系统为每个程序固定分配的大小以k为单位。栈空间是操作系统为每个程序固定分配的大 每个线程都有自己的栈 int main(){ char array[102410241024] {0}; //定义一个超大的数组就会栈溢出 return 0; } 堆堆没有大小限制只是无力限制。但是堆内存不能由编译器自动释放 include stdlib.h int main(){ int p malloc(sizeof(int)10); // 在堆中申请了10个int的大小 char p2 malloc(sizeof(char)10); memset(p,0,sizeof(int)*10); // malloc申请的堆内存 在代码的操作上相当于数组
for(int i0;i10;i){ p[i] i; // 操纵数组
}free(p) ; // 释放通过malloc申请的堆内存
free(p2); } 不能将一个栈变量的地址作为函数的返回值e因为函数结束后栈变量被释放 eg: int *geta(){ int a 10; return a; }但是可以把堆变量的地址作为函数返回值返回 int geta(){ int p malloc(sizeof(int)); return p; }int main(){ int *p geta(); malloc(p); } 一个经典的错误模型 void getheap(int p){ p malloc(sizeof(int)10); } void main(){ int *p NULL; getheap(p); // 此处是错误的因为函数的参数是值传递虽然语义是getheap(p),但是mallo的内存地址只是付给了函数的形参函数退出后形参的值并不能传递给实参(指针的值也一样不能传递)导致p还是空指针下面的p[0]1发生空指针异常 p[0] 1; printf(%d\n, p[0]); free(p); }经典的正确模型二级指针作为形参对上面错误模型的改写 void getheap(int **p){p malloc(sizeof(int)10); // 所致地址号的内容就是指以及指针的内容 } void main(){ int *p NULL; getheap(p); // 此处是错误的因为函数的参数是值传递虽然语义是getheap(p),但是mallo的内存地址只是付给了函数的形参函数退出后形参的值并不能传递给实参(指针的值也一样不能传递)导致p还是空指针下面的p[0]1发生空指针异常 p[0] 1; printf(%d\n, p[0]); free(p); }不能用变量声明一个数组eg:int arr[i], 如果申请内存的大小靠程序运行期间决定那么就要使用 malloc(sizeof(int)*i),要记得free 代码区和静态区的大小都是固定的静态区是编译器根据代码提前申请的。堆和栈所占大小是动态但是栈有一个操作系统规定的栈上线 cd /proc // 每个进程号都是一个文件 cd pid cat maps // 查看内存映射这里列出了代码段堆栈静态区的使用情况栈的预设范围 堆的分配和 操作系统分配内存的单位不是字节而是页。cat smps之后发现堆有个项是内存页大小4k。页太大浪费的内存空间太大但操作系统维护起来很简单因为不用频繁的申请释放内存 malloc申请的堆内存上会存在旧数据所以申请后需要用memset清空 memset(p,p,sizeof(int)10) 这两句话的简写就是calloc这样内存上全部是0 int main(){ char p calloc(10,sizeof(char)); // 申请大小是10*sizeof(char) } relloc用于扩展已经申请的堆内存在原有内存上增加连续的内存如果没有连续空间可扩展则会新分配一个连续空间将原有内存拷贝到新空间然后释放原有内存 但是relloc只申请不打扫内存中有旧数据 rello(p,新的内存大小),.如果p为NULL则realloc等于malloc不指定分配空间的起始位置 void main(){ char p1 calloc(10,sizeof(char)); char p2 realloc(p1,5); // p1指向的地址变为5 // realloc(NULL,5) malloc(5) } 结构体 include string.h struct student{ char name[100]; int age; int sex; }; // 声明一个结构体 void main(){ struct student st; // 定义了一个结构体的变量名字叫st //struct student st2 {.name周杰伦,.sex0}; 结构体中通过.来给属性赋值 struct student st3 {0}; // 定义结构体变量并把结构体变量的所有属性设置为0 struct student st4; memset(st,0,sizeof(st)); // 结构体变量初始化 st.age 25; st.sex 1; strcpy(st.name,刘德华); printf(%d\n, st.age ); } 结构体的内存对齐模式 结构体在内存中是一个矩形而不是一个不规则形状以结构体中占地最大的元素对齐。而且不同类型的属性要跨偶数个字节 struct A { int a; // 4字节 char b; // 以4字节对齐 }; // 总共8字节struct B { char a; // 1个字节 short b; // short不同于char类型所以要夸2字节从第3个字节开始对齐 占2个字节 char c; // 占1个字节 int d; // 第二个8字节对齐行 long long e; // 8个字节占地最多的属性所以其他属性以8字节对齐 }; printf(%d\n, sizeof(B)); 结构体成员的位字段 struct A { char a:2; // char占1个字节但是这样声明的结构体中的a字段只有前2bit能通过结构体使用但值得注意的是此时整个结构体仍然占1个字节而不是2bit }; void main(){ struct A a; a.a 3; //二进制11有符号char所以会打印-1 printf(%d\n, ); }struct B { char a:2; unsigned char b:4; char c:1; }; printf(%d\n, sizeof(struct B)); 指针操作结构体不了的内存地址 struct H { char a; // 1个字节但是后三个字节由于结构体对齐而操作不了 int b; };void mian(){ struct H h {1,2}; char p1 h; p1 ; p1 4;(p1) 5;(p1) 6; *(p1) 7; printf(%d\n, h4); } 结构体模仿数组用字段地址连续的结构体成员 struct D { char a; char b; char c; };void main(){ struct G g; char *p g; p[0] a; p[1] b; p[2] c; printf(%d,%d,%d\n, g.a,g.b,g.c); } 结构体数组 struct People { int age; char name[10]; };void main(){ struct People p[3] {{11,aa},{22,bb},{33,cc}}; for (int i 0; i 3; i) { printf(%d,%s\n, p[i].age,p[i].name); } } 结构体可以变相实现数组的赋值 struct A { char arr[10]; };void main(){ struct A a1 {hello}; struct A a2 {0}; a2 a1; printf(%s\n, a2.arr); } 结构体的嵌套 struct A{ char a; char b; } struct{ struct A a; int b; } // 一共占8字节结构体赋值其实就是结构体之间内存的拷贝 struct strss { char s[100]; }; void main(){ struct strss s1,s2; strcpy(s1.s,hello); // s2 s1; 这句话等同于下面的memcpy,结构体是变量所以可以赋值 memcpy(s2,s1,sizeof(s1)); printf(%s\n, s2.s); } 指向结构体的指针操作结构体 void main(){ struct A a; struct A p a; // (p).a 10; 这样写是对的但是太麻烦没人这么写 p - a 10; // 用-代表结构体的一个成员 } 指向结构体数组的指针 string.hstdlib.h void main(){ struct A *p ; /* struct A array[10] {0};
p array; // 指针指向数组首地址 *///也可以在堆中创建结构体
p malloc(sizeof(struct A) * 10);
memset(p,0,sizeof(struct A) * 10)
struct A *array p;p-a 10;
p-b 11;p; // p已经变化了所以free时要从头free就是array。如果free(p)就从当前p的位置往下数10个字节这样就free了不属于结构体数组的内存运行报错
p-a 3
p-b 4;for (int i 0; i 10; i)
{printf(%d,%d\n, array[i].a,array[i].b);
}free(array); } 结构体作为函数参数时尽量使用指针传递参数不要直接使用结构体作为形参 因为结构体和int等变量一样作为参数传递时是值拷贝传递如果传递指针则函数只需要拷贝8字节的地址号而且如果函数想要操作结构体的话也只能通过指针进行参数操作 void setname(struct student a,int age){a-age age; } 四。联合体 联合体所占内存的大小等于联合体中最长属性所占狄村的大小联合体的所有属性公用一块内存地址 union A{ int a; char b; } void main(){ union A a; a.a 0X12345678; printf(%d\n, sizeof(union A)); // 4 ,最长的int属性栈4字节 printf(%p,%p\n, a.a,a.b); // 2个地址一样 printf(%d,%d\n, a.a,a.b); // 12345678, 78 }一个经典的错误写法 union A{ int a; char *b; } void main(){ union A a; a.b malloc(100); a.a 100; // 此时改变了a的值就是改变了b的值下面free的地址就不再是原来的地址会报错 free(b) } 所以如果一个联合体中包含了含有指针变量那么一定要在使用完这个指针后病free掉它才能使用联合体的其它成员 五。 枚举 枚举是一个int常亮不能改变他的值美剧中的每个量都相当于#define x 整数 //#define red 0 相当于下面的枚举定义 //#define black 1 //#define yellow 2 enum A{ red,black,yellow }; void main(){ printf(%f\n, red); // 打印0 }六。typedef typedef char BYTE; 自定义一个BYTE类型作为char类型 相当于 define BYTE chartypedef 通常用于简化结构体变量的名字为一个简短的名字 struct A{ int a; } typedef struct abc A; // 本来声明变量时需要struct A a, 现在只需要abc A即可typedef定义结构体的简写形式 typedef struct A{ int a; }abc; // 张扬相当于上面2句话的简写, A也可以不写形成第三种写法如下typedef struct { int a; }abc; typedef定义函数指针 include string.h include stdio.h void mystrcat (char s1,char s2){ strcat(s1,s2); } // 定义一个函数有三个参数函数指针形参1形参2 void test(void (p)(char ,char ),char s1,char s2){//函数指针p,返回值是void ,形参有两个都是char *类型 p(s1,s2); }// 上面的test函数太复杂因为参数里包含一个函数指针 typedef void (MYSTRCAT)(char ,char ) // 把一个函数指针定义为MYSTRCAT类型 void main(){ MYSTRCAT aa[10]; char s1[100] hello; char s2[5] world; test(mystrcat,s1,s2); printf(%s\n, s1); } 七。文件操作 写文件 include stdio.h int main(){ FILE *p fopen(aaa.txt,w); fputs(hello world\n,p); fclose(p); return 0; } 读文件 include stdio.h include stdlib.h int main(){ char s[1024] {0}; FILE *p fopen(aaa.txt,r); while(!feof(p)){ // 如果文件已经到最后则文件返回真) memset(s,0,sizeof(s)); fgets(s,sizeof(s),p); // 从p位置读取10个字节 printf(%s, s); }; fclose(p);return 0; } 如果文件不存在则新建文件如果存在就追加文件内容 fopen(aaa.txt,a); 转载于:https://www.cnblogs.com/72808ljup/p/5785541.html