C语言初阶——指针与结构体

一、指针

1.1 指针是什么

(1)指针是内存中的一个最小单元的编号,也就是地址。

(2)平时口语中的指针,通常情况下指的是指针变量,用来存放内存地址的变量。

(3)指针变量:里面存放的是指针(也就是地址),通过这个地址可以找到一个对应的内存单元。(地址是唯一标识一块地址空间的)

(4)一个内存单元对应一个字节

(5)指针变量的大小取决于一个地址存放的时候需要多大的空间;(见初始C语言部分)

(6)拓展:因为在32位机器上,地址用二进制表示有32位,在日常的使用当中很不方便,所以为了简要表示,在日常生活中我们会将地址进行十六进制转换,也就是二进制每四位对应十六进制一位,这样我们就可以用八位十六进制代替三十二位二进制,大大减少了复杂程度。(0x是十六进制的标志)

例:0x11223344——0001 0001 0010 0010 0011 0011 0100 0100

1.2 指针与指针类型

int main() {
	int a = 0x11223344;//十六进制
	int* pa = &a;
	*pa = 0;
	//结果为:a中11,22,33,44全部都改成了0;
	int b = 0x11223344;
	char* pc = (char*)&b;
	*pc = 0;
	//结果为:b中11,22,33,44,只有11变成了00,其余不变
	return 0;
}

指针类型的意义一:

指针类型决定了指针在被解引用的时候访问几个字节。如果是int*的指针,则访问4个字节;如果是char*的指针,则访问1个字节;

int main() {
	int a = 0x11223344;
	int* pa = &a;
	char* pc = (char*) & a;
	printf(" pa =%p\n", pa);  //0000009B091FFB14
	printf("pa+1=%p\n", pa+1);//0000009B091FFB18
	printf(" pc =%p\n", pc);  //0000009B091FFB14
	printf("pc+1=%p\n", pc+1);//0000009B091FFB15
	return 0;
}

指针类型的意义二:

指针的类型决定了指针进行 + 1和 -1操作的时候(+-整数操作同理),跳过几个字节,即决定了指针的步长。

int main() {
	int a = 0, b = 0;
	int* pi = &a;            //pi解引用访问4个字节,pi+1跳过4个字节;
	float* pf = (float*) & b;//pf解引用访问4个字节,pf+1跳过4个字节;
	*pi = 100;
	*pf = 100.0;
	//当上述两个指令运行的时候,最终a和b中的数据并不相同;
	//因为int*默认存储整型数据,float*默认存储浮点型数据;
	//整型和浮点型数据在内存中的存储上是不同的,对内存的解读方式也是不同的,因此存在差异。
	return 0;
}

1.3 野指针

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

1.3.1 指针未初始化

int main() {
	int* p;
	//p没有初始化,意味着没有明确的指向。
	//一个局部变量没有初始化的话,放的是随机值:0xcccccccc
	*p = 10;//非法访问内存,这里的指针就是野指针
	return 0;
}

1.3.2 数组越界访问

int main() {
	int arr[10] = { 0 };
	int* p = arr;
	int i = 0;
	for (i = 0; i <= 10; i++) {
		*p = i;//会出现数组的越界访问,因为i=10的时候访问i[10],越界了。
		p++;
	}
	return 0;
}

1.3.3 指针指向的内存释放

int* test() {
	int a = 10;
	return &a;
}
//当进入函数之后,把a的地址赋予给指针变量p之后,因为a是局部变量,所以出函数销毁
//此刻p所指向的内存已经释放(销毁),所以此刻的p指针就是野指针。
int main() {
	int* p = test();
	return 0;
}

1.3.4 解决办法

(1)使用空指针null初始化指针,同时在运用指针之前进行判断指针是不是空指针,如果不是再使用。(使用空指针会导致程序崩溃)

(2)小心指针越界;

(3)小心指针指向的空间释放;

(4)避免返回局部变量的地址;

(5)指针还用之前检查有效性。

二、指针运算

2.1 指针+-整数

#define N 5
int main() {
	float arr[N];
	float* p;
	for (p = &arr[0]; p < &arr[N];) {
		*p++ = 0;
		// *p = 0 ;
		// p++;
	}
	return 0;
}

2.2 指针-指针

