C语言基础

指针

9.为什么需要用指针?

①若要通过函数调用来改变调用者里的局部变量,就要传地址,可以通过指针的方式来修改main函数的数据

如实现两数交换:

void changeData(int* data1, int* data2)
{
	int tmp;
	tmp = *data1;
	*data1 = *data2;
	*data2 = tmp;
}

②指针能指向固定区域

	volatile unsigned int* p = (volatile unsigned int*)0x0000FE1526;
	printf("固定地址为:%p\n", p);

10.通过指针引用数组

指针可以当作数组名,并用下标法访问数组名可以拿来加但是a++是不可以的,因为数组名为常变量指针

将数组中的n个元素按逆序存放

​//初始化数组
void initArr(int* arr, int len)
{
	for (int i = 0; i < len; i++)
	{
		scanf("%d", arr++);
	}
}
//遍历数组并输出
void printArr(int* arr, int len)
{
	for (int i = 0; i < len; i++)
	{
		printf("%d  ", *arr++);
	}
	putchar('\n');
}
//将数组里的值逆序存
void revangArr(int* arr, int len)
{
	int i;
	int j;
	int tmp;
	for (i = 0; i < len / 2; i++)
	{
		j = len - i - 1;
		tmp = *(arr+i);
		*(arr + i) = *(arr + j);
		*(arr + j) = tmp;
	}
}

int main()
{
	int array[6];
	initArr(array, 6);
	printArr(array, 6);
	revangArr(array, 6);
	printArr(array, 6);
}

11.指针和二维数组

int arr[3][4]= { {11,22,33,44},{1,2,3,4},{12,4} };

