前端

C语言基础

2019-02-07  本文已影响0人  无尾树袋熊

注意点

  1. 函数名不可重复
  2. 要执行一个定义好的函数,需要在main函数中调用。格式:函数名();
  3. include<stdio.h>查找系统定义的函数

  4. c语言中的main函数写法多,标准写法如上
  5. 多行注释不能嵌套多行注释/* */
  6. 注释应用场景:思路分析,函数变量说明

C基础

一、关键字

二、标识符

  1. 只呢由字母,下划线,数字组成
  2. 不能以数字开头
  3. 不能是关键字
  4. 严格区分大小写
  1. 见名知意,驼峰命名:方便阅读

三、C语言常量和变量

常量:固定的数据

整型常量(整数)
实型常量(小数)
  1. 单精度(例如:10.12f 或 10.12F)
  2. 双精度(默认都为双精度)
字符型常量
  1. 字符型常量的 ''中只能放一个字符(例: 'a' '1')
  2. 特殊情况:转移字符除外('/t' '/n' '//')
字符串型常量
  1. 可以放一个或多个字符("123" "你好")
  2. 系统会在末尾加上一个字符 '\0'作为结束标志

变量:可以改变的数据

定义变量: 数据类型 变量名1,变量名2;
变量的作用域
局部变量:定义在{}内的
全局变量:定义在{}内外的

注意点

  1. {}会新开辟一段存储空间
  2. 局部变量:在同一个作用域内,不能出现同名变量.不同作用域可以出现同名变量
  3. 全局变量:相同作用域,可以出现同名变量

四、printf和scanf函数

printf函数:

  1. 把指定的数据显示在屏幕上
格式:
  1. printf("输出的内容");
  2. printf("格式化字符串",输出列表项);
  3. 格式化字符串:%[标示][输出宽度][.精度][长度]类型
  4. %i,%d:整型常量和变量 %f:单精度小数 %lf:双精度小数 %c:字符型常量变量
输出宽度格式:

指定输出内容位数 。如果输出内容大于或等于指定的宽度,则按照实际输出的宽度输出。如果如果输出内容小于指定的宽度,则在实际输出的内容前添加空格

标志格式:
  1. -左对齐,默认右对齐
  2. +当输出值为正时,添加一个+号,默认不显示
  3. 0右对齐时,用0填充宽度,默认用空格(常用在日期格式上)
  4. 空格 输出值为正时,在前面加上空格,为负数加上负号
精度格式:

指定输出小数位数保留

  1. 其它格式: %[.]类型(为占位符)

Scanf函数:

用于接受键盘输入的内容,是一个阻塞式函数

格式:
  1. scanf("格式化字符串",地址列表);
  2. &取地址符号: &变量名

注意点:

  1. 单精度的小数,有效位数只有6-7位,超出后则为垃圾数据(有效位数是从小数点前开始计算)
  2. 双精度的小数,有效位数只有15-16位,超出后则为垃圾数据
  3. scanf如果接受的不是字符类型的数据.输入的空格,TAB,回车都是无效的
  4. scanf函数的格式化字符串不能以\n结尾,不然永远无法结束
  5. ==scanf函数的格式化字符串中还有别的字符串,必须要原样输入==
  6. scanf函数如果需要接受多个非字符类型的数据,可以通过空格,TAB,回车作为分隔符
  7. 清空输入缓冲区:

五、C语言运算符

告诉程序执行特定算数或逻辑操作的符号

(1)算数运算符

(2)类型转换

1.自动类型转换
1.运算转换

小类型转大类型:int -> double(大小一样才能运算,编译器自动转换)

2.赋值转换

例:

int num = 3.14;
printf("num = %i\n",num)
2.强制类型转换

例:

double c = 3.33;
int d = c;

(2)赋值运算符

1.简单赋值运算符

= 将右边的值赋值给左边的变量

2.复杂赋值运算符

+= -= *= /= %=
例:

b += 5; //b = b + 5;
b -= 5; //b = b - 5;
b *= 5; //b = b * 5;
b %= 5; //b = b % 5;
3.赋值运算符结合性
1.右结合性
int b = 10;
b += 10 -5;// b = b + (10 - 5);
2.优先级

赋值运算的优先级 低于 算数运算符

(3)自增自减

快速加减1 例:

int num = 1;
num++; // num--;后加减
++num; // --num;先加减

比较:

