C语言学习记录--指针、结构体

完了,要重新学习C语言了。

指针是能存放其他变量地址的变量;

# include <stdio.h>

int main(void)
{
	int * p; //p是变量的名字, int * 表示p变量存放的是int类型变量的地址
	int i = 3;

	p = &i;  //OK
	//p = i; //error,因为类型不一致,p只能存放int类型变量的地址,不能存放int类型变量的值
	//p = 55; //error 原因同上

	return 0;
}

1.p保存了i的地址,p可以指向i;此时i和p等价。也就是说,如果p指向i,那么p就等于i,不能说它是i的地址,或者说i的值,它就是i本身。i和*p能在任何值地方变。
2.但是p不是i,i也不是p;修改p的值不改变i的值,修改i的值也不改变p的值;
3.如果一个指针变量指向了某个普通变量,则 指针变量就完全等同于普通变量;
eg:
如果p是个指针变量,并且p存放了普通变量i的地址,
则如果p指向了普通变量i,则
p就完全等同于i
或者说,在所有出现
p的地方都可以替换成i;
在所有出现i的地方都可以替换成
p;

int * p; // 不表示定义了一个名字叫*p的变量;而是指的是:
p是变量名,p变量名的数据类型是int 类型;
所谓int
类型,实际上就是存放了int变量地址的类型;

指针变量也是变量,只不过它存放的不是内存单元的内容,只能存放内存单元的地址;
普通变量之前不能加*,常量和表达式之前不能加&;
指针就是地址,地址就是指针;
地址就是内存单元的编号;
指针变量是存放地址的变量;
指针和指针变量是两个不同的概念;
但是要注意,通常我们在叙述的时候会把指针变量简称为指针,但是实际上他们的意义是不一样的;

int i = 10int *P = &i //	等价于int *p	 p = &i;

指针的重要性:
表示一些复杂的数据结构;
快速的传递数据;
使函数返回一个以上的值;
能直接访问硬件;
能够方便处理字符串;
是理解面向对象语言的基础;
总结:指针是C语言的灵魂。

指针的定义:
地址:内存单元的编号;
从零开始的非负整数;
指针就是地址,地址就是指针;
地址就是内存单元的编号;
指针就是地址,地址就是指针;
指针变量是存放地址的变量;
指针和指针变量是两个不同的概念;
但是要注意,通常我们在叙述的时候会把指针变量简称为指针,但是实际上他们的意义是不一样的;

指针的本质是一个操作受限的非负整数;

指针的分类:
1.基本类型指针

# include <stdio.h>

int main(void)
{
	int * p; //p是变量的名字, int * 表示p变量存放的是int类型变量的地址
			 //int * p; 不表示定义了一个名字叫做*p的变量
			// int * p; 应该这样理解: p是变量名, p变量的数据类型是 int *类型
			//          所谓int * 类型 实际就是存放int变量地址的类型	
	int i = 3;
	int j;

	p = &i;
		/*
			1. p保存了i的地址, 因此p指向i
			2. p不是i,i也不是p,更准确的说: 修改p的值不影响i的值,修改i的值也不会影响p的值
			3. 如果一个指针变量指向了某个普通变量, 则
					*指针变量  就完全等同于  普通变量
			   例子:	
					如果p是个指针变量,并且p存放了普通变量i的地址
					则p指向了普通变量i
					*p 	就完全等同于  i
					或者说:  在所有出现*p的地方都可以替换成i
							 在所有出现i的地方都可以替换成*p				
			
			        *p 就是以p的内容为地址的变量
		*/
	j = *p;  //等价于 j = i;
	printf("i = %d, j = %d\n", i, j);

	return 0;
}

一个用指针互换两个数字的code:

# include <stdio.h>

void swap_1(int , int );//函数声明的时候一般不写形参;
void swap_2(int * , int * );
void swap_3(int * , int * );

int main(void)
{
	int a = 3;
	int b = 5;

	swap_3(&a,&b);
	printf("a = %d, b = %d\n", a, b);

	return 0;
}


void swap_1(int i, int j)
{
	int t;	 

	t = i; i = j; j = t;
}

