C语言知识点 – 2
文章目录
一、函数
1.数组传参
数组在传参是,传递的是首元素的地址,而不是整个数组;
数组传参时不能在函数内计算数组大小,只能由外部传进来。
代码如下:
void Test(int arr[], int sz)
//相当于void Test(int* arr, int sz)
{
int size = sizeof(arr) / sizeof(arr[0]);
//由于arr是数组的地址,sizeof(arr)计算的就是指针的大小
//因此数组传参时不能在函数内计算数组大小,只能由外部传进来
}
2.静态库
使用别人的函数模块,只包含.h文件,不暴露.c文件。
具体操作如下:
1.编辑好函数后,生成静态库,右键点击项目 – 属性 – 常规 – 配置类型 – 应用程序 – 静态库;
2.点击生成解决方案,生成.lib文件,在DeBug文件夹中;
3.拷贝到需要使用的工程中,添加头文件 – 现有项 – __.h文件,然后在工程中包含.h文件;
4.导入静态库:#pragma comment(lib, “binary_search.lib”).
#include "binary_search.h"//包含头文件
#pragma comment(lib, "binary_search.lib")//导入静态库
3.函数递归
int factorial(int x)
{
if (x <= 1)
{
return 1;//若n小于等于1,则返回1
}
else
{
return x * factorial(x - 1);//若n大于1,则递归调用
}
}
2.斐波那契数列
int fib(int x)
{
if (x <= 2)//若n小于等于2,则返回1
{
return 1;
}
else
{
return fib(x - 1) + fib(x - 2);//若n大于2,则递归调用
}
3.求字符串长度
int my_strlen(char* str)
{
if ('\0' == *str)
{
return 0;//若第一个字符为\0,就返回0
}
else
{
return 1 + my_strlen(str + 1);//若第一个字符不是\0,就递归调用
}
4.字符串反转
实现:将参数字符串中的字符反向排列,不是逆序打印。
void reverse_string(char* arr)
{
int len = strlen(arr);//字符串长度
char tmp = *arr;//tmp为第一个字符
*arr = *(arr + len - 1);//第一个字符变为最后一个字符
*(arr + len - 1) = '\0';//最后一个字符先赋值\0
if (strlen(arr + 1) >= 2)//如果arr+1指向的字符串长度大于等于2,就递归调用
reverse_string(arr + 1);
*(arr + len - 1) = tmp;//最后将第一个字符给到最后一个的位置
}
//fbcde\0 tmp = a --> fedcba
//fecd\0\0 tmp = b --> fedcb\0
//fed\0\0\0 tmp = c --> fedc\0\0
二、数组
1.数组在内存中的存放
数组在内存中是连续存放的。
2.二维数组的初始化
二维数组如果初始化,行可以省略,列不能省略,根据初始化内容来确定行数。
int arr[][3] = {1,2,3,4,5};
int arr[][2] = {{1, 2}, {3,4}};
3.二维数组行和列的计算
int arr[][3] = {1,2,3,4,5};
int row = sizeof(arr) / sizeof(arr[0]);
int col = sizeof(arr[0]) / sizeof(arr[0][0]);
4.数组名
数组名是首元素的地址,但是有两个例外:
1.sizeof(数组名)计算的是整个数组的大小,此时数组名代表整个数组;
2.&数组名,取到的是整个数组的地址。
三、操作符
1. / 和 %
float a = 5 / 4;//要想/结果是浮点数,/两边必须有一个是浮点数,否则结果就是整数
float b = 5.0 / 4;
除了%两边都需要为整数外,其他的算术运算符两边可以是整数或浮点数。
2.原码、反码、补码
正整数的原码、反码、补码都是一样的;
负整数的反码是原码除了符号位外按位取反,补码是反码加一;
3.移位操作符
左移操作符<< : 操作数为二进制整数,左边抛弃,右边补0;
右移操作符>> : 算数右移:左边用符号位填充,右边丢弃(vs为算术右移);
逻辑右移:左边补0;右边丢弃。
4.位操作符
都是对补码进行运算,操作数必须为整数;
& : 按位与;
| :按位或;
^ :按位异或。
不创建临时变量,实现两数的交换:
a = a ^ b;
b = a ^ b;//b = a ^ b ^ b,自己异或为0,a和0异或为a
a = a ^ b;
求二进制数中1的个数:
1.循环右移法
int Count1(int n)
{
int i = 0;
int count = 0;
for (i = 0; i < 32; i++)
{
if (1 == ((n >> i) & 1))
{
count++;
}
}
return count;
}
2.公式法
//n = n & (n - 1)这个表达式每次会减少一个二进制数n中的1
int Count1(int n)
{
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
return count;
}
5.单目操作符
-
! :逻辑反操作;
-
:按位取反;
(类型) :强制类型传唤。
对一个数的二进制位取反:
打印出来是原码。
6.整型提升
C的算术型运算总是至少以缺省整形的精度来进行的,为获得这个精度,表达式中的字符型和短整型操作数在计算之前被转换为普通整形,这就叫做整型提升。
规则:有符号数的整型提升按照符号位来,无符号数直接补0。
char a = -1;
//a的二进制补码为11111111,符合号为为1,则整型提升后前面的位全部补1
//结果为:11111111111111111111111111111111
实例1:
int main()
{
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if(a == oxb6)
printf("%a");
if(b == oxb600)
printf("b");
if(c == 0xb6000000)
printf("c");
return 0;
}
由于 == 也是运算,所以a、b均发生了整型提升,而a和b的符号位均为1,整型提升后为负数,其补码就变了,而c是整形,不需要整型提升,所以结果输出c。
实例2:
int main()
{
char c1 = 3;//赋值也是运算符
//3的补码:00000000000000000000000000000011
//c1中只能存8位:000000011
char c2 = 127'
//127 : 00000000000000000000000001111111;
//c2 : 01111111
char c3 = c1 + c2;
//发生整型提升
//c1 : 00000000000000000000000000000011
//c2 : 00000000000000000000000001111111
//相加:00000000000000000000000010000010
//c3 : 10000010
printf("%d", c3);
//以%d形式打印,又要整型提升
//补码:11111111111111111111111110000010b
//反码:11111111111111111111111110000001b
//原码:00000000000000000000000001111110b -- -126d
}
//最终打印结果为 -126