目录
三.数组
1.数组的创建和初始化
数组初始化语法:
type_t arr_name [const_n];
(注:数组创建,在C99标准之前, [] 中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念,变长数组初始化的元素个数必须与数组的长度相匹配。)
int a; //如果a是全局变量则在静态区创建变量初始化为0,否则在栈区初始化为随机值。
int arr[]; //未初始化,是随机值。
初始化方法:
int arr1[10] = {1,2,3};// 不完全初始化,其他元素默认初始化为0
int arr2[] = {1,2,3,4};// 编译器自动分配4个int大小的数组
int arr3[5] = {1,2,3,4,5};
char arr4[3] = {'a',98,'c'};// b的ASCII码值是98,98与‘b’等价
char arr5[] = {'a','b','c'};// 初始化为包含a,b,c,d,'\0'四个字符的数组,4个字节大小。
char arr6[] = "abcdef";// 初始化的时候数组会多一个元素,最后一个元素是\0
// 二维数组初始化时行可省略,列不可省略。
int arr2[][5]={{1,2},{4,5},{5,6}};
2.数组在内存中的存储
3.数组传参
int main(void){
int arr[10]={0,3,42,434,32,323,3234,1215,123,888};
printf("给定10个数字,进行升序排列: \n");
int sz=sizeof(arr)/sizeof(arr[0]);
int q=0;
for(int i=0;i<=sz-1;i++){
for(int q=0;q<=sz-1-i;q++){
//一轮
if(arr[q]>arr[q+1]){
int tmp=0;
tmp=arr[q+1];
arr[q+1]=arr[q];
arr[q]=tmp;
}
//一轮冒泡排序
}
}
for(int i=0;i<=sz-1;i++){
printf("%d \n",arr[i]);
}
return 0;
}
四.操作符
操作符分为:以下几种。
1.算术操作符 + - * / %
2.移位操作符
注:整数的二进制表示有原码,反码,补码三种,最高位是符号位,整数在内存中存储的是补码的形式,打印出的是原码形式。
若将int a=-5左移一位则是:
转化为原码是10000000 00000000 00000000 00001010是-10,打印a得到的是-10(打印值打印的是原码)。
对右移操作符而言, 有两种情况:
一种是算术右移,右丢弃,左补原符号位。
另一种逻辑右移,右丢弃,左补0,采用哪种移位取决于编译器,在vs2022采用的是算术右移。
3.位操作符
& //按位与
例如a=3,b=-5,c=a&b;
| //按位或
^ //按位异或
a=a^b;
4.赋值操作符 =
注意:
连续赋值:a = x = y+1; // 避免使用连续赋值,因为代码可读性差
复合赋值符:
5.单目操作符
如下:
! 逻辑反操作- 负值+ 正值& 取地址sizeof 操作数的类型长度(以字节为单位)~ 对一个数的二进制补码按位取反-- 前置、后置--(前置就先--再使用,后置--则相反)++ 前置、后置++* 间接访问操作符(也就是解引用操作符)(类型) 强制类型转换
注意:1.sizeof求变量内存空间大小时括号可省略,求类型时不能,这表明sizeof不是函数2.sizeof(数组名)求的是数组空间的总大小3.sizeof(s=a+2)求s所占空间大小,sizeof括号中表达式实际不运算,即s没变化,原因是sizeof在编译期间已计算了s所占空间大小,可以理解为被替换为非负整数了,运行期间不再运算。
6.关系操作符
> 大于>= 大于或等于< 小于<= 小于或等于!= 判断“不相等”== 判断“相等”
7.逻辑操作符
&& 逻辑与(意思是并且,如果左操作数逻辑为假,就不执行右操作数)|| 逻辑或(意思是或者,如果左操作数逻辑为真,就不执行右操作数)
8.条件操作符
又叫三目操作符,因为有三个操作数。
exp1 ? exp2 : exp3
表达式一为真时返回表达式2的结果,否则返回表达式3的结果。
9.逗号表达式
a = get_val();
count_val(a);
while (a > 0)
{
//业务处理
a = get_val();
count_val(a);
}
while (a = get_val(), count_val(a), a>0)
{
//业务处理
}
10.下标引用、函数调用和结构成员
1. [ ] 下标引用操作符
2. ( ) 函数调用操作符
3. . 和-> 操作符:访问一个结构体的成员
用法
. :结构体.成员名-> :结构体指针->成员名
struct student{
char name[20];
char sex[5];
int age;
};
struct student s = {name1,male,20};
char n1[20] = s.name; //使用.访问结构体成员
char*p = &s;
char s1[5] = p->sex; //使用->访问结构体成员,即用指针访问结构体成员,p是指针
int a1 = p->age; //使用->访问结构体成员,即用指针访问结构体成员,p是指针
隐式类型转换
什么是整形提升?为什么要整形提升?
什么是截断?
在C语言中,将int类型数据存入char类型变量会发生截断(truncation)操作。由于char类型的存储空间较小,通常只有一个字节(8位),而int类型的存储空间通常为4个字节(32位),因此将int类型数据存入char类型变量时,会将int类型数据的高位字节截断,只保留最低位的字节。
具体来说,将int类型数据存入char类型变量时,会将int类型数据的最低位字节复制到char类型变量中,而高位字节将被丢弃。
注意:截断时先将原数转为补码再进行截断。
int main()
{
char c = 1;
printf("%u\n", sizeof(c));
printf("%u\n", sizeof(+c));
printf("%u\n", sizeof(-c));
return 0;
}
+和-会将c整形提升为int类型,故打印结果为:
寻常算术转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。
下面的层次体系称为寻常算术转换:
long doubledoublefloatunsigned long intlong intunsigned intint
复杂表达式的求值
注意:非法代码如下(未定义行为)//表达式1,只能保证,*的计算是比+早,但是优先级并不能决定第三个*比第一个+早执行。a*b + c*d + e*f//表达式2,左操作数获取在--前还是--后不确定c + --c;//表达式3,错误代码i = i-- - --i * ( i = -3 ) * i++ + ++i