void swap_2(int * p, int * q) //形参名字是p和q,接收实参数据的是p和q,而不是*p和*q
{
	int * t;   //如果要 互换p q的值,则一定是*t而不是t,因为数据类型要保持一致;
	t = p; p = q; q = t;
}//  函数2还是无法互换ab,因为这只是互换了pq的地址,所以相当于互换了pq的值,但是ab是静止量,是无法互换ab的地址的。


void swap_3(int * p, int * q) //形参名字是p和q,接收实参数据的是p和q,而不是*p和*q
{
	int t;
	t = *p; *p = *q; *q = t;  //p是int *  , *p是是int;
}

的含义:
1.乘法;
2.定义指针变量;//定义了一个叫做p的变量,int
表示只能存放int变量的地址;
3.指针运算符;//该运算符放在已经定义好的指针变量的前面,如果p是一个已经定义好的指针变量,则*p表示以p的内容为地址的变量;

如何通过被调函数修改主调函数普通变量的值:
1.实参必须为该普通变量的地址;
2.形参必须是指针变量;
3.在被调函数中通过
*形参名=…
就可以修改主调函数中相关变量的值;

  • 指针和数组:
    指针和一维数组:
    数组名:
    一维数组名是个指针常量;
    它存放的是一维数组的第一个元素的地址;
    它的值不能被改变;
    一维数组名指向的是数组的第一个元素;
    *a[i] 和 (a+i)一样;// 这个要记住
    eg:
# include <stdio.h>

int main(void)
{
	int a[5]; //a是数组名  5是数组元素的个数 元素就是变量  a[0]  -- a[4]
//	int a[3][4]; //3行4列 a[0][0]是第一个元素 a[i][j]第i+1行j+1列
	int b[5];
	
	//a = b;//error a是常量
	printf("%#X\n", &a[0]);
	printf("%#X\n", a);

	return 0;
}
/*
	在Vc++6.0中的输出结果是:
--------------
0X12FF6C
0X12FF6C
Press any key to continue
--------------
	总结:
		一维数组名
					一维数组名是个指针常量
					它存放的是一维数组第一个元素的地址

*/

下标和指针的关系:
如果p是个指针变量,则
p[i]永远等价于*p(i+1)

确定一个一维数组最少需要两个参数;
数组第一个元素的地址;
数组的长度;

  • 结构体:
    为什么需要结构体:
    为了表示一些复杂的事物,而普通的基本类型无法满足实际要求;
    什么叫结构体:
    把一些基本类型数据组合形成的一个新的复合数据类型,这个就叫做结构体;
    eg:
# include <stdio.h>

struct Student
{
	int age;
	float score;
	char sex;
};

int main(void)
{
	struct Student st = {80, 66.6, 'F'};	
/*	int age;
	float score;
	char sex;
	int age2;
	float score2;
	char sex2;
*/
	return 0;
}

怎么样使用结构体和变量:

  • 赋值和初始化:
# include <stdio.h>

//第一种方式
struct Student
{
	int age;
	float score;
	char sex;
};

int main(void)
{
	struct Student st = {80, 66.6, 'F'}; //初始化  定义的同时赋初值
	struct Student st2;//先定义,再初始化
	st2.age = 10;
	st2.score = 88;
	st2.sex = 'F';

	printf("%d %f %c\n", st.age, st.score, st.sex);
	printf("%d %f %c\n", st2.age, st2.score, st2.sex);
	

	return 0;
}

定义的时候可以整体赋值;
如果定义完了之后,则只能单个的赋值;

如何提取出结构体变量中的每一个成员:
1. 结构体变量名.成员名
2. 指针变量名->成员名
eg:

# include <stdio.h>

//第一种方式
struct Student
{
	int age;
	float score;
	char sex;
};

int main(void)
{
	struct Student st = {80, 66.6, 'F'}; //初始化  定义的同时赋初值
	struct Student *pst=&st; //&st不能改为st;
	st.age = 10;//第一种方式初始化;
    pst->age=10;//第二种方式;

	printf("%d %f %c\n", st.age, st.score, st.sex);
	printf("%d %f %c\n", st2.age, st2.score, st2.sex);
	

	return 0;
}

pst->age在计算机内部会被转化成(*pst).age
pst->age所指向的那个结构体变量中的age的成员;

# include <stdio.h>