for (int i = 0; i < 3; i++) {

for (int j = 0; j < 4; j++) {

printf("a[%d][%d]的地址是:%p,值为:%d\n", i,j,&arr[i][j], arr[i][j]);

printf("a[%d][%d]的地址是:%p,值为:%d\n", i, j, arr[i]+j,*(arr[i]+j));

printf("a[%d][%d]的地址是:%p,值为:%d\n", i, j, *(arr+i)+j,*(*(arr+i)+j));

//以上三个输出结果是一样的

}

运行结果:

12.数组指针

int (*p)[4]

	int arr[3][4] = { {11,22,33,44},{1,2,3,4},{12,4} };
	int i, j;
	int* p = arr;
	//定义一个指针,让指针偏移的时候,也偏移对应大小的数组
	//数组指针,定义一个指针,指向一个数组;
	//数组指针才是真正等同于二维数组名
	int(*p2)[4] = arr;
	printf("p2的地址是%p\n", p2);
	printf("++p=%p,++p2=%p\n", p + 1, p2 + 1);//p+1偏移4个字节,p2 + 1偏     //移4*4=16个字节
	for (i = 0; i < 3; i++) {
		for (j = 0; j < 3; j++) {
			printf("%d\n", *(*(p2 + i) + j));
		}
	}

13.函数指针

 

13.1函数名就是地址

用函数指针来进行函数调用

void printWelcome()
{
	puts("欢迎光临\n");
}
int getData(int data)
{
	return ++data;
}
int main()
{       void (*p)();
	int (*p2)(int data)
	p = printWelcome;
	p2 = getData;
	(*p)();//函数调用
	printf("%d",(*p2)(10));
	return 0;
}

 

13.2函数指针能根据程序运行过程的不同情况,调用不同的函数

例:有两个整数a和b,由用户输入1,2或3。如输入1,程序就给出a和b中大

者,输入2,就给出a和b中小者,输入3,则求a与b之和。

int getMax(int a, int b)
{
	return a > b ? a : b;
}

int getMin(int a, int b)
{
	return a < b ? a : b;
}

int getSum(int a, int b) 
{
	return a + b;
}

int dataHandle(int a, int b, int(*p)(int, int))
{
	return (*p)(a, b);
}

int main()
{
	int data1;
	int data2;
	int cmd;
	int (*p)(int, int);
	int ret;
	printf("请输入两个整数:\n");
	scanf("%d%d", &data1, &data2);
	printf("请输入指令:");
	scanf("%d", &cmd);
	switch (cmd)
	{
	case 1:
		p = getMax;
		break;
	case 2:
		p = getMin;
		break;
	case 3:
		p = getSum;
		break;
	default:
		printf("指令错误");
		exit(-1);
	}
	ret = dataHandle(data1, data2, p);
	printf("%d", ret);
	return 0;
}

14.指针数组 

数组的每一项都是一个指针变量

int a = 1;

int b = 2;

int c = 3;

int* p[3] = { &a,&b,&c };

for (int i = 0; i < 3; i++){

printf("%d  ", *p[i]);

}

函数指针数组,对于13.2的例子可将程序改写成:

int (*p[3])(int, int);

p[0] = getMax;

p[1] = getMin;

p[2] = getSum;

printf("大值:%d,小值:%d,和:%d\n", (*p[0])(1,2), (*p[1])(1,2), (*p[2])(1,2));

15.指针函数

函数的返回值为指针

有3个学生,每个学生有4门课程的成绩。要求在用户输入学生序号以后,

能输出该学生的全部成绩。用指针函数来实现。

int* getPos(int pos ,int (*ppos)[4])

//int (*ppos)[4]为数组指针,即该指针指向一个数组

{

int* p;

p = (int *)(ppos + pos);

return p;

}

int main()

{

int score[3][4] = { {88,55,99,66},{75,98,64,85},{66,44,88,76} };

int pos;

int* ret;

printf("请输入学生序号\n");

scanf("%d", &pos);

ret = getPos(pos, score);

printf("学生%d的成绩为:\n", pos);

for (int i = 0; i < 4; i++)

{

printf("%d  ", *(ret+i));

}

return 0;

}

对上例中的学生,找出其中有不及格的课程的学生及其学生号。

int* research(int(*ppos)[4])

{

int* q=NULL;//防止野指针

for (int i = 0;  i < 4; i++)

{

if (*(*ppos + i) <= 60) {

q = ppos;

}

}

return q;

}

//

int main()

{

int score[6][4] = { {88,59,99,66},{75,98,64,85},{66,44,88,56} };

int* num;

for (int i = 0; i < 3; i++) {

num = research(score + i);

if (num == (score + i))

{

printf("不及格的学生序号为:%d\n", i+1);

}

}

return 0;

}

字符串拼接:

char* myStrcat(char* des, char* src)

{

assert(des != NULL || src != NULL);

char* data = des;

while (*des) {

des++;

}

while (*src!='\0')

{

*des++ = *src++;

}

*des = '\0';

return data;

}

int main()

{

char cdata1[10] = "chen";

char* p = "xiao";

char* p2;

p2 = (char*)malloc(1);

*p2 = 'c';

 myStrcat(cdata1, p);

printf("%s\n", cdata1);

printf("%c\n", *p2);

}

字符串

16.字符串常用的两种定义格式:

char str[ ] = "hello";

char *p =“hello”

两者区别前者是是字符串变量,后者是字符串常量,不允许被修改

以上定义的字符串多了结束标志‘\0’

ps:C语言只有在定义字符数组的时候才能用“=”来初始化变量,其它情况下是不能直接用“=”来为字符数组赋值的,之所以不能赋值成功,是因为数组名是一个指针常量,指向固定地址,再对其赋值即改变其指向的地址,作为常量自然不同意。

要为字符数组赋值可以用string.h头文件中的strcpy函数来完成。

例如:

char a[10] = "123"; /*正确,在定义的时候初始化*/

char a[10];

a = "123"; /*错误,不能用“=”直接为字符数组赋值*/

strcpy(a, "123"); /*正确,使用strcpy函数复制字符串*/

17.sizeof和strlen的区别

  1. 动态开辟字符串

函数:

 

  1. 常用函数

拷贝:char *strcpy(char* dest, const char *src);

char *strncpy(char *dest, const char *src, int n)

断言:assert

char* myStrcpy1(char* des, char* src)

{

char* data = des;

//assert 的作用是现计算表达式expression ,如果其值为假(即为0)

    //那么它先向stderr打印一条出错信息,然后通过调用abort来终止程序运行

assert(src == NULL || des == NULL);//断言

//if (src == NULL || des == NULL) {

return NULL;

}

while (*src != '\0') {

*des = *src;

des++;

src++;

}

*des = '\0';

return data;

}

