C语言——内联函数、结构体、结构体数组和结构体指针、传递结构体变量和结构体指针

本文详细介绍了C语言中的内联函数,包括其作用、使用方式以及预处理运算符#和##。接着,深入讲解了结构体的声明、定义、访问成员、初始化以及结构体数组和指针的运用。此外,还讨论了如何通过传递结构体变量和指针在函数间进行数据交换,以及动态分配结构体内存的方法。

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

目录

一、内联函数

1.内联函数

2.  #  和  ## 

3.可变参数

 二、结构体

1.结构体声明

2.定义结构体类型变量

3.访问结构体变量

4.初始化结构体变量

5.初始化结构体的指定成员值

三、结构体数组和结构体指针

1.结构体数组

2.初始化结构体数组

3.结构体指针

四、传递结构体变量和结构体指针

1.传递结构体变量

2.传递指向结构体变量的指针

3.动态申请结构体


一、内联函数

1.内联函数

  • C语言引入内联函数来解决程序中函数调用的效率问题。

代码举例:

#include <stdio.h>

inline int square(int x);

inline int square(int x)
{
	return x * x;
}

int main(void)
{
	int i = 1;
	
	while(i <= 100)
	{
		printf("%d的平方是%d\n",i-1,square(i++));
	}
	return 0;
}

运行结果:

  • 内联函数虽然节省了函数调用的时间消耗,但由于每一个函数出现的地方都要进行替换,因此增加了代码编译的时间。另外,并不是所有的函数都能够变成内联函数。
  • 现在的编译器也很聪明,就算不写inline,它也会自动将一些函数优化成内联函数。

2.  #  和  ## 

  • #  和  ##  是两个预处理运算符。
  • 在带参数的宏定义中,# 运算符后面应该跟一个参数,预处理器会把这个参数转换为一个字符串。

代码举例:

#include <stdio.h>

#define STR(s) # s

int main(void)
{
	printf(STR(Hello     %s num = %d),STR(LoveC),520);
	
	return 0;
	
}

运行结果:

  • ## 运算符被称为记号连接运算符,比如我们可以使用 ## 运算符连接两个参数。

代码举例:

#include <stdio.h>

#define TOGETHER(x,y) x ## y

int main(void)
{
	printf("%d\n",TOGETHER(2,50));
	
	return 0;
	
}

运行结果:

3.可变参数

  • 之前我们学习了如何让函数支持可变参数,带参数的宏定义也是使用可变参数的:

#define SHOWLIST(…) printf(#__VA_ARGS__)

  • 其中,…表示使用可变参数,__VA_ARGS__在预处理中被实际的参数集所替换。

代码举例:

#include <stdio.h>

#define SHOWLIST(...) printf(# __VA_ARGS__)

int main(void)
{
	SHOWLIST(LoveC,520,3.14\n);
	
	return 0;
	
}

运行结果:

 二、结构体

1.结构体声明

结构体声明是描述结构体组合的主要方法。

2.定义结构体类型变量

struct 结构体名称 结构体变量名

代码举例:

#include <stdio.h>

struct Book
{
	char title[128];
	char author[40];
	float price;
	unsigned int date;
	char publisher[40];
}book;//全局变量 

int main(void)
{
//	struct Book book;//局部变量 

	return 0;
	
}

3.访问结构体变量

  • 要访问结构体成员,需要引入一个新的运算符一点号(.)运算符。比如book.title就是引用book结构体的title成员,它是一个字符数组;而book.price则是引用book结构体的price成员,它是一个浮点型的变量。

代码举例:

#include <stdio.h>

struct Book
{
	char title[128];
	char author[40];
	float price;
	unsigned int date;
	char publisher[40];
}book;

int main(void)
{
	printf("请输入书名:");
	scanf("%s",book.title);
	printf("请输入作者:");
	scanf("%s",book.author);
	printf("请输入售价:");
	scanf("%f",&book.price);
	printf("请输入出版日期:");
	scanf("%d",&book.date);
	printf("请输入出版社:");
	scanf("%s",book.publisher);
	
	printf("\n=====数据录入完毕=====\n");
	
	printf("\n书名:%s\n",book.title);
	printf("作者:%s\n",book.author);
	printf("售价:%2f\n",book.price);
	printf("出版日期:%d\n",book.date);
	printf("出版社:%s\n",book.publisher);
	
	return 0;
	
}

运行结果:

4.初始化结构体变量

  • 初始化一个变量和数组:
int a = 520;
int array[5] = {1, 2, 3, 4, 5};
  • 初始化一个结构体变量:
struct Book book = {
    "《带你学C带你飞》",
    "小甲鱼",
    48.8,
    20220817,
    "清华大学出版社"
};