指针-指针表示的是指针和指针之间元素的个数;不是所有的指针都能相减,只有指向同一个空间的指针才能相减(这样的减法才有意义)

2.3 指针的关系运算

指针和指针是可以进行比较的,比如数组中循环时,可以用最后一个元素的地址当做限制条件,但是要记住标准规定了:

允许指向数组元素的指针与指向数组最后一个元素后面那个内存位置的指针进行比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

三、结构体

3.1 结构体的声明

结构是一些值的集合,这些值被称为成员变量。结构体的每个成员可以是不同类型的变量。

(1)结构体类型的声明:

struct  tag{                            结构体关键字   结构体标签(可以看做是结构体名){

      member-list;                        成员列表(包含数据类型+成员名,如:char name[])

}variable-list;                         }变量列表(变量列表可有可无,一般都不加)

(2)结构体变量的创建:

struct tag a = { 0 } ;

#include<stdio.h>

struct Stu {
	char name[10];
	char sex[5];
	char num[10];
};

struct Grp {
	struct Stu p;
	int chinese;
	int math;
	int english;
};
//支持结构体中继承另一个结构体,类似于c++的类。
int main() {
	struct Stu s1 = { "张三","男","219077889" };
	struct Grp s2 = { "李四","男","219177364",124,143,21 };
	printf("%s %s %s\n", s1.name, s1.sex, s1.num);
	printf("%s %s %s ", s2.p.name, s2.p.sex, s2.p.num);
	printf("%d %d %d\n", s2.chinese, s2.math, s2.english);
	return 0;
}

3.2 结构体传参

在使用结构体的时候,一般不适用printf直接打印,因为在代码编写的过程中可能会多次打印,所以一般会采用函数的形式来进行函数的打印。那么在这个时候就涉及到传参的问题,如下方代码所示两种传参形式和几种对应的打印形式。

#include<stdio.h>

struct Stu {
	char name[10];
	char sex[5];
	char num[10];
};

void print1(struct Stu s) {
	printf("%s %s %s\n", s.name, s.sex, s.num);//第一种
}

void print2(struct Stu* s) {
	printf("%s %s %s\n", s->name, s->sex, s->num);//第二种
	printf("%s %s %s\n", (*s).name, (*s).sex, (*s).num);//第三种
}

int main() {
	struct Stu s1 = { "张三","男","219077889" };
	printf("%s %s %s\n", s1.name, s1.sex, s1.num);//第四种
	print1(s1);
	print2(&s1);

	return 0;
}

(1)注意:在函数传参时,参数是需要进行压栈的。如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销较大,所以会导致性能的下降。

因此,使用第二种,传递参数,并且使用s->name的形式更加好。

(2)结论:结构体传参的时候,要传递结构体的地址

  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
指针是一个未指向任何有效内存地址的指针。在C语言中,可以使用NULL常量来表示空指针。当一个指针被赋值为NULL时,它就成为了一个空指针。空指针通常用于表示指针不指向任何有效的对象或内存空间。引用中的代码示例中,使用了一个条件判断`if(!p)`来确保结构指针不为空指针结构是一种用户自定义的数据类型,可以将不同类型的数据组合在一起以形成一个结构结构可以包含多个成员变量,每个成员变量可以是不同的数据类型,比如整型、字符型、浮点型等。通过结构能够更好地组织和管理相关的数据。 在C语言中,可以通过定义结构变量和结构指针来使用结构结构变量是直接存储结构的实例,而结构指针则存储了结构实例的内存地址。引用中的代码示例展示了如何定义和使用结构以及使用结构指针修改结构变量的值。 需要注意的是,在使用结构指针时,需要确保指针不为空指针,以避免发生错误。可以通过条件判断来判断指针是否为空,如`if(!p)`。 总结来说,C语言的空指针结构是两个不同的概念。空指针是指向空地址的指针,用于表示指针不指向任何有效的对象或内存空间。而结构是一种用户自定义的数据类型,用于组合不同类型的数据。结构可以通过结构变量和结构指针来使用,并通过指针来修改结构变量的值。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [C语言指针结构详述](https://blog.csdn.net/weixin_44969353/article/details/126185425)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [C语言结构指针结构变量作形参的区别](https://blog.csdn.net/qq_42759112/article/details/119275822)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值