拼接:char *strcat(char *dest, const char *src);

将src拼接到dest后面

比较:

结构体

20.结构体数组,指针,函数应用

结构体指针注意:1.把以前的普通变量名,或者下标访问的.运算符,改成结构体指针的->

2.指针++,每次遍历会到数组尾巴,下次遍历之前记得回来(重新指数组头)!

做一个选票系统(要避免野指针!

struct xuanMin* initXm(struct xuanMin* p, int* pn)

{

if (p == NULL) {

printf("有几个候选人\n");

scanf("%d", pn);

p = (struct xuanMin*)malloc(*pn * sizeof(struct xuanMin));

}

for (int i = 0; i < *pn; i++) {

p->ticket = 0;

printf("请输入选民的候选人名字:\n");

scanf("%s", p->name);

p++;

}

return p - *pn;

}

void printXm(struct xuanMin* p, int len)

{

int i;

for (i = 0; i < len; i++) {

printf("%s的票数为:%d\n",p->name, p->ticket);

p++;

}

}

int dovot(struct xuanMin* p, int len)

{

int feipiao = 0;

int flag;

char tmpname[32];

struct xuanMin* pbak = p;

for (int i = 0; i < 5; i++) {

flag = 0;

p = pbak;

printf("请输入你要投票的候选人名字:\n");

memset(tmpname, '\0', sizeof(tmpname));

scanf("%s", tmpname);

for (int j = 0; j < len; j++) {

if (strcmp(tmpname, p->name) == 0) {

p->ticket++;

flag = 1;

}

p++;

}

if (flag == 0) {

printf("无此候选人,弃票\n");

feipiao++;

}

}

return feipiao;

}

struct xuanMin getMax(struct xuanMin* p, int len)

{

struct xuanMin max = *p;

for (int i = 0; i < len; i++) {

if (max.ticket < p->ticket) {

max = *p;

}

p++;

}

return max;

}

int main()

{

struct xuanMin* xm = NULL;

int total=0;

xm = initXm(xm, &total);

int feipiao = dovot(xm, total);

struct xuanMin max = getMax(xm, total);

printXm(xm, total);

printf("%s当选,票数为:%d,废票数为:%d", max.name, max.ticket, feipiao);

return 0;

}

共用体/联合体

  1. 结构体元素有各自单独空间 共用体元素共享空间,空间大小有最大类型确定
  2. 结构体元素互不影响 共用体赋值会导致覆盖

ps:在用scanf或getchar连续输入字符时,需要主要清空缓冲区!

有若干个人员的数据,其中有学生和教师。学生的数据中包括:姓名、号码、性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。要求用同一个表格来处理。

struct person

{

char people;

char name[32];

char zhiye;

union

{

int class;

char zhiwu;

}mes;

};

int main()

{

struct person u[3];

for (int i = 0; i < 3; i++) {

printf("请输入是学生还是老师,学生输入s,老师输入t:\n");

scanf("%c", &(u[i].people));

if(u[i].people == 's') {

printf("请输入学生名字\n");

scanf("%s", u[i].name);

printf("请输入信息,学生输入班级(整形数字),\n");

scanf("%d", &(u[i].mes.class));

}

else if (u[i].people == 't') {

printf("请输入老师名字\n");

scanf("%s", u[i].name);

printf("请输入信息,老师输入职务(字符),\n");

getchar();

scanf("%c", &(u[i].mes.zhiwu));

}

int c;

// 未读到文件结尾前提下,清空换行符前的所有字符

while ((c=getchar()) != EOF && c != '\n') {}

}

for (int i = 0; i < 3; i++) {

if (u[i].people == 's') {

printf("%c\n名字:%s,信息:%d\n", u[i].people, u[i].name, u[i].mes.class);

}

else if (u[i].people == 't') {

printf("%c\n名字:%s,信息:%c\n", u[i].people, u[i].name, u[i].mes.zhiwu);

}

}

return 0;

}

枚举类型

typedef关键字

给已经有的变量类型起名字,一般配合结构体用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值