5.初始化结构体的指定成员值

  • 其语法和数组指定初始化元素类似,不过结构体指定初始化成员使用点号(.)运算符和成员名。
  • 比如可以让程序只初始化Book的price成员:
struct Book book = {.price = 48.8};
  • 还可以不按结构体声明的成员顺序进行初始化:
struct Book book = {
    .publisher = "清华大学出版社",
    .price = 48.8,
    .date = 20220817
};

三、结构体数组和结构体指针

1.结构体数组

  • 第一种方法是在声明结构体的时候进行定义:
struct 结构体名称
{
    结构体成员;
}数组名[长度];
  • 第二种方法是先声明一个结构体类型(比如上面Book),再用此类型定义一个结构体数组:
struct 结构体名称
{
    结构体成员;
};
struct 结构体名称 数组名[长度];

2.初始化结构体数组

struct Book book[3]={
    {"《零基础入门学习Python》","小甲鱼",49.5,{2016,11,11},"清华大学出版社"},
    {"《零基础入门学习Scratch》","不二如是",49.9,{2017,10,1},"清华大学出版社“},
    {"《带你学C带你飞》","小甲鱼",49.9,{2017,11,11},"清华大学出版社"}
};

3.结构体指针

struct Book * pt;
pt = &book;

通过结构体指针访问结构体成员有两种方法:

  • (*结构体指针).成员名
  • 结构体指针->成员名

四、传递结构体变量和结构体指针

1.传递结构体变量

两个结构体变量可以直接赋值

代码举例1:

#include <stdio.h>

int main(void)
{
	struct Test
	{
		int x;
		int y;
	}t1,t2;
	
	t1.x = 3;
	t2.y = 4;
	
	t2 = t1;
	
	printf("t2.x = %d,t2.y = %d\n",t2.x,t2.y);
	
}

运行结果:

 代码举例2:

#include <stdio.h>

struct Date
{
	int year;
	int month;
	int day;
};

struct Book
{
	char title[128];
	char author[40];
	float price;
	struct Date date;
	char publisher[40];
};

struct Book getInput(struct Book book);
void printBook(struct Book book);

struct Book getInput(struct Book book)
{
	printf("请输入书名:");
	scanf("%s",book.title);
	printf("请输入作者:");
	scanf("%s",book.author);
	printf("请输入售价:");
	scanf("%f",&book.price);
	printf("请输入出版日期:");
	scanf("%d-%d-%d",&book.date.year,&book.date.month,&book.date.day);
	printf("请输入出版社:");
	scanf("%s",book.publisher);
	