int num = 10;
int res = 10 + num++; //res = 20,num = 11;
int res = 10 + ++num; //res = 21,num = 11;
char ch = "m";
ch++;
printf("ch = %c\n",ch);//ch = e

(4)sizeof运算符

1.格式:
  1. sizeof(变量/常量/数据类型);
int res = sizeof(3.14);
int res = sizeof(double);

int res = 10;
int res = sizeof(res);
//数据类型不能省略圆括号
  1. sizeof 变量/常量;
2.作用:

用于计算变量/常量/数据类型占用的存储空间

(5)逗号运算符

  1. 用于简化代码
  2. 有运算结果
  3. 结果是最后一个表达式的值.例:
int a,b,c;
a = 10,b = 20,c = 30;
int res = ((a + b),(a + c));// res = 40 面试常用

(6)关系运算符

int a,b;
a = 10 ,b = 5;
int res = a > b;//res = 1
int res = a < b;//res = 0

(7)逻辑运算符

1.逻辑与 &&
int res = (10 > 5)&&(20 > 19);//res = 1
int res = (10 > 11)&&(20 > 19);//res = 0
2.逻辑或 ||
int res = (10 > 11)||(20 > 21);//res = 0
int res = (10 > 11)||(20 > 19);//res = 1
3.逻辑非 !
int res = !(10 > 9);//res = 0
int res = !(10 < 9);//res = 1
4.逻辑运算符结合性
int num = 1;
int res = (10 > 20)&&(++num > 0);
//res = 1 num = 1 一假则假

int num = 1;
int res = (10 < 20)||(++num > 0);
// res = 1 num = 1 一真则真
int res = !!!(10 > 9);//res = 0

(8)三目运算符

int a = 10 , b = 5;
int res = a > b ? a : b;//res = 10

注意点:

  1. 在+ - * /的运算中,整数和整数的运算结果一定是整数.整数和小数的运算结果一定是小数
  2. 在%中不能出现小数
  3. 在%中被除数为0,结果就为0
  4. 在%中,结果的正负性,取决于被除数
  5. 自动类型转换不会改变原有量的值
  6. 自增自减只能用与变量
  7. 自增自减最好单独出现.例如:
int num = 10;
int res = 10 + num;
num++;
  1. 同一个表达式同一个变量同时自增自减,没有规定怎么运算,不同编译器结果不一样
  2. sizeof优先级高于算数运算符
  3. 关系运算符是左结合性(无法判断某个值是否在某个区间内).例:
int res = 10 > 5 > 3;//res = 0
  1. <= < > >= 优先级高于 == !== ==先优先级后结合性==.例:
int res = 10 == 10 > 9;//res = 0

五、流程控制

(1)if选择结构

格式:
if(条件表达式){
    条件成立执行语句
}
其它语句
if(条件表达式){
    条件成立执行语句
}else{
    条件不成立执行语句
}
if(条件表达式){
    条件成立执行语句
}else if(条件表达式){
    条件成立执行语句
}else if(条件表达式){
    条件成立执行语句
}else{
    条件不成立执行语句
}
if可以相互嵌套

(2)switch选择结构

格式:
switch(表达式){ 
    case 表达式1:
      被表达式1控制的语句;
      break;
    case 表达式2:
      被表达式2控制的语句;
      break;
    default:
      被default控制的语句;
      break;
}
  1. case穿透问题
  1. default书写位置可以随便写(尽量写在最后)
  2. switch后()里只能放表达式/变量/常量,并且是整型或能被提升为整型.例:
switch(num) 
switch(2) 
switch(1 + 1) 
switch(1.1) //报错,小数不能被提升为整型
switch('a') //char本质为int类型
  1. switch的case后面只能放常量/表达式,并且是整型或能被提升为整型.例:
case num //报错
  1. switch的case的值不能重复
switch(2){
    case 1:
    
    case 1://会报错
}
  1. case后不能定义变量,要定义必须加上{}.(作用域混乱)例:
switch(1){
    case 1:
    int num = 666;//会报错
}

switch(1){
    case 1:{
    int num = 666;//没问题
    }
}

(3)循环结构

1.while
while(条件表达式){
    条件满足才执行的代码
}
 while (i <= num) {
            res = res + i;
            i++;
        }
2.dowhile
do{
   被控制的语句 
}while(条件表达式);
//先执行,再判断

-应用场景:验证

