通过vscode Remote SSH 到linux远程服务器,使用linux gcc 环境说明: 购买一个云linux服务器,或者安装一个linux的虚拟机, 通过vscode remote ssh插件远程连接,完成一系列的C的语法学习 如果安装的是ubantu环境,自带桌面及C系列的软件包,推荐使用 vscode下载 https://code.visualstudio.com/ 安装Remote SSH插件 ctrl+shift+p 选择,remote ssh 如果默认端口是22的话,ssh xt@357210.xyz 其他端口需要指定端口号 ssh -p 26759 xt@357210.xyz 对应配置文件的格式 Host 357210.xyz HostName 357210.xyz User xt Port 26759 ctrl+shift+p 选择,remote-ssh:connect to host 在弹出的框中输入密码,然后回车 |
C概述 在计算机的世界中,C语言是基础中的基础,C语言中讲述了高级编程中最基础的那部分知识, 高级语言就是除了汇编,编译原理,机器语言之外的,人方便阅读的语言 操作系统是C写的,未来会有其他语言冲击这个领域,目前C的地位还没有哪个语言能替代 在编程界,没有哪个语言能摆脱C语言的影响,它们大多都调用了C语言的库函数, 毕竟OS都是C写的,语言要运行在OS上,这也是没办法的事, 未来开发人员的三条路: 1. 向上发展,开发一系列方便好用的模块,打造一个好用的平台,调调API就解决了一切,这叫服务模式 2. 向下发展,底层建设,网络的底层研究透了不管是当黑客还是转身当杀毒专家都可以,OS底层,稀缺人才哪里都有需要 3. 算法方向,不限语言,但编程发展到这一步,会点C/C++对学习算法是有帮助的;学习AI,会C/C++也是不错的加分项 |
C运行示例:以ubantu环境为例 xt@ai:/opt/tpf/cwks/src/test$ cat a.c #include <stdio.h> int main(){ printf("%d\n",1); return 0; } 编辑运行 xt@ai:/opt/tpf/cwks/src/test$ gcc a.c xt@ai:/opt/tpf/cwks/src/test$ ls a.c a.out xt@ai:/opt/tpf/cwks/src/test$ ./a.out 1 printf:按指定的格式将数据输出到控制台,%d表示整数,\n表示换行,printf() 函数在 "stdio.h" 头文件中声明。 stdio.h 是一个头文件 (标准输入输出头文件) ,定义一系列io方法,printf就是其中一个 #include:预处理命令,引用外部写好的文件到本文件,从而本文件可以调用其中的方法, return 0; 退出程序 /* ... */ 注释 |
|
|
C简单数据类型:数字,字符,布尔 数字:int,float,double 字符:char 其实,每个字符都对应一个整数 换句话讲,计算机中一切皆数字,将不同的数字,找个符号与之对应,就有了字符 布尔:bool, 布尔就是逻辑真假类型,bool按发音直译过来的单词 bool:0为假,其他皆为1(表示真) #include <stdio.h> #include <stdbool.h> int main(void) { bool flag = 11; printf("flag:%d\n", flag); return 0; } 0为假,1为真,布尔值只有0与1两个值,占1个字节 bool默认值为0-假 #include <stdio.h> #include <stdbool.h> int main(void) { bool flag; printf("flag:%d\n", flag);//flag:0 return 0; } |
C变量 定下数据类型后,就有了变量, 变量是一个量, - 量就是大小,多少,规模,量化后,就可以比一比大小 - int a = 1; 1就是要表示的量 变量可以表示 一类数据, - 比如int类型数据, - 用符号代表该类数据,1,2,3,...n这样的数据都可以使用一个变量表示 - 这类数据都有相同的类型int 变量,变量,量的值是可以变化的 - a = 2; a被声明后,可以放任何一个int数据 有多少种数据类型,就有多少种变量 变量主要有:数字,字符,指针 #include <stdio.h> int main(){ int a=1,b=2; char c = 'a'; float f = 1.0; double d = 2.0; printf("a=%d\n",a); printf("c=%c\n",c); printf("f=%f\n",f); printf("d=%f\n",d); return 0; } xt@ai:/opt/tpf/cwks/src/test$ gcc a11.c xt@ai:/opt/tpf/cwks/src/test$ ./a.out a=1 c=a f=1.000000 d=2.000000 变量占用字节大小:sizeof #include <stdio.h> int main(){ int a = 11; float b = 11; printf("a=%f,b=%f\n",a,b); // a=11.000000,b=0.000000 printf("size int:%d,size float:%d\n",sizeof(a),sizeof(b)); // size int:4,size float:4 return 0; } |
C常量 有多少种数据类型,就有多少种常量 常见常量:整数,浮点,布尔,字符,字符串 #include <stdio.h> int main(){ printf("数字常量:%d\n",1); printf("字符常量:%c\n",'c'); printf("字符串常量:%s\n","abc"); return 0; } xt@ai:/opt/tpf/cwks/src/test$ gcc a.c xt@ai:/opt/tpf/cwks/src/test$ ./a.out 数字常量:1 字符常量:c 字符串常量:abc define定义的常量只是字符串的替换 #include <cstdio> #define Pi 3.14 #define add + int main(){ int a = 1 add 2; printf("a=%d\n",a); return 0; } $ gcc b.c $ ./a.out a=3 只是将 1 add 2 中的add替换为了+ 所以,就成了 1 + 2 define这种处理是在预编译阶段, 也就是说这里的Pi,add压根就不是什么变量,只是一种语法操作 从这个角度看,define定义常量没有多少性能的提升 const 定义常量 #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { const int B = 2; int c =B; int d =B; printf("B addr:%p\n",&B); printf("c addr:%p\n",&c); printf("d addr:%p\n",&d); return 0; } $ gcc c.c $ ./a.out B addr:0x7ffff75393dc c addr:0x7ffff75393d8 d addr:0x7ffff75393d4 顺更提一下,栈内存的地址是从高到低排列的 static变量在“代码区,数据区,堆,栈”中的 数据区 中 const让变量不再变化,本质是还是变量,只是值不能被改变 想要它成为静态变量,还得加个static,然后它的存储位置直接就到数据区了 #include <stdio.h> int main(){ static const int a = 1; printf("a=%d\n",a); return 0; } $ gcc b.c $ ./a.out a=1 define与const区别举例:variably modified 'arr1' at file scope #include <stdio.h> const int max_arr_len=101; struct CsvRow { char* arr1[max_arr_len]; }; int main () { return 0; } $ gcc d.c d.c:5:11: error: variably modified 'arr1' at file scope char* arr1[max_arr_len]; ^~~~ 下面代码是对了,那怎么上面的就错了? #include <stdio.h> int main () { const int max_arr_len=101; char* arr1[max_arr_len]; return 0; } 核心在于const定义的常量,本质还是变量,只是它不能修改 struct中数组长度是要在编辑时确定下来的,而一个变量的值在运行时赋值的 main里面的代码可以运行,在于它的范围是方法内,是在运行时才确定 define 定义常量 #include <stdio.h> #define max_arr_len 101 struct CsvRow { char* arr1[max_arr_len]; }; int main () { return 0; } |
C变量生命周期 linux一个进程大致分 文本区:数据代码,只读 数据区:全局变量 及 静态变量 存储区域,程序编辑阶段就需要初始化的数据存放该区 堆栈区:局部变量/数据 存储区域,栈通常是int,float等方法中定长变量存储区域,堆是变长常量存储区域 c static static int count = 0; static 修饰变量/方法,会将该变量/方法限定于所在文件,并转到进程内存的数据区 对于全局变量,外部程序无法访问其他文件中的被static修饰的变量/方法 如果不想某个 函数/变量 被外部文本访问,加上static就可以了 对于方法中的局部变量,本应在方法调用之后消失, 但由于作用域被提升到了文件的级别,方法调用后也不会消失了 局部变量在堆栈中,但加上static后,会转移到数据区, 方法中的静态变量放在数据区固定的地址处, 所以 局部静态变量 的值并不会随方法结束而消失 #include <stdio.h> #include <string.h> void test(){ static int count = 0; count++; printf("%d",count); } int main () { int i; for(i =0;i<3;i++){ test(); } return 0; } 输出 123 c extern c生成可执行文件主要分:编辑,连接,执行 最终所有代码是在一个文件中了, 如果开发的代码多,除了include可以引入外部文件外, 还可以使用extern告诉编辑器,某个变量/方法在其他文件中,可以先用用 若不使用extern,那么所谓的全局变量, 也仅限于本文件内,虽然最后所有文件还是会连接到一起 extern 函数 extern double str_sec(char* t_str); |
C static 示例1 方法内的静态变量举例:判断卡号是否不连续了 #include <stdio.h> #include <stdbool.h> #include <string.h> //是否首次出现,是否不连续了 bool is_first_show(char* card){ static char* card_old = NULL; if(card_old==NULL){ card_old = card; return 1; }else{ if(strcmp(card,card_old)==0){ card_old = card; return 0; }else{ card_old = card; return 1; } } } int main(void) { char* card="623004134003432038"; bool flag = is_first_show(card); if(flag){ printf("1 首次出现 \n"); } card="623004134003432031"; flag = is_first_show(card); if(flag){ printf("2 首次出现 \n"); } flag = is_first_show(card); if(flag){ printf("3 首次出现 \n"); } card="623004134003432038"; flag = is_first_show(card); if(flag){ printf("4 首次出现 \n"); } return 0; } $ gcc d.c $ ./a.out 1 首次出现 2 首次出现 4 首次出现 上面的代码有问题,正确的如下 上面的代码问题在于,使用的是指针,指针变量可能会出现,地址相同,而内容已经变了的情况 card_old = card; 这行代码只是改变了指针变量的地址,与比较内容是否相等还是有细微差异的 将card的地址赋予card_old,如果card是数组,在方法外部被修改内容, 那么card_old与card同地址,其内容也随之改变,这与比较内容是否相同的本意不符 优化后的代码如下 这个地方也可以当作一个指针使用的典型例子 //是否首次出现,是否不连续了 bool is_first_show(char* card){ static char card_old[30]; int count = strlen(card)+1; if(card_old==NULL){ memcpy(card_old,card,count); return 1; }else{ if(strcmp(card,card_old)==0){//相同时不必再赋值了 return 0; }else{ memcpy(card_old,card,count); return 1; } } } |
隐式转换 隐式转换的顺序: int -> unsigned int -> long -> unsigned long -> unsigned long long -> float -> double -> long double #include <stdio.h> int main(){ int a=2; float f; f = a; double d; d =f ; printf("a=%d\n",a); # a=2 printf("f=%f\n",f); # f=2.000000 printf("d=%f\n",d); # d=2.000000 return 0; } 显式转换 #include <stdio.h> int main(){ int a; float f=1; a = (int)f; printf("a=%d\n",a); // a=1 printf("f=%f\n",f); // f=1.000000 return 0; } |
计算机内存 计算机硬件的组成之一是内存,通常是内存条 OS是软件,由 编程语言 编写, 这里说的是内存是OS的内存,它将电脑中多个内存条统一编码, 每8位一个字节,标记为一个地址,并且从0编号,形成一个虚拟内存 我们说一个电脑内存多大指是的虚拟内存,可能有多个内存条映射而成 |
C指针定义 电脑的虚拟内存,每个字节标记一个地址,从0编号, 所以说,地址是一串数字,或者说是一个整数, 它与内存的一个字节对应(确切是字节的起始位) 这个关联内存位置的数字,就是指针,它指向内存的一个位置,一个字节的开头, 到哪里结束,即指针确定数据所占的字节数,由指针的数据类型决定 由于是整数,指针可以有加减运算,也可以移动, 类似刻度尺上的数字 可以通过指针 访问/操作 内存 取地址指: 取 从指定地址开始,以数据类型所占字节数为长度的数据 指针是一个地址,是一个特殊意义的数字 指针变量是一个变量,专门存储地址的变量,所有变量的地址长度一致, 不管是什么指针变量,它们所占的字节数一致,因此它们的值都是地址 如果是64位计算机,通常是8个字节 指针变量的值是一个8字节(64位)的数字地址,所有指针变量都是如此 #include <stdio.h> int main(){ int* a; printf("a adder size of byte:%ld\n",sizeof(a)); return 0; } $ gcc g.c $ ./a.out a adder size of byte:8 |
#include <stdio.h> // 定义枚举类型 enum AVMediaType { AVMEDIA_TYPE_UNKNOWN = -1, ///< 通常被视为 AVMEDIA_TYPE_DATA AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_DATA, ///< 不透明数据,通常连续 AVMEDIA_TYPE_SUBTITLE, AVMEDIA_TYPE_ATTACHMENT, ///< 不透明数据,通常稀疏 AVMEDIA_TYPE_NB }; // 一个函数,用于打印枚举类型的名称 void printMediaType(enum AVMediaType type) { switch (type) { case AVMEDIA_TYPE_UNKNOWN: printf("AVMEDIA_TYPE_UNKNOWN\n"); break; case AVMEDIA_TYPE_VIDEO: printf("AVMEDIA_TYPE_VIDEO\n"); break; case AVMEDIA_TYPE_AUDIO: printf("AVMEDIA_TYPE_AUDIO\n"); break; case AVMEDIA_TYPE_DATA: printf("AVMEDIA_TYPE_DATA\n"); break; case AVMEDIA_TYPE_SUBTITLE: printf("AVMEDIA_TYPE_SUBTITLE\n"); break; case AVMEDIA_TYPE_ATTACHMENT: printf("AVMEDIA_TYPE_ATTACHMENT\n"); break; case AVMEDIA_TYPE_NB: printf("AVMEDIA_TYPE_NB\n"); break; default: printf("Unknown media type\n"); break; } } int main() { // 示例使用枚举类型 enum AVMediaType mediaType1 = AVMEDIA_TYPE_VIDEO; enum AVMediaType mediaType2 = AVMEDIA_TYPE_AUDIO; enum AVMediaType mediaType3 = AVMEDIA_TYPE_UNKNOWN; printf("c enum:%d\n",AVMEDIA_TYPE_VIDEO); // 打印枚举类型的名称 printMediaType(mediaType1); printMediaType(mediaType2); printMediaType(mediaType3); return 0; } c enum:0 AVMEDIA_TYPE_VIDEO AVMEDIA_TYPE_AUDIO AVMEDIA_TYPE_UNKNOWN 虽然本质是数字,但却不能直接赋值给int类型 |
C格式化输出:printf #include <stdio.h> int main(){ int a,b=2; char c; float f; double d; scanf("%d %c %f %lf",&a,&c,&f,&d); printf("a=%d\n",a); printf("c=%c\n",c); printf("f=%f\n",f); printf("d=%f\n",d); scanf("%d,%c,%f,%lf",&a,&c,&f,&d); printf("a=%d\n",a); printf("c=%c\n",c); printf("f=%f\n",f); printf("d=%f\n",d); return 0; } |
C运算符 逻辑运算符:&&,||,! #include <stdio.h> #include <stdbool.h> int main() { int a =1,b=2,c=3; bool f = 0; if((a>0 && b>1 && c>2) || !f){ printf("ok\n"); } return 0; } 位运算符:&,|,^,~,<<,>> |
C进制 二进制:0b/0B,0-1 #include <stdio.h> #define u32 unsigned int #define u8 unsigned char //输出二进制 void print_bin(u32 input) { u8 temp[33] = {0}; int i = 0; while(input) { temp[i] = input % 2; input = (u32)input / 2; i++; } for(i--; i>=0; i--) { printf("%d",temp[i]); } printf("\r\n"); } int main() { print_bin(5);//101 int a =0b101,b=0b011; print_bin(a&b);//1 print_bin(a|b);//111 print_bin(a^b);//110 print_bin(~b);//1111 1111 1111 1111 1111 1111 1111 1100 print_bin(b<<1);//110 都向左移动一位,相当于每1位都乘以进制2,(1*2 + 1*1)*2 = 6 print_bin(b>>1);//1 return 0; } 八进制:0-7,以数字0开头 #include <stdio.h> int main() { int a =0101,b=0011; printf("10进制 a=%d,b=%d\n",a,b); printf("8进制 a=%o,b=%o\n",a,b); return 0; } $ ./a.out 10进制 a=65,b=9 8进制 a=101,b=11 16进制:0-9,A-F或a-f不区分大小写,以0x开头 #include <stdio.h> int main() { int a =0x101,b=0x011; printf("10进制 a=%d,b=%d\n",a,b); printf("16进制 a=%x,b=%x\n",a,b); return 0; } $ gcc num.c $ ./a.out 10进制 a=257,b=17 16进制 a=101,b=11 |
4字节,32位 int最小值=-2147483648, int最大值=2147483647 #include <stdio.h> #include <limits.h> #include <float.h> int main() { printf("int类型数据所占空间=%d\n", sizeof(int)); printf("int最小值=%d, int最大值=%d\n", INT_MIN, INT_MAX); // 使用limits.h里的宏 //方法2 signed int max = (1 << (sizeof(int) * 8 - 1)) - 1; // 位计算 signed int min = -(1 << (sizeof(int) * 8 - 1)); printf("int最小值=%d, int最大值=%d\n", min, max); // 方法3 printf("int最小值=%d, int最大值=%d\n", max+1, min-1); // double数据类型精度及范围--数据很大,1.79769e+308 printf("float类型数据所占空间:%d\n", sizeof(float)); printf("double类型数据所占空间:%d\n", sizeof(double)); printf("double精度:%lf\n"); //有警告,不过可以运行 printf("double最小值=%lf\n, double最大值=%lf\n", -DBL_MAX, DBL_MAX); //使用float.h的宏 //试一试它是不是真的这么大 double max_double = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000; printf("double max value is %lf\n",max_double); return 0; } int是2为开头的10位数 $ ./a.out int类型数据所占空间=4 int最小值=-2147483648, int最大值=2147483647 int最小值=-2147483648, int最大值=2147483647 int最小值=-2147483648, int最大值=2147483647 float类型数据所占空间:4 double类型数据所占空间:8 double精度:0.000000 double最小值=-179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000 , double最大值=179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000 double max value is 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000 double1.79769e+308,300多位,平时用足够,不需要再加什么long, 已经够long了 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000 |
float可以很大,最大为3.4乘以10的38次方(double是1.7×10的308次方) 但它的有效数字位数最大为7,超过7的部分,经printf("%f")格式化输出后 - 小数点部分会被置为0 - 大于0但超过7位的部分就不准了 float有效小数位:小数点后6位 #include <stdio.h> int main(){ float a = 0.1234567; printf("%f\n",a); // 0.123457 printf("size of float :%ld\n",sizeof(a)); //size of float :4 return 0; } 如果小数点后超出6位,直接四舍五入 c float的精度 #include <stdio.h> int main(){ float a = 1234567890.1234567; printf("a = %f\n", a); // a = 1234567936.000000 return 0; } float小数点后6位有效小数,但它的有效位数是7,第8位就开始不准了 float的存储结构 float类型数据占四个字节,一个字节是8位,共32位 以类似 3.402823466 E+38 的格式存储 第1位: 0表示正数,1表示负数 第2-9位:指数 第10-32:几点几的小数部分 AI中的小数 import numpy as np np.allclose(1e-8,0) # True AI中认为小数点高于7位的部分为0, 而C中float高于6位就自动四舍五入 第8位就是0,第7位四舍五入到第6位上,即合理又不浪费 还减少了计算的代价, AI框架最终还是要转化为C的float类型进行计算, 而double的有效位数为15,对AI来说太多了, 所以AI中数据类型通常指定为float32 float的最大值 :3.402823466 E+38 3.4乘以10的38次方是一个非常大的数 10的9次方为亿,其38次方不知道多少个亿 大部分运算使用float类型够用 |
#include <stdio.h> int main(){ double a = 12345678901234567890.1234567; printf("%lf\n",a); // 0.123457 printf("size of float :%ld\n",sizeof(a)); //size of float :4 return 0; } double的有效位数为17,超出17位的就不准了 gcc db.c ./a.out 12345678901234567168.000000 size of float :8 double1.79769e+308,300多位,平时用足够,不需要再加什么long, 已经够long了 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000 |
C数字补0 #include <stdio.h> int main(){ int a = 111; printf("%05d\n",a); return 0; } 输出 00111 |
sprintf格式化输入 #include <stdio.h> #include <stdlib.h> #define N2 19 int main(){ int a = 111; char str[N2]; sprintf(str,"%05d",a); printf("%s\n",str); return 0; } #include <stdio.h> #include <stdlib.h> #include <string.h> void ifmt(char** res,int i){ char tmp[100]; sprintf(tmp,"%d",i); *res = (char*)malloc(strlen(tmp)*sizeof(char)+1); sprintf(*res,"%s",tmp); } void dfmt(char** res,double i){ char tmp[100]; sprintf(tmp,"%lf",i); *res = (char*)malloc(strlen(tmp)*sizeof(char)+1); sprintf(*res,"%s",tmp); } int main() { char* res; int a =3; ifmt(&res,a); printf("-%s-\n", res); free(res); double b = 3.2; dfmt(&res,b); printf("-%s-\n", res); //-3.200000- 多了一些0 free(res); return 0; } |
sscanf int #include <stdio.h> int main(){ char* ss = "123"; int i ; sscanf(ss,"%d",&i); printf("d=%d\n",i); } $ gcc b.c $ ./a.out d=123 sscanf double #include <stdio.h> int main(){ char* ss = "123.4"; double i ; sscanf(ss,"%lf",&i); printf("d=%lf\n",i); } $ gcc b.c $ ./a.out d=123.400000 atoi:只针对整数,double会损失小数部分 #include <stdio.h> int main(){ char* s1 = "123"; int i = atoi(s1); printf("i=%d\n",i); //i=123 char s2[] = "123.456"; double d = atoi(s2); printf("d=%lf\n",d); //d=123.000000 } |
#include <stdio.h> #include <stdlib.h> void tobin(int n){ int arr[32] = { 0 };//int 型有32位, int i = 0; while (n > 0) { arr[i] = n % 2; ++i; n /= 2; } int k = 0; for (k = i-1; k >= 0; k--) //逆序输出 { printf("%d", arr[k]); } } int main() { tobin(5); return 0; } ........................................................... |
for循环 # include <stdio.h> int main() { int i = 1; int sum = 0; for (i=0; i<=3; ++i) { sum = sum + i; } printf("sum = %d\n", sum); return 0; } for (表达式1; 表达式2; 表达式3) 表达式1可以空着, 但不能写成变量的定义,即不能写int i =0; int i的定义必须写在for的前面, i = 0的赋值这样的表达式才算正确 |
C 断言 #include <stdio.h> #include <stdlib.h> #include <assert.h> typedef char string[30]; struct Students { int student_id; // 4 bytes string student_name;// 32 bytes float score; // 4 bytes }; struct Students st1; void test(int a){ // 动态断言 // 条件成立则顺利通过,不成立则抛出异常并中断程序; assert(a>5); //静态断言,用于编译检测 static_assert(sizeof(st1)>36,"编译检查失败,长度必须大于36"); } void test_exit(int a){ if (a<3){ exit(-1); } } int main(){ int a = 6; test_exit(a); test(a); return 0; } |
#include <stdio.h> int main(){ int a,b=2; char c; float f; double d; scanf("%d %c %f %lf",&a,&c,&f,&d); printf("a=%d\n",a); printf("c=%c\n",c); printf("f=%f\n",f); printf("d=%f\n",d); scanf("%d,%c,%f,%lf",&a,&c,&f,&d); printf("a=%d\n",a); printf("c=%c\n",c); printf("f=%f\n",f); printf("d=%f\n",d); return 0; } 格式在C中如果写错了,后果不可预料 #include <stdio.h> int main(){ int a = 11; float b = 11; printf("a=%d,b=%f\n",a,b); // a=11,b=11.000000 printf("size int:%d,size float:%d\n",sizeof(a),sizeof(b)); // size int:4,size float:4 return 0; } 注意看,b并没有写错,错的是a,但结果却是b输出不正确 #include <stdio.h> int main(){ int a = 11; float b = 11; printf("a=%f,b=%f\n",a,b); // a=11.000000,b=0.000000 printf("size int:%d,size float:%d\n",sizeof(a),sizeof(b)); // size int:4,size float:4 return 0; } |
scanf为格式化输入,将常量存放到指定的地址& printf为格式化输出,将常量从内存输出到控制台 xt@ai:/opt/tpf/cwks/src/test$ gcc a12.c xt@ai:/opt/tpf/cwks/src/test$ ./a.out 1 2 2.0 3.0 a=1 c=2 f=2.000000 d=3.000000 1,a,1.0,3 a=1 c=a f=1.000000 d=3.000000 |
puts #include <stdio.h> int main() { char c; puts("请输入一个字符"); c = getchar(); puts("你输入的字符是"); putchar(c); return 0; } printf,格式化输出,可输出各种格式 puts,只输出字符串,并在结尾带个换行符 |
#include <stdio.h> #include <string.h> typedef struct Kong { } K; typedef struct Kis { int a; } Ki; typedef struct Students { int sid; char name[150]; } Student; int main( ) { K kk; Ki ki; printf("before init K struct, the count of the Bytes:%ld\n",sizeof(kk)); printf("before init Ki struct, the count of the Bytes:%ld\n",sizeof(ki)); Student st; printf("before init Students struct, the count of the Bytes:%ld\n",sizeof(st)); st.sid = 12345; strcpy(st.name, "东段洋"); Student st2; memcpy(&st2, &st, sizeof(st)); printf( "sid : %d\n", st2.sid); printf( "name : %s\n", st2.name); return 0; }
before init K struct, the count of the Bytes:0 before init Ki struct, the count of the Bytes:4 before init Students struct, the count of the Bytes:156 sid : 12345 name : 东段洋
多于一个字段时,struct多出两个字节,用途尚不知
#include <stdio.h> #include <string.h> typedef struct Kis { int a; int b; char name[150]; } Ki; typedef struct Students { int sid; char name[150]; } Student; int main( ) { Ki ki; printf("before init Ki struct, the count of the Bytes:%ld\n",sizeof(ki)); Student st; printf("before init Students struct, the count of the Bytes:%ld\n",sizeof(st)); return 0; }
before init Ki struct, the count of the Bytes:160 before init Students struct, the count of the Bytes:156
结构体COPY:复制与引用的区别
#include <stdio.h> #include <string.h> typedef char string[30]; struct Students { int student_id; string student_name; float score; }; /* 函数声明 */ void copy( struct Students st ); void update( struct Students *st ); int main( ) { struct Students st1; /* 声明 */ st1.student_id = 11; copy( st1 ); printf("name:%s\n",st1.student_name); printf("score:%f\n",st1.score); update( &st1 ); printf("name:%s\n",st1.student_name); printf("score:%f\n",st1.score); return 0; } void copy( struct Students st ) { strcpy( st.student_name, "七三学徒"); st.score = 60; } void update( struct Students *st ) { strcpy( st->student_name, "七三学徒"); st->score = 60; } 输出 name: score:0.000000 name:七三学徒 score:60.000000
结构体指针 类型
#include <stdio.h> struct Empty{ }; //结点结构体 struct Node{ int data; //数据域 struct Node* next; //指针域 }; //链式队列结构体 typedef struct LQ{ int size; //队列大小 struct Node out; //头结点,本身data不存储数据,仅使用其next,其next永远指向队列的第一个节点 struct Node* in; //尾结点指针,指向队列最后一个节点,其数据就是队列最后一个节点的数据 }LkQueue, *LinkQueue; //定义两个类型,一个LQ结构体,一个LQ结构体指针 int main (int argc, char** argv) { printf("Empty size :%ld\n",sizeof(struct Empty));// 1 printf("node size :%ld\n",sizeof(struct Node));// 16 printf("LkQueue size :%ld\n",sizeof(LkQueue));// 32 printf("LinkQueue:%ld\n",sizeof(LinkQueue));//8 int a =2; int* b = &a; printf("int size:%ld\n",sizeof(a));//4 printf("int* size:%ld\n",sizeof(b));//8 return 0; }
C函数作为参数 ElemType(*FunctionName)(ElemType, ElemType, ......) #include <stdio.h> int add(int a,int b){ return a+b; } void test(int (*func)(int,int),int a,int b){ int res = func(a,b); printf("res=%d\n",res); } int main() { test(add,1,2); return 0; } (base) [xt@ai1 C++]$ gcc f.c (base) [xt@ai1 C++]$ ./a.out res=3 |
C命令行参数 #include <stdio.h> int main( int argc, char *argv[] ) { int i; for (i=0;i<argc;i++){ printf("第%d个参数:%s\n",i,argv[i]); } } $ gcc a.c $ ./a.out -name aaa 第0个参数:./a.out 第1个参数:-name 第2个参数:aaa int main (int argc, char** argv) { return 0; } |
C可变参数 param_count参数的位置必须在...的前面 #include <stdarg.h> #include <stdio.h> void parse_params(int param_count, ...); int main(void) { // 超出param_count的被忽略 char *p1 = "aa"; char *p2 = "bb22"; char *p3 = "cc"; parse_params(2, p1, p2, p3); } void parse_params(int param_count, ...) { va_list param_list; va_start(param_list, param_count); int idx; char *val; printf("---------------\n"); for(idx = 1; idx <= param_count; ++idx){ val = va_arg(param_list, char*); printf("第 %d 个参数: %s\n", idx, val); } printf("---------------\n"); va_end(param_list); } 可变参数2 #include <stdarg.h> #include <stdio.h> #include <string.h> void parse_params(int param_count, ...); typedef char string[30]; struct Data { int id; float score; string name1; string name2; string name3; }; int main(void) { struct Data d1; d1.id = 1; d1.score = 2; strcpy(d1.name1,"aa"); struct Data *p1 = &d1; parse_params(1, p1); } void parse_params(int param_count, ...) { va_list param_list; va_start(param_list, param_count); int idx; struct Data *val; printf("---------------\n"); for(idx = 1; idx <= param_count; ++idx){ val = va_arg(param_list, struct Data*); printf("第 %d 个参数: %s\n", idx, val->name1); } printf("---------------\n"); va_end(param_list); } 自定义可变参数:使用结构体封装参数,以复制的方式传递,内外操作互不影响 #include <stdio.h> #include <string.h> typedef char string[300]; struct Params { int int_count; int float_count; int string_count; int int_val[100]; float float_val[100]; string string_value[100]; }; void parse_params(struct Params params); int main(void) { struct Params d1; d1.int_count = 1; d1.int_val[0] = 10; d1.string_count = 2; strcpy(d1.string_value[0],"aa"); strcpy(d1.string_value[1],"bbb"); parse_params(d1); } void parse_params(struct Params params) { printf("---------------\n"); int idx; for(idx = 1; idx <= params.int_count; ++idx){ printf("第 %d int个参数: %d\n", idx, params.int_val[idx-1]); } for(idx = 1; idx <= params.string_count; ++idx){ printf("第 %d string个参数: %s\n", idx, params.string_value[idx-1]); } printf("---------------\n"); } |
|
|
.c C语言 .cpp C++ 通常gcc编辑.c文件 也可以使用gcc去编译了一个.cpp文件,但编辑的细节是不一样的 比如&符号在C语言中是取地址符,在C++中还可以是引用传址,只要是.cpp后缀,&符号就会被看作是C++的引用传值 而C语言的中传址使用的是指针* gcc m.cpp gcc 运行了cpp程序,并且可以使用C++的引用, 但如果不安装g++则会报下面的错误 $ gcc m.cpp gcc: fatal error: cannot execute ‘cc1plus’: execvp: No such file or directory 安装g++后就可以了 $ sudo apt install g++ $ gcc m.cpp $ |
&符号在C语言中是取地址符, 在C++中还可以是引用传址, 只要是.cpp后缀,&符号就会被看作是C++的引用传值 而C语言的中传址使用的是指针* |
|
|
|
C语言可变参数