	return book;
}

void printBook(struct Book book)
{
	printf("书名:%s\n",book.title);
	printf("作者:%s\n",book.author);
	printf("售价:%.2f\n",book.price);
	printf("出版日期:%d-%d-%d\n",book.date.year,book.date.month,book.date.day);
	printf("出版社:%s\n",book.publisher);
}



int main(void)
{
	struct Book b1,b2;
	
	printf("请录入第一本书的信息 ……\n");
	b1 = getInput(b1);
	putchar('\n');
	printf("请录入第二本书的信息 ……\n");
	b2 = getInput(b2);
	
	printf("\n\n录入完毕,现在开始打印验证……\n\n");
	
	printf("打印第一本书的信息……\n");
	printBook(b1);
	putchar('\n');
	printf("打印第二本书的信息……\n");
	printBook(b2);
	
	return 0;
	
}

运行结果:

2.传递指向结构体变量的指针

上述代码改为:

#include <stdio.h>

struct Date
{
	int year;
	int month;
	int day;
};

struct Book
{
	char title[128];
	char author[40];
	float price;
	struct Date date;
	char publisher[40];
};

void getInput(struct Book *book);
void printBook(struct Book *book);

void getInput(struct Book *book)
{
	printf("请输入书名:");
	scanf("%s",book->title);
	printf("请输入作者:");
	scanf("%s",book->author);
	printf("请输入售价:");
	scanf("%f",&book->price);
	printf("请输入出版日期:");
	scanf("%d-%d-%d",&book->date.year,&book->date.month,&book->date.day);
	printf("请输入出版社:");
	scanf("%s",book->publisher);
	
	return book;
}

void printBook(struct Book *book)
{
	printf("书名:%s\n",book->title);
	printf("作者:%s\n",book->author);
	printf("售价:%.2f\n",book->price);
	printf("出版日期:%d-%d-%d\n",book->date.year,book->date.month,book->date.day);
	printf("出版社:%s\n",book->publisher);
}



int main(void)
{
	struct Book b1,b2;
	
	printf("请录入第一本书的信息 ……\n");
	getInput(&b1);
	putchar('\n');
	printf("请录入第二本书的信息 ……\n");
	getInput(&b2);
	
	printf("\n\n录入完毕,现在开始打印验证……\n\n");
	
	printf("打印第一本书的信息……\n");
	printBook(&b1);
	putchar('\n');
	printf("打印第二本书的信息……\n");
	printBook(&b2);
	
	return 0;
	
}

3.动态申请结构体

使用malloc函数为结构体分配存储空间

上述代码改为:

#include <stdio.h>
#include <stdlib.h>


struct Date
{
	int year;
	int month;
	int day;
};

struct Book
{
	char title[128];
	char author[40];
	float price;
	struct Date date;
	char publisher[40];
};

void getInput(struct Book *book);
void printBook(struct Book *book);

void getInput(struct Book *book)
{
	printf("请输入书名:");
	scanf("%s",book->title);
	printf("请输入作者:");
	scanf("%s",book->author);
	printf("请输入售价:");
	scanf("%f",&book->price);
	printf("请输入出版日期:");
	scanf("%d-%d-%d",&book->date.year,&book->date.month,&book->date.day);
	printf("请输入出版社:");
	scanf("%s",book->publisher);
	
	return book;
}

void printBook(struct Book *book)
{
	printf("书名:%s\n",book->title);
	printf("作者:%s\n",book->author);
	printf("售价:%.2f\n",book->price);
	printf("出版日期:%d-%d-%d\n",book->date.year,book->date.month,book->date.day);
	printf("出版社:%s\n",book->publisher);
}



int main(void)
{
	struct Book *b1,*b2;
	
	b1 = (struct Book *)malloc(sizeof(struct Book));
	b2 = (struct Book *)malloc(sizeof(struct Book));
	
	if (b1 == NULL || b2 == NULL)
	{
		printf("内存分配失败!\n");
		exit(1);
	}
	
	printf("请录入第一本书的信息 ……\n");
	getInput(b1);
	putchar('\n');
	printf("请录入第二本书的信息 ……\n");
	getInput(b2);
	
	printf("\n\n录入完毕,现在开始打印验证……\n\n");
	
	printf("打印第一本书的信息……\n");
	printBook(b1);
	putchar('\n');
	printf("打印第二本书的信息……\n");
	printBook(b2);
	
	free(b1);
	free(b2);
	
	return 0;
	
}
### Nginx 文件名逻辑漏洞(CVE-2013-4547) #### 漏洞概述 Nginx 文件名逻辑漏洞(CVE-2013-4547)允许攻击者通过精心构造的 URL 请求来绕过访问控制并读取或执行受限资源。此漏洞的根本原因在于 Nginx 错误地解析了带有特定编码字符的 URL,从而导致文件路径处理不当[^1]。 #### 影响范围 该漏洞影响多个版本的 Nginx,在某些配置下可能导致未经授权的文件访问甚至远程代码执行。具体受影响的版本包括但不限于: - Nginx 1.4.x 版本系列 - Nginx 1.5.x 版本系列 (部分) 当 Web 应用程序部署于上述版本之上时,可能存在潜在风险[^3]。 #### 复现过程 为了验证这一漏洞的存在,可以通过上传一个看似无害但实际上包含恶意 PHP 代码的图片文件 `phpinfo.jpg` 来测试。一旦成功上传,攻击者能够修改 HTTP 请求中的参数使服务器错误解释文件扩展名,进而触发命令注入行为[^4]。 ```bash curl -X POST http://example.com/upload.php \ -F "file=@/path/to/phpinfo.jpg" ``` 随后发送如下请求可尝试利用漏洞: ```http GET /uploads/phpinfo.jpg%00.php?cmd=id HTTP/1.1 Host: example.com ``` 如果存在漏洞,则返回的结果会显示当前用户的 ID 信息。 #### 安全修复措施 针对 CVE-2013-4547 的防护手段主要包括以下几个方面: - **升级至最新稳定版**:官方已发布更新解决此问题,建议立即应用最新的安全补丁以消除隐患[^2]。 - **手动修补源码**:对于无法即时升级的情况,可以从官方网站下载专门为此漏洞准备的安全补丁,并按照指引完成编译安装流程。 - **加强输入校验**:无论何时都应严格过滤用户提交的数据,特别是涉及文件操作的部分,防止非法字符进入内部处理环节。 - **启用 WAF 防护**:Web Application Firewall 能够识别异常模式并阻止可疑流量到达应用程序层面上游位置。 综上所述,及时采取适当行动可以有效降低遭受此类攻击的风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值