3.for
for(初始化表达式;条件表达式;循环后增量表达式){
    被控制的语句;
}
  1. 初始化表达式在循环执行过程中只会执行一次

(4)跳转语句

1.break
  1. 只能用在switch和循环结构中, 离开应用的范围没有任何意义
  2. 作用是跳出循环语句 while , dowhile,,for,switch
  3. 如果循环嵌套的时候,break只会跳出所在(最近的)的循环
  4. 不能离开应用范围,不然会报错.例:
if(1){
printf("随便写点东西\n");
break; 
// 离开应用范围后会报错
}
2.continue
  1. 只能用在循环中,离开应用范围没有任何意义
  2. 作用:跳过本次循环,进入下一次循环
  3. 不能离开应用范围,不然会报
  4. 如果循环嵌套的时候,continue只会跳出所在(最近的)的循环
3.goto
  1. 只能用于在同一个函数中跳转, 可以往前往后跳,只要是在同一个函数中
  2. goto需要配合标签使用(标签可以是任意的名称后面加上:).例:
printf("第一行代码\n");
goto lnj; 
printf("第二行代码\n");
lnj: printf("第三行代码\n"); //直接执行
  1. 一般不使用

注意点

  1. if结构中只有一个{}中的语句会被执行
  2. if省略大括号后只有紧随其后的那条语句才受控制(else只与最近的没有被匹配的if匹配)
  3. {}单独出现代表的是一个代码块.例;
int num = 10;
{
    int num = 18;
    printf("%i\n",num);//18
}
printf("%i\n",num);// 10
  1. 如果if/while省略了{},那么后面不能再定义变量(作用域混乱)
int num = 18;
if(num >= 18)
    int num = 666;
    printf("开网卡");
//看起来num的作用域是从定义的一行到return或}为止.但实际上num只有在if条件满足时才会执行,两者冲突.
  1. 任何值都有真假性
  2. 企业开发中一定不要用==来判断两个小数是否相等,可能会出现精度问题(建议使用 >= <=)
  3. 排序问题:两两比较后,最值会出现在最后
  4. 企业开发中能用if用if
  5. while省略大括号后只有紧随其后的那条语句才受控制
  6. while/if,任何值都有真假性,都可以嵌套其它合法代码
  7. 用于控制while的变量在循环的内部外部都可以使用.控制for的变量只能在循环内使用(企业开发中,能用for就用for)
  8. for和while都可以省略大括号.(省略后只能控制紧随其后的语句,且不能定义变量)
  9. 在企业开发中一般情况下,循环嵌套不会超过两层, 最多不超过三层
  10. 规律:循环嵌套的时候,外循环控制行数, 内循环控制列数
  11. 在企业开发中,但凡遇到需要解决很多行很多列的问题, 就要想到循环嵌套

六、函数

返回值类型 函数名称(形参列表){
被封装到函数中的代码;
}

(1)如何定义函数

  1. 确定形参列表(告诉调用者调用时是否需要传递一些辅助的数据)
  2. 确定返回值和返回值类型(返回的数据是什么类型, 返回值类型就写什么类型)
  3. return的作用之一就是将后面的数据返回给函数的调用者.例:
int getMax(int num1, int num2){
    int max = num1 > num2 ? num1 : num2;
    return max;
}
int main(){
    int a = 10,b = 20;
    int res = getMax(a,b);
    printf("res = %i\n",res);//20
}

(2)函数声明

voide test{};
int main(){
    test ();
    return 0;
}
viode test(){
    printf("test\n");
}
  1. 函数的声明可以声明多次,但函数只实现一次
  2. 返回值是int类型,可以不用编写函数声明(了解)
  3. 函数声明必须写在调用之前

(3)main函数

  1. main函数是系统自动调用的函数,不能手动调用
  2. 系统调用main函数时,默认会传递两个参数:
int main (int argc,const char *argv[]){
    
}
//argc:第二个数组保存数据的个数
//argv:默认保存了一个数据:当前文件的地址.并且可以动态的添加数据
//默认情况下,调用main函数时,回给argv这个数组中存放一个元素
  1. return 0;目的是告诉系统是正常结束的

(4)函数补充

1.分类
2.注意点

(5)递归函数

//求n的阶乘:
int factorial();
int main()
{
    int n = -1;
    printf("请输入一个数n = ?按回车键结束\n");
    scanf("%i",&n);
    setbuf(stdin,NULL);
    int res = factorial(n);
    printf("res = %i\n",res);
    return 0;
}
int factorial(int num){
    if(num == 1){
        return 1;
    }else{
         return factorial(num - 1)*num;
    }
}

