int a = 100; int b = 200; sum = Add(a, b) //f(x) = 2*x+1 //f(x,y) = x+y
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
intAdd(int x, int y) { int z = x+y; return z; } intmain() { int num1 = 10; int num2 = 20 ; int sum = 0; int a = 100; int b = 200; sum = Add(num1,num2) sum = Add(a,b) printf("SUM = %d\n" , sum) return0; }
16.自定义函数
17.数组
一组相同元素的集合
数组的大小要拿常量来指定
1 2 3 4 5 6 7 8 9 10 11 12 13 14
intmain() { //int a = 1; // int b = 2; //int c = 3; //int 4 = 4; int arr[10] = {1,2,3,4,5,6,7,8,9,10}; //定义一个存放10个整数数字的数组 //char ch[20]; // float arr2[5]; return0;
intmain() { int a = 1; //整型1站四个字节 ——32个bit位 //000000000000000000000000000000001 //四个字节放的就是这个二进制序列 //左边丢弃右边补零 }
(3)位操作符
这个位还是二进制位
&按位与
|按位或
^按位异或
1 2 3 4 5 6 7 8 9 10 11 12
//按位与 //--对应的二进制要与(并且)一下 //c语言中0为假,非0就是真 intmain() { int a = 3; //011 int b = 5; //101 int c = a&b; //001 //只有两个都为1按位与出来才是1 printf("%d\n",c); } 输出结果为 //1(1) (换为十进制)
1 2 3 4 5 6 7 8 9 10
//按位或 intmain() { int a = 3; //011 int b = 5; //101 int c = a|b; //111 //只要有一个不是0按位或出来就是1 printf("%d\n",c); } 输出结果为//7
1 2 3 4 5 6 7 8 9 10 11 12
//按位异或 //计算规律 对应的二进制位相同则为0 // 对应的二进制位相异则为1 intmain() { int a = 3; //011 int b = 5; //101 int c = a|b; //110 printf("%d\n",c); } 输出结果为//6
(4)赋值操作符
[1]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
intmain() { int a =10; a = 20;//赋值 // ==判断相等 //a = a+10; (给a加10在赋给a)等价于 //a += 10; 例子 //a = a - 20; a -= 20 ; //a = a & 2; a &= 2; return0; //符合赋值符 //+= -= *= ...... }
(5)单目操作符
双目操作符
三目操作符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
intmain() { int a = 10; int b = 10; a + b;//+双目操作符 return0; !---逻辑反操作 int a = 10; //在c语言中我们表示真假 //0 表示假 一切非0 表示真 printf("%d\n"!a ) //为真 固定输出为一个数字1 }
sizeof 计算的是变量/类型所占空间的大小
单位是字节
sizeof 计算int不可省略括号 计算a可以省略括号
~对一个数的二进制进行按位取反
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#include<stdio.h> intmain() { int a = 0;//四个字节 32bit int b = ~a; //按位(二进制位)取反 //1010 变成 //0101 printf("%d\n",b); return0; } //原码 反码 补码 //负数在内存中存储的时候,存储的是二进制的补码 //使用的打印的是这个数的原码 //先补码-1得到反码 ,反码按位取反变成原码
– ++
1 2 3 4 5 6 7 8 9 10 11
//-- ++ (--++的值都是1 ) #include<stdio.h> intmain() { int a = 10; int b = a++;//后置++,先使用,再++ // int b = ++a;前置++,先++,再使用 //后置-- 先使用 再-- printf("a = %d\n b = %d\n", a ,b); return0 ; }
1
// *
1 2 3 4 5 6 7 8 9
//(类型)---强制类型转换 #include<stido.h> intmain() { int a = (int) 3.14;//我要把3.14强制转换 3.14是double类型的 //这里让他强制转化为int型的 return0; }
(6)关系操作符
比较大小 看关系是什么
大于等于>=
不等于!=
(7)逻辑操作符
1 2 3 4 5 6 7 8 9 10 11 12 13 14
//&&逻辑与 必须两个都是非0的 一0一非0输出也为0 #include<stido.h> intmain() { //真 -非0 //假 - 0 // int a = 3; int b = 5; int c = a&&b; printf("c = &d\n",c); return0; } //
1 2 3 4 5 6 7 8 9 10 11 12
//||逻辑或 a和b里有一个为真就行 //他俩都为假的时候才为假 都是真的那都是真的 #include<stdio.h> intmain() { int a = 10; int b = 0; int c = a||b; return0; }
// exp1? exp2 : exp3; #inculde <stdio.h> intmain() { int a = 100; int b = 20; int max = 0;//存储 max = (a > b ? a : b ) //如果a>b这个表达式的结果为真 //则max 为a 不管如何max都放的是ab的等较大值 if (a > b) max = a ; else max = b ; return0; }
#include<stdio.h> intAdd( int x, int y) { int z =0; z = x + y; return z; } intmain() { int a = 10; int b = 20; int sum = ADD(a,b); //()-函数调用操作符 return0;
#include<stdio.h> intMax(int x, int y)//接收a b { //大括号为函数体 if ( x > y ) return x; else return y; } intmain() { int a = 10; int b = 20; int max = 0; max = Max(a,b); //定义一个名为Max的函数 printf("max = %d\n",max); return0 ; }
#include<stdio.h> intmain() { int a = 10;//局部变量-自动变量(省略auto) return0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14
//register #include<stdio.h> intmain() { // register int a =10; //建议把a定义成寄存器变量 int a = 10; a = -2; int 定义的变量是有符号的 (signed) int ; unsignedint num = 0; 无符号为没有正负 return0; }
//static修饰函数也是改变了函数的作用域 //这种说法不准确 //正确说法是 //static修饰函数 改变了函数的链接属性 //外部链接属性==>内部链接属性 #include<stdio.h> //在外部 static int Add(int x, int y) // z = x + y; // return z; 声明外部函数 externintAdd(int,int); intmain() { int a = 10; int b = 20; int sum = Add(a,b); printf("sum = %d\n") return0; }
//不考虑溢出的情况 #include<stdio.h> intmain(void) { int i = 0; int n = 0; int ret = 1; printf("请输入一个整数:"); scanf("%d",&n); for(i = 1;i <= n ;i++) { ret = ret * i; } printf("ret = %d",ret); return0; }
#include<stdio.h> intmain(void) { int i = 0; int n = 0; int ret = 1; int sum = 0; printf("请输入10:"); scanf("%d",&n); for(n =1 ;n<=10;n++) { for(i = 1;i <= n ;i++) { ret = ret * i; } sum = sum + ret; } printf("sum = %d",sum); return0; }
#include<stdio.h> intmain(void) { int a = 0; int b = 0; int c = 0; printf(" 请输入三个数:"); scanf("%d%d%d",&a,&b,&c); //算法实现 //a中放最大值 b次之 C中放最小值 if(a<b) { //临时变量 防止在将a的值赋给b时,a的值丢失 int tmp = a; a = b; b = tem; } if(a<c) { int tmp = a; a = c ; c = tmp; } printf("%d %d %d\n", a, b, c); return0; }
7.打印1~100所有3的倍数
1 2 3 4 5 6 7 8 9 10 11 12 13
#include<stdio.h> intmain(void) { int i = 0; for(int i = 1;i <= 100;i++) { if(i%3 == 0) { printf("%d",i); } } return0; }
8.给定两个数求最大公约数
辗转相除法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#include<stdio.h> intmain(void) { int n,r,m; printf("请输入两个大于零的整数:"); scanf("%d %d", &m, &n); while (r = m%n) { m = n; n = r; } printf("%d\n", n); return0; }
9.打印1000~2000的闰年
1判断闰年的方法,能被4整除且不能被100整除
2能被400整除是闰年
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#include<stdio.h> intmain(void) { int year; for (int year = 1000; year <= 2000; year++) { if (year % 4 == 0 && year % 100 != 0) { printf("%d\n", year); } elseif (year % 400 == 0) { printf("%d\n", year); } } return0; }
//什么是水仙花数字——三位上的数字的立方和等于这个数字 //步骤;寻找100~999之间的数字,分解整数,并且验证每个数的平方,最后输出是水仙花数字的数 #include<stdio.h> intmain(void) { int num, bai, shi, ge;//定义这个数字和他的百位,十位,个位,为整形 printf("水仙花数有:\n"); for (num = 100; num < 1000; num++)//定义数的区间——保证为三位数 { bai = num / 100;//求出百位上的数 shi = (num - bai * 100) / 10;//求出十位上面的数 ge = num % 10;//求模——余数 //验证个十百位上的立方和是否等于这个数 if (num == bai*bai*bai +shi*shi*shi+ge*ge*ge) printf("%d\n", num); } return0; }
#include<stdio.h> //定义函数 get_max(int x , int y) { if(x > y ) return x; else return y; } intmain(void) { int a = 10; int b = 20; //函数的使用 //a传给x,b传给y //传过去什么就用什么接收 int max = get_max(a,b); printf("max = %d\n",max); return0; }
(2)写一个函数可以交换连个整型变量的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14
//错误示范——在主函数中实现两个整型变量的交换 #include<stdio.h> intmain(void) { int a = 10; int b = 20; int c = 0; printf("a = %d b = %d\n",a,b); c = a; a = b; b = c; printf("a = %d b = %d\n",a,b); return0; }
//定义函数但是失败了的示范 #include<stdio.h> //自定义函数 //前面加上void意思是此函数没有返回值 //什么类型就用什么类型接收 voidexchange(int x, int y) { //定义一个临时变量用于交换 int c = 0; c = x; x = y; y = c; //此时执行失败,在这个定义函数的区块中,交换是成功了,但是x和a,y和b //两组之间没有联系 } intmain(void) { int a = 10; int b = 20; printf("a = %d b = %d\n", a, b); //函数的使用 exchange = (a, b); printf("a = %d b = %d\n", a, b); return0; }
1 2 3 4 5 6 7 8 9 10 11 12 13
//正确示范 #include<stdio.h> voidexchange(int x,int y) { } intmain(void) { int a = 10; int b = 20; printf("a = %d b = %d\n",a,b); return0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
//在这里引入指针的概念 #include<stdio.h> intmain(void) { int a = 10; int *pa = &a;//pa的类型就是int* ,指针变量 //pa里面存的是a的地址 //加个*意思是解引用操作 *pa;//对pa进行解引用操作的意思是,通过pa里面存的这个地址, //找到它所指向的内容,那这个*pa就是a, //如果给 20 *pa = 20; //就借助这个指针变量把a的值改成了20 printf("%d\n", a); //也就是说,如果要改变a的值,不用a亲自动手,指针变量也可以修改 // return0; }
intnumber_search(int arr[], int k) { //算法实现 int sz = sizeof(arr) / sizeof(arr[0]); int left = 0;//左下标 int right = sz - 1 ;//右下标 //放到循环中 while (left <= right)//这样才说明中间是有元素可以被查找的 { int mid = (right + left) / 2;//中间元素的下标 //拿到这个mid——锁定个元素 if (arr[mid] < k)//如果中间元素比我要找的k要小, //被查找范围的右下标不用变,左下标变成mid+! { left = mid + 1; } elseif (arr[mid] > k) { right = mid - 1; } else { return mid; } //如果找不到 return-1;//返回去了 } }
intmain(void) { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; int k = 7; int ret = number_search(arr, k); if (ret == -1) { printf("找不到指定的数字\n"); } else { printf("找到了,下标是:%d\n",ret); } return0; }
#include<stdio.h> //函数声明 //在这个函数声明中的x和y是可以省略掉的,因为我们根本就不回去用他 intAdd(int x, int y); intmain(void) { int a = 10; int b = 20; int sum = 0; //函调用 sum = Add(a, b); printf("%d", sum); return0; } //这时候把函数定义放到主函数的下面 //程序会报错——“Add未定义” //虽然定义了但是程序并不知道 //这里就需要在主函数前面进行一个声明——函数声明 Add(int x, int y) { int z = x + y; return z; } //这样写是比较啰嗦的
在add.h(头文件)文件中 //写函数声明 #ifndef _ADD_H //如果没有定义过后面那个符号 //那就先定义一下define //如果定义过了,就为假 //下面的代码就不要了 //防止用一个头文件被引用多次 #define _ADD_H intAdd(int ,int); #endif 在add.C文件中 //写函数的定义 intAdd(int x, int y) { int z = x + y; return z; } 在test.c文件中 //直接进行用这个上面定义的加法函数 #include<stdio.h> #include"add.h" int main(void) { int a = 10; int b = 20; int sum = 0; sum = Add(a,b); printf("%d",sum); } //为什么要这么弄呢? //如果吧所有的代码函数都放到同一个test.c文件中 //项目组十个人分工,布置任务 //没法同时都在一个test.c文件中工作, //这样分开工作,最后include引用,组合在一起 //功能复杂——分模块写
//计算n的阶乘——使用函数 //jiecheng这个函数没用递归 #include<stdio.h> intjiecheng(int z) { int i = 0; int ji = 1; for (i = 1; i <= z; i++) { ji = ji * i; } return ji; } //运用递归函数 intjiecheng2(int z) { if (z <= 1) return1; else return z * jiecheng2(z - 1); } intmain(void) { int n = 0; int ret = 0; printf("请输入一个数:"); scanf_s("%d",&n); ret = jiecheng2(n); printf("上面这个数的阶乘是:%d",ret); return0; }
上面递归的方法进行了太多的重复计算 这个用循环的方法 //解释 // 1 1 2 3 5 8 13 21 43 55 //为了避免计算重复的是 //假设把第一个数的值赋给a,第二个数的值赋给b, //将a+b的值赋给c //循环往复 //其中前两个一加赋给第三个 //计算斐波那契数是从第三个开始 //创建循环的条件 #include<stdio.h> intfbn(int z) { int a = 1; int b = 1; //这是前两个斐波那契数 int c = 0; //计算斐波那契数从第三个数开始 while (z > 2) { c = a + b; a = b; b = c; z--; } return c; } intmain(void) { int n = 0; int ret = 0; scanf_s("%d", &n); ret = fbn(n); printf("第%d个斐波那契数%d", n,ret); return0; }
#include<stdio.h> intmain(void) { char arr[] = "abcdefe";//这里面放了[a] [b][c][d][e][f][\0] /*printf("%c\n", arr[3]);*///输出字符串中的第三个字符 //这里的[]就是下标引用操作符 int i = 0; int len = strlen(arr); for (i = 0; i < 6; i++) //下面这个同上 // for(i = 0; i <(int)strlen(arr);i++) //for(i = 0; i< lenli++) { printf("%c ", arr[i]);//输出abcdef } return0; }
1 2 3 4 5 6 7 8 9 10 11 12
#include<stdio.h> intmain(void) { char arr[] = {1,2,3,4,5,6,7,8,9,0}; int sz = sizeof(arr)/sizeof(arr)[0]; int i = 0; for(i = 0;i < sz ;i++) { printf("%c",sz); } return0; }
总结:
数组其实是用下标来访问的,下标是从0开始的。
数组的大小可以通过计算来得到。
3.一维数组在内存中的存储
一维数组在内存中的排布
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#include<stdio.h> intmain(void) { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; int sz = sizeof(arr) / sizeof(arr[0]); int i = 0; for (i = 0; i < sz; i++) { //输出此一维数组在内存中的排布情况 printf("&arr[%d] = %p\n", i, &arr[i]); //在内存中连续开辟空间来存放1~10 //数组在内存中是连续存放的 } return0; }
数组在内存中是连续存放的
4.二维数组的创建和初始化
二维数组的创建
1 2 3 4 5 6 7
数组的创建 //3行4列的二维数组 int arr[3][4]; //3行5列 char arr[3][5]; //2行4列 double arr[2][4];
二维数组的初始化
1 2 3 4
//这里创建一个3行4列的二维数组 //在第一行存放123没有初始化的位置放置0 //在第二行放置45,没有初始化的位置放置0 int arr[3][4] = {{1,2,3},{4,5}};
//左移 #include<stdio.h> intmain(void) { int a = 5; int b = a << 1; //5的二进制表示是101 //0000000000000000000000000000000101 //经过向左移动左边补0后,当前的数字从5变成了10 return0;
位操作符
只能作用到整数上去
注意:他们的操作符数必须是整数
&-按位与
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#include<stdio.h> intmain(void) { //&-按位与-按二进制位与 int a = 3; int b = 5; int c = a & b; //拿到的都是这个数的补码 //00000000000000000000000000000011 //00000000000000000000000000000101 //整型占32个比特位 //00000000000000000000000000000001 //有一个为0就是0,两个都是1 才是1 printf("%d\n", c); return0; }
|-按位或
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#include<stdio.h> intmain(void) { int a = 3; int b = 5; int c = a & b; //拿到的都是这个数的补码 //00000000000000000000000000000011 //00000000000000000000000000000101 //00000000000000000000000000000111 //有一个为1就是1,两个都是1 也是1 printf("%d\n", c); return0; }
^-按位异或-按二进制位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#include<stdio.h> intmain(void) { //&-按位与-按二进制位与 int a = 3; int b = 5; int c = a & b; //拿到的都是这个数的补码 //00000000000000000000000000000011 //00000000000000000000000000000101 //00000000000000000000000000000110 //对应的二进制如果相同为0,相异为1 printf("%d\n", c); return0; }
一道变态的面试题目
不创建临时变量(第三个变量)实现两个数的交换
1
不创建临时变量(第三个变量)实现两个数的交换
1 2 3 4 5 6 7 8 9 10 11 12 13 14
先来一个创建临时变量的 #include<stdio.h> intmain(void) { int a = 10; int b = 20; int c = 0;//创建c为临时变量 printf("交换之前:a=%d,b=%d\n", a, b); c = a; a = b; b = c; printf("交换之后:a=%d,b=%d\n", a, b ); return0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
加减法 //缺陷 //当他们特别大的时候,没有超过最大值,但是加在一起的时候超过,必然就会有一些二进位丢失,就还原不出来了,缺陷——可能会溢出 #include<stdio.h> intmain(void) { int a = 10; int b = 20; printf("交换之前:a=%d,b=%d\n", a, b); a = a ^ b; b = a ^ b; a = a ^ b; printf("交换之后:a=%d,b=%d\n", a, b); return0; }
按位异或 //执行效率不高,可读性比较差 #include<stdio.h> intmain(void) { int a = 10; int b = 20; printf("交换之前:a=%d,b=%d\n", a, b); //整型在内存中战32个比特位 //ab分别用二进制表示 //00000000000000000000000000001010 //00000000000000000000000000010100 //进行三次按位异或——相同为0,相异为1 a = a ^ b; //00000000000000000000000000011110——这个所表示的数是30 //即现在的a变成了30 //*******现在要进行按位异或的ab分别是 //00000000000000000000000000011110 //00000000000000000000000000010100 b = a ^ b; //得到 //00000000000000000000000000001010——这个所表示的数是10 //即现在的b变成了10 //*******现在要进行按位异或的ab分别是 //00000000000000000000000000011110 //00000000000000000000000000001010 a = a ^ b; //得到 //00000000000000000000000000010100——这个所表示的数是20 //即现在的a变成了20 printf("交换之后:a=%d,b=%d\n", a, b); return0; }
编写代码实现求一个整数存储在内存中的二进制中1的个数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#include<stdio.h> intmain(void) { int num = 0; int count = 0; scanf_s("%d", &num); //统计Num的补码中有几个1 while(num) { if (num % 2 == 1) count++; num = num / 2; } printf("%d\n", count); return0; } //代码存在问题,算负数的时候
int a = 10; printf("%d\n",!a);逻辑反操作,此时为假 输出为0 //一般放在if语句中来使用,要根据实际的场景来进行使用
关系操作符
+正值——正号一般都省略掉了
&取地址——一般都和指针配合使用
1
这个东西与下面的解引用操作符是一对,通常会出现在一起
1 2 3 4 5 6 7 8 9
int a = 10; //&取地址操作符 int* p = &a;//p称为指针变量,int*是p的类型 //*p 解引用操作符 *p //通过p里面所存的这个值,来找到它所指向的对象,*p就是它所指向的那个对象a,因为p是指向a的,p里面存了a的地址,所以p是指向a的,现在*p就是a, //现在我这样 *p = 20;//现在a的值变成20了 return0;
*解引用操作符(间接访问操作符)
sizeof操作数的类型长度(以字节为单位)
1 2 3 4 5 6 7 8 9 10 11
int a = 10; //4 char c = 'r'; //1 char* p = &c; // 指针的大小要不是4个字节,要不就是8个字节,与你电脑系统格式32位 还是64位有关, int arr[10] = {0}; // 他是一个数组,里面有十个整型元素,一个整型元素占四个字节,10个整型这里就是 40个字节 //对于数组来说,去掉数组名,剩下的就是他的类型,例如 int crr[40],它叫做crr,去掉他的名字,剩下int[40],这就是他的类型 ************ //可以通过名称来计算大小,也可以通过类型来计算大小 注意:当sizeof后面是类型的时候是不可以省略括号的,当后面是名字的时候是可以省略括号的 //下面sizeof计算的是变量所占内存空间的大小,变量包含数组,单位是字节 printf("%d\n",sizeof(输入你要计算的东西));
1 2 3 4 5 6 7 8 9 10 11 12 13
例题:下面这个代码输出的两个值分别是什么 #include<stdio.h> intmain(void) { short s = 0; int a = 10; printf("%d\n",sizeof(s = a + 5));//无论a是什么,现在放到了s的=后面,就要按着s的规矩来,一个四个字节的a放到s这里来,也只能存两个字节,因为s为短整型,只有两个字节。 printf("%d\n",s);//这个地方输出0,并不意味着这个地方就放不下15,而是因为,sizeof这个操作符放的这个表达式是不会真实计算的,也就是说a+5仅仅是个摆设放在上面中s=的后面, //给我们的感觉是要把一个整型元素放在一个短整型元素中去,这个地方发生截断,但其实这个地方并不会发生截断,sizeof括号中放的这个表达式是不参与直接运算的,s的并没有发生变化,所以s还是0,输出0。 return0; } //输出结果为 0 和 2
#include<stdio.h> intmain( void) { int a = (int)3.15; pinrtf("%d\n",a); return0; }
1
40 10 4 4
关系操作符
比较大小 > >= < <= != ==
区别 = 和==
逻辑操作符
&&逻辑与
逻辑与还具有短路的功能,当式子左边算出为假,那么后面的式子不管什么都不再计算,(后面的不会执行)
其中一个为假, 结果就为假,
两个都为真,结果 为真
1 2 3 4 5 6 7 8 9 10
#include<stdio.h> intmain(void) { int a = 3; int b = 5; int c = a && b: //1为真 0为假 a和b有一个为假 就为假 printf("%d\n",c); return0; }
||逻辑或
一个为真或起来就真,
两个同时为假才为假。
例题:
1 2 3 4 5 6 7 8
#include<stdio.h> intmain(void) { int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ && ++b && d++; printf("a = %d b = %d c = %d d = %d ", a, b, c, d); return0; }
结果:1 2 3 4
1 2
//将上个式子a的值改成1 结果为 2335
1 2 3 4 5 6 7 8 9 10
改成逻辑或 #include<stdio.h> intmain(void) { int i = 0, a =1, b = 2, c = 3, d = 4; i = a++ || ++b || d++; //只要开始为真,整体就为真,后面的不进行运算 printf("a = %d b = %d c = %d d = %d ", a, b, c, d); return0; }
条件操作符(三目操作符)
exp1 ? exp2 :exp3
如果表示式1的结果为真,表达式2要算,表达式2的结果整个表达式的结果,
如果表达式1的结果为假,表达式3要算,表达式3的结果是整个表达式的结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
//如果要实现下面这个代码,转成条件表达式是什么样? if (a > 5) b = 3; else b = -3; //**************************************************** #include<stdio.h> intmain(void) {
int a = 0; int b = 0; scanf_s("%d",&a); b = (a > 5 ? 3 : -3); printf("%d", b); return0; }
练习:使用条件表达式得到两个的数较大值
1 2 3 4 5 6 7 8 9 10
#include<stdio.h> intmain(void) { int a = 0, b = 0, c = 0; printf("请输入两个数:\n"); scanf_s("%d %d", &a, &b); c = (a > b ? a : b); printf("较大的数为:%d\n", c); return0; }
逗号表达式
exp1, exp2, exp3, …expN
逗号表达式,就是用逗号隔开多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
1 2 3 4 5 6 7 8 9 10 11
//代码1 #incldue<stdio.h> intmain(void) { int a = 1; int b = 2; int c = (a >b ,a = b+10,a,b = a +1); //a > b这个表达式不产生结果 a不产生结果 // return0; }
1 2 3
代码2 if( a = b +1,c= a /2, d > 0 ); //真正起到判断作用的是最后一个d>0,d大于0,条件为真,反之条件为假
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
代码3 a = get_val(); count_val(a); while (a >0) { //这里面上面的代码重复出现了两次,比较啰嗦 //业务处理 a = get_val(); count_val(a); } //如果使用逗号表达式,则为 //逻辑一模一样,重复的代码只出现了一次,使代码更加简洁,但有的时候可能不太容易理解。 while(a = get_val(),count_val(a),a > 0) { //业务处理 }
下标引用、函数调用和结构成员
1.[]下标引用操作符
操作数:一个数组名+一个索引值
1 2 3
int arr [10];//创建数组 arr[9] = 10;//实用下标引用操作符 []的两个操作符是arr和9,一个是数组名,一个是索引值
例子 #incldue<stdio.h> intmain(void) { int a = 10; int b = 20; int c = b + a * 3;//*优先级较高,先进行乘再进行加, //当相邻的操作符不相同的时候,他们就有自己的优先级 //优先级高的先算,优先级低的后算 //若两个操作符相同,那么应该先计算哪个呢? //这时候就引出我们要说的结核性 //从哪边向哪边进行结合, //除了优先级和结核性 //还要看——是否控制求值顺序 return0; }
//将数组中的全部元素,都改成1 #include<stdio.h> intmain(void) { int arr[10] = { 0 }; int * p = arr;//数组名首元素地址 int i = 0; for( i = 0; i < 10 ; i++) { *(p + 1) = 1; } return0; } //如果将上面的p指针类型改成char* //最后的结果不同,因为不同类型的指针大小不同 ******************** 根据你的需求,将地址交给一个合理的指针
3野指针
野指针就是指针指向的位置是不可知的——随机的,不正确的,没有明确限制的
局部变量不初始化,默认是随机值
在内存中随便找了一个位置放了这个随机值的地址。
1 2 3 4 5 6 7 8
#include<stdio.h> intmain(void) { int a ;//局部变量不初始化,默认是随机值 int *p ;//局部的指针变量,就被初始化随机值。 *p = 20; return0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14
一个指针越出了,他所能管理的范围后,他就被成为野指针——指针越界访问 如下: #include<stdio.h> intmain(void) { int arr[10] = { 0}; int *p = arr; int i = 0; for(i = 0;i < 12 : i++) { p++: } retunr 0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
指针指向的那块内存空间释放了——(涉及到动态内存开辟)——延迟的问题 int *test() { int a = 10; // a 为 局部变量,出这个变量就不存在了,这块内存空间就还给了操作系统 return &a; //这里返回的是a在内存中的地址,让下面的int*p来进行接收,但是这里的a是局部变量。 //返回的是局部变量的地址,除了这个局部变量所在的大括号,他所占的这个4个字节就还给内存空间了 } intmain(void) { int *p = test(); *p = 20; return0; }
如何规避野指针
1指针初始化
当未初始化的指针变量进行解引用操作的时候,就是在内存中随便找了个地方,就把地址存到这里了。
初始化,然后再解引用
2小心指针越界(指针越界访问)
3指针指向空间释放,即设置NULL
(这里在动态访问的时候会详解)
NULL是用来初始化指针的,给指针赋值。(int* p = NULL;)空指针
当指针不用的时候,把他设置为空指针,无法访问他的空间,不能用。(在调试程序窗口验证)
4指针使用之前检查有效性
4指针运算
指针加减整数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#include<stdio.h> intmain(void) { int arr[10] = { 1,2,3,4,5,6,7,8,9,10}; int i = 0 int sz = sizeof(arr) / sizeof(arr[0]) int *p = arr; for(i = 0 ; i <sz; i++) { printf("%d".*p); p = p + 1; } return0; }
指针-指针
就是地址-地址
得到的其实是中间的元素个数
相反如果小地址减去大地址,得到的数就是负数。
不同类型的指针无法相减
这两个指针指向的同一块空间
不可预知的,我们也无法知道他的结果
1 2 3 4 5 6 7 8
#inlcude<stdio.h> int main(void) { int arr[10]={1,2,3,4,5,6,7,,9,10}; &arr[9] - &arr[0]; printf return 0; }
int main(void) { int a = 10; int b = 20; int c = 30; int d = 40; int* arr[4] = {&a,&b,&c,&d}; for(i = 0 ; i < 4 ; i ++) { printf("%d",*(arr[i])); } return 0; } //结果输出为10 20 30 40