|
通过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语言可变参数