注意点:

  1. 函数可以有参数,也可以没有参数.函数的参数可以是零个或多个.
int sum(int a, int b){
    return a + b;
}
  1. 函数可以有返回值,也可以没有返回值(如果函数没有返回值, 那么返回值类型写void).例:
void test(){
    printf("test\n");
}
  1. (即使返回值类型,形参列表不同)函数的==名称也不能相同==
  2. 函数不能嵌套定义
  3. 如果是==基本类型的数据==(int,char,float,double)作为函数的参数,那么在函数内修改形参,不会影响外面实参的值
  4. 在函数内部不能定义和形参同名的变量

七、进制和位运算

(1)进制

  1. 如果用16进制,前面加上0x(%x 输出)
  2. 如果用8进制,前面加上0(%0 输出)
  3. 如果用2进制,前面加上0b
1. 2进制转8进制
从右至左每3位划分为8进制的1位, 不够前面补0
001 100 100
第0位: 100 等于十进制 4
第1位: 100 等于十进制 4
第2位: 001 等于十进制 1
最终结果: 144就是转换为8进制的值
2. 2进制转16进制
从右至左每4位划分为16进制的1位, 不够前面补0
0110 0100
第0位: 0100 等于十进制 4
第1位: 0110 等于十进制 6
最终结果: 64就是转换为16进制的值
3. 其它进制转换为十进制
101101 = (1 * 2 ^ 5) + (0 * 2 ^ 4) + (1 * 2 ^ 3) + (1 * 2 ^ 2) + (0 * 2 ^ 1) + (1 * 2 ^ 0)
          = 32 + 0 + 8 + 4 + 0 + 1
          = 45
          
016  =   (0 * 8 ^ 2) + (1 * 8 ^ 1) + (6 * 8 ^ 0)
        =    0  + 8 + 6
        =    14
        
0x11f =  (1 * 16 ^ 2) + (1 * 16 ^ 1) + (15 * 16 ^ 0)
         =   256  + 16 + 15
         =   287
4.十进制快速转换为其它进制
十进制        -->     二进制
   100          -->    1100100
   100 / 2   = 50     0
   50  / 2   = 25     0
   25  / 2   = 12     1
   12  / 2   = 6      0
   6   / 2   = 3      0
   3   / 2   = 1      1
   1   / 2   = 0      1
   
   
   十进制        -->     八进制
   100          -->     144
   100 / 8    = 12    4
   12  / 8    = 1     4
   1   / 8    = 0     1
   
   十进制        -->     十六进制
   100          --> 64
   100 / 16   =  6    4
   6   / 16   =  0    6
5. 十进制小数转换为二进制小数
// 整数部分(除2取余)
  12
/  2
------
   6    // 余0
/  2
------
   3    // 余0
/  2
------
   1   // 余1
/  2
------
  0   // 余1
//12 --> 1100
  
// 小数部分(乘2取整数积)
  0.125
*     2
  ------
   0.25  //0
   0.25
*     2
  ------
    0.5  //0
    0.5
*     2
  ------
    1.0  //1
    0.0
// 0.125 --> 0.001

// 12.8125 --> 1100.001
6. 二进制小数转换为十进制小数
// 整数部分(乘以2的n次方, n从0开始)
0 * 2^0 = 0
0 * 2^1 = 0
1 * 2^2 = 4
1 * 2^3 = 8
 // 1100 == 8 + 4 + 0 + 0 == 12

// 小数部分(乘以2的负n次方, n从0开始)
0 * (1/2) = 0
0 * (1/4) = 0
1 * (1/8) = 0.125
// .100 == 0 + 0 + 0.125 == 0.125

// 1100.001  --> 12.125
7.原码反码补码
  1. 正数的原码、反码和补码都是它的二进制.例12:
0000 0000 0000 0000 0000 0000 0000 1100
0000 0000 0000 0000 0000 0000 0000 1100
0000 0000 0000 0000 0000 0000 0000 1100
  1. 负数的原码、反码和补码:
    • 二进制的最高位我们称之为符号位,最高位是0代表是一个正数,最高位是1代表是一个负数
    • 一个负数的原码,是将该负数的二进制最高位变为1
    • 一个负数的反码,是将该数的原码除了符号位以外的其它位取反
    • 一个负数的补码, 就是它的反码 + 1
    • 例:-12的原码,反码,补码:
