C语言:《一维数组 二维数组的初始化和使用》, 《操作符详解》 ,《结构体初始化 传参 》《 结构体内存对齐》

本文详细介绍了C语言中的一维和二维数组的创建、初始化及内存存储特性,深入讲解了操作符的用法,包括位操作符、逻辑操作符和逗号表达式,并探讨了整型提升的概念。此外,还讨论了结构体的定义、初始化、成员访问和内存对齐的重要性及规则,以及结构体在函数传参中的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

.
1.一维数组的创建和初始化

int arr1[10];

	int count = 10;
	int arr2[count];// 不能创建数组

	char arr3[10];

数组创建, [] 中要给一个常量才可以,不能使用变量。

char  arr4[]="abc";
char  arr5[3]={'a','b','c'};

双引号里面的是字符串,代表的却是一个指向无名数组起始字符的指针,该数组被双引号之间的字符以及一个额外的二进制值为零的字符‘\0’初始化;而单引号里面的代表字符,字符使用其ASCII码。

数组是使用下标来访问的,下标从0开始。
数组的大小可以计算得到。
2.一维数组在内存中的存储
随着数组下标的增长,元素的地址,也在有规律的递增。 由此可以得出结论:数组在内存中是连续存放的。

二维数组的创建和初始化

int arr[3][4] = { 1, 2, 3, 4 };//  长度为3的一维数组,每个元素又是长度为4
	int arr1[3][4] = { { 1, 2 }, { 3, 4 } };
	int arr2[][4] = { { 2.3 }, { 4, 5 } };

二维数组在内存中的存储
打印二维数组的每个元素

int main()
{
 int arr[3][4];
 int i = 0;
 for(i=0; i<3; i++)
 {
 int j = 0;
 for(j=0; j<4; j++)
 {
 printf("&arr[%d][%d] = %p\n", i, j,&arr[i][j]);
 }
 }
 return 0;
 }

在这里插入图片描述
在这里插入图片描述
数组名
数组名是数组首元素的地址
int arr[10] = {1,2,3,4,5};
printf("%p\n", arr);
printf("%p\n", &arr[0]);
printf("%d\n", *arr)
两个例外: &arr 数组名出现在sizeof之后表示首元素地址

操作符和表达式

位操作符:
& //安位与
| //按位或
^ //按位异或
操作数必须为整数

不创建临时变量交换两个数的值

  int a = 5;
	int b = 6;
	a = a^b;
	b = a^b;
	a = a^b;
	printf("%d  %d", a, b);
	return 0;

逻辑操作符
&& 逻辑与
1&&1=1
1&&0=0
0&&0=0
|| 逻辑或
0||0=0
0||1=1
1||1=1

逗号表达式:
逗号表达式,就是用逗号隔开的多个表达式,从左往右依次执行,整个表达式的结果,是最后一个表达式的结果

整形提升:
C的整型算术运算总是至少以缺省整型类型的精度来进行的。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
char a,b,c;
a=b+c;
b和c的值被提升为普通整型,然后再执行加法运算。加法运算完成之后,结果将被截断,然后再存储于a中。

如何进行整形提升
负数的整形提升:
在这里插入图片描述
正数的整形提升:
在这里插入图片描述
无符号整形提升,高位补0

整形提升的实例:

char a = 0xb6;
	short b = 0xb600;
	int c = 0xb6000000;
	if (a == 0xb6)
	{
		printf("a");
	}
	if (b == 0xb600)
	{
		printf("b");
	}
	if (c == 0xb6000000)
	{
		printf("c");
	}

a,b要进行整形提升,但是c不用,a,b整形提升之后就变成负数,所以a0xb6 b0xb600为假, c不发生整形提升所以 c==0xb6000000为真

实例二:

int main()
{
 char c = 1;
 printf("%u\n", sizeof(c));
 printf("%u\n", sizeof(+c));
 printf("%u\n", sizeof(!c));
 return 0;
}

表达式+c发生整形提升,所以是4个字节,-c也会发生整形提升,但是sizeof©就是一个字节。

结构体
结构体的定义和初始化:
struct point
{
int x;
int y;
}p1; //声明类型的同时定义变量p1
struct point p2; //定义结构体变量p2

结构体成员的访问:

typedef struct stu
{
	char name[20];
	int age;
}stu;
void print(struct stu* ps)
{
	printf("name=%s,age=%d", (*ps).name, (*ps).age);
	//使用结构体指针访问指向对象的成员
	printf("name=%s,age=%d", ps->name, ps->age);
}
int main()
{
	struct stu s= { "wangfan", 22 };
	printf(&s);   //结构体地址传参
	system("pause");
	return 0;
}

结构体传参:

struct S
{
	int data[1000];
	int num;
};
struct S s = { { 1, 2, 3, 4 }, 1000 };
void print1(struct S s)
{
	printf("%d\n", s.num);
}
void print2(struct S* ps)
{
	printf("%d\n", ps->num);
}
int main()
{
	print1(s);
	print2(&s);
	system("pause");
	return 0;
}

函数传参的时候,参数是需要压栈的。 如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。
结构体传参的时候,要传结构体的地址

结构体内存对齐
为什么要进行内存对齐:
1.平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2.性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要做两次内存访问;而对齐的内存访问仅需一次访问。

结构体内存对齐的规则:
1.第一个成员在结构体变量偏移量为0 的地址处。
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数 = 编译器默认的一个对齐数与该成员大小中的较小值。vs中默认值是8 Linux默认值为4.
3.结构体总大小为最大对齐数的整数倍。(每个成员变量都有自己的对齐数)
4.如果嵌套结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包含嵌套结构体的对齐数)的整数倍。
struct S1
{
char c1;
char c2;
int i;
};
printf("%d\n", sizeof(struct S1));

char 为1个字节, int 为4个字节;char c1 从0偏移开始,占用一个字节;现在可用偏移为1偏移,接下来存放 int i ,1不是对齐数4 的整数倍,所以向后继续偏移一直到4,4是对齐数4的整数倍,所以将int i 存放在偏移地址为4处,占用4个字节;现在可用偏移变成8,存放 char c2 ,占一个字节,现处于9偏移。9不是最大对齐数4的整数倍,所以向后继续偏移直到偏移处为12的地方。

struct S2
{
double d;
char c;
int i;
};
printf("%d\n", sizeof(struct S2));
解析:
double 占8个字节, char 占一个字节,int 占4个字节;double d 从0处开始偏移,占用8个字节;现在可用偏移为8,接下来存放 char c ,8是对齐数1的倍数,所以char c 存放在偏移地址为8处,占用一个字节;现在可用偏移变成9,接下来存放 int i ,9不是对齐数4的倍数,所以继续向后偏移到12,12是对齐数4的倍数,所以将 int i 存放在偏移地址为12处,占用4个字节,现处于16偏移,是最大对齐数8的倍数。

结构体嵌套问题:
struct S3
{
char c1;
struct S2 s2;
double d;
};
printf("%d\n", sizeof(struct S3));

char 占一个字节,struct S2 s2 为例2 的结构体,占16个字节,double 占8个字节;char c1 从0处开始偏移,占用一个字节;现在可用偏移为1偏移;接下来存放struct S2 s2 ,1不是对齐数8的整数倍,所以继续向后偏移到8,8是对齐数8 的倍数,所以将结构体s2存放到8偏移处,占用16个字节;现在可用偏移为8+16=24,24是对齐数8的整数倍,所以将 double d 存放到当前的24偏移处,占用8个字节,现处于24+8=32偏移处,32是最大对齐数8的整数倍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值