struct Student
{
	int age;
	char sex;
	char name[100];
}; //分号不能省

// 上面仅仅只是定义了一个数据类型,定义了一个叫结构体的数据类型;数据类型的名字叫struct Student
//有三个成员

int main(void)
{
	struct Student st = {20, 'F', "小娟"};//定义变量,并赋初始值;
	struct Student * pst = &st;
	
	printf("%d %c %s\n", st.age, st.sex, st.name);
	printf("%d %c %s\n", pst->age, pst->sex, pst->name);  //pst->age 转化成 (*pst).age 等价于 st.age

	return 0;
}
/*
	2009年11月24日9:17:43
	通过函数完成对结构体变量的输入和输出
*/


# include <stdio.h>
# include <string.h>

struct Student
{
	int age;
	char sex;
	char name[100];	
}; //分号不能省

void InputStudent(struct Student *);
void OutputStudent(struct Student ss);
int main(void)
{
	struct Student st;  //15行

	InputStudent(&st); //对结构体变量输入  必须发送st的地址
//	printf("%d %c %s\n", st.age, st.sex, st.name);
	OutputStudent(st); //对结构体变量输出  可以发送st的地址也可以直接发送st的内容

	return 0;
}

void OutputStudent(struct Student ss)
{
	printf("%d %c %s\n", ss.age, ss.sex, ss.name);
}

void InputStudent(struct Student * pstu) //pstu只占4个字节
{
	(*pstu).age = 10;
	strcpy(pstu->name, "张三");
	pstu->sex = 'F';	
}

/*
//本函数无法修改主函数15行st的值 所以本函数是错误的
void InputStudent(struct Student stu)
{
	stu.age = 10;
	strcpy(stu.name, "张三");  //不能写成 stu.name = "张三";
	stu.sex = 'F';
}
*/

指针的优点:

/*
	2009年11月24日9:17:43
	示例:
		发送地址还是发送内容
	目的:
		指针的优点之一:
			快速的传递数据,
			耗用内存小
			执行速度快
*/


# include <stdio.h>
# include <string.h>

struct Student
{
	int age;
	char sex;
	char name[100];
}; //分号不能省

void InputStudent(struct Student *);
void OutputStudent(struct Student *);
int main(void)
{
	struct Student st ;  //15行
	//printf("%d\n", sizeof(st));

	InputStudent(&st); //对结构体变量输入  必须发送st的地址
	OutputStudent(&st); //对结构体变量输出  可以发送st的地址也可以直接发送st的内容 但为了减少内存的耗费,也为了提高执行速度,推荐发送地址

	return 0;
}

void OutputStudent(struct Student *pst)
{
	printf("%d %c %s\n", pst->age, pst->sex, pst->n me);
}

void InputStudent(struct Student * pstu) //pstu只占4个字节
{
	(*pstu).age = 10;
	strcpy(pstu->name, "张三");
	pstu->sex = 'F';	
}

/*
//本函数无法修改主函数15行st的值 所以本函数是错误的
void InputStudent(struct Student stu)
{
	stu.age = 10;
	strcpy(stu.name, "张三");  //不能写成 stu.name = "张三";
	stu.sex = 'F';
}
*/

结构体变量不能相加,不能相减,不能乘除,只能相互赋值。

  • 枚举:
    把一个事物所有的可能的取值一一列举出来;
    枚举的优点:
    使代码更安全;
# include <stdio.h>

//只定义了一个数据类型,并没有定义变量, 该数据类型的名字是 enum WeekDay
enum WeekDay
{
	MonDay, TuesDay, WednesDay, ThursDay, FriDay, SaturDay, SunDay
};

int main(void)
{
	//int day; //day定义成int类型不合适
	enum WeekDay day = SunDay;
	printf("%d\n", day);

	return 0;
}
  • 链表:
    没看懂;

位运算符:
&; //按位与;
&& //逻辑与;
i&j //把i和j的每一位进行相与;
i&&j //i并且j,最后输出的只能是1或0;

| //按位或;
|| //逻辑或;

~ //按位取反;

^ //按位异或; //相同为0,不同为1;

<< //按位左移;
>> //按位右移;
二进制数左移n位相当于乘2^n,右移n位相当于除2的n次方;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值