0000 0000 0000 0000 0000 0000 0000 1100 //12二进制
1000 0000 0000 0000 0000 0000 0000 1100 //-12原码
1111 1111 1111 1111 1111 1111 1111 0011  //-12反码
1111 1111 1111 1111 1111 1111 1111 0100 //-12补码
// 1 - 1; 1 + (-1);
0000 0000 0000 0000 0000 0000 0000 0001 // 1补码
1111 1111 1111 1111 1111 1111 1111 1111 // -1补码
  ---------------------------------------
10000 0000 0000 0000 0000 0000 0000 0000 // 计算结果补码
 0000 0000 0000 0000 0000 0000 0000 0000 //  == 0

(2)位运算

1. & 按位与
9 & 3 = ?
0000 0000 0000 0000 0000 0000 0000 1001 // 9的补码
0000 0000 0000 0000 0000 0000 0000 0011 // 3的补码
-----------------------------------------------
0000 0000 0000 0000 0000 0000 0000 0001 // 1
2. | 按位或

规则: 一真则真

0000 0000 0000 0000 0000 0000 0000 1001 // 9的补码
0000 0000 0000 0000 0000 0000 0000 0011 // 3的补码
-----------------------------------------------
0000 0000 0000 0000 0000 0000 0000 1011
3. ~ 按位取反

规则: 真变假, 假变真

4. ^ 按位异或
0000 0000 0000 0000 0000 0000 0000 1001 // 9的补码
0000 0000 0000 0000 0000 0000 0000 0011 // 3的补码
-------------------------------------------
0000 0000 0000 0000 0000 0000 0000 1010 // 10
int pwd = 123456789;
int res = pwd ^ 998;
printf("加密之前: %i\n", pwd);
printf("加密之后: %i\n", res);
int res2 = res ^ 998;
printf("解密之后: %i\n", res2);
return 0;
5. << 按位左移
 9 << 1
0000 0000 0000 0000 0000 0000 0000 1001 // 位置参考
000 0000 0000 0000 0000 0000 0000 10010 // 9的补码
5. >> 按位右移
1000 0000 0000 0000 0000 0000 0000 1001 // -9源码
1111 1111 1111 1111 1111 1111 1111 0110 // -9反码
1111 1111 1111 1111 1111 1111 1111 0111 // -9补码
//右移后
11111 1111 1111 1111 1111 1111 1111 011 //补码
11111 1111 1111 1111 1111 1111 1111 010 // 右移完毕的结果, 反码
10000 0000 0000 0000 0000 0000 0000 101 // 右移完毕的结果, 源码
void printBinary(char value){
    // int 4 --> 32
    // char 1 --> 8
    // 在企业开发中 , 数字我们称之为魔鬼
int len = sizeof(value) * 8;
for(int i = 0; i < len; i++){
    int temp = (value >> (len - 1 - i)) & 1;
    printf("%i", temp);
    if(((i+ 1) % 4) == 0){
    printf(" ");
    }
}

注意点:

  1. 变量的内存是连续的
  2. 内存地址从大到小(只要定义变量,就会开辟内存空间)
  3. 计算机会从内存地址大的开始分配内存(内存寻址从大到小)也就是说先定义的变量内存地址大于后定义的变量
  4. 由于内存寻址是从大到小,所以存储补码也是从大到小(也就是从高位开始存储)
//高位         -->           低位
00000000 00000000 00000000 00001001
  1. ==变量的地址是所占用内存空间最小的那个地址==

类型说明符

  1. 说明长度的:
short int//2个字节
long//32位编译器中4个字节,64位8个字节
long long//8个字节
short num1 = 123; // short == short int
long num2 = 123; // long  == long int
  1. 说明符号位的

注意点:

  1. c语言的rand函数是一个伪随机数.(生成随机数)例:
//先导入:#include();
srand(time(NULL));//种一个种子
int res = rand();
  1. 三目是一个运算符,所以必须有结果(结果A和结果B的位置放的必须是变量,常量, 表达式)(如果放的是一个函数, 那么这个函数必须有返回值)
  2. 企业开发中,尽量不要写数字
  3. %p是专门用于输出变量地址的
  4. &是专门用于取出变量地址
  5. C语言的规则:不看怎么存只看怎么取
上一篇下一篇

猜你喜欢

热点阅读