C语言复习之结构体和指针
程序员文章站
2022-05-23 21:55:07
一前言:
1>下面所用到的实例为:
typedef struct {
&...
一前言:
1>下面所用到的实例为:
typedef struct {
int a;
short b[2];
}ex2;
typedef struct ex {
int a;
char b[3];
ex2 c;
struct ex *d;
}ex;
2>类型为ex的结构可以用下面的图表示:
3>可以用下列的方法进行声明:
ex x = {10,”hi”,{5,{-1,25}},0};
ex *px = &x;
二.访问指针
1.表达式px的右值是:
px是一个指针变量,但此处并不存在任何间接访问操作符,所以这个表达式的值就是px的内容。
2. 表达式px的左值是
1>它表示了px的旧值将被一个新值所取取代
现在考虑表达式px+1。这个表达式并不是一个合法的左值,因为它的值并不存储于任何可标识的内存位置。
2>px+1的右值:如果px指向一个结构数组的元素,这个表达式将指向该数组的下一个结构。但,就算如此,这个表达式任然是非法的,因为我们没有办法分辨内存下一个位置所存储的是这些结构元素之一还是其他东西。
三.访问结构
可以使用*操作符对指针执行间接访问。
1.表达式*px右值是px所指向的整个结构
间接访问操作随箭头访问结构,所以使用实现显示,其结果就是整个结构。
1>你可以把这个表达式赋值给另一个类型相同的结构,2>你也可以把它作为点操作符的左操作数,访问另一个指定的成员。
3>你可以把它作为参数传递给函数,也可以把它作为函数的返回值返回(但是 :这样做效率不高)
2.表达式*px的左值是:
1>此处,该结构将接受一个新值,或者更准确的说,它将接受它的所有成员的新值。作为左值,重要的是位置,而不是这个位置所保存的值。
2>表达式*px+1是非法的,因为*px的结果是一个结构。c语言没有定义结构和整型值之间的加法运算。
3>但是*(px+1),如果x是一个数组的元素,这个表达式表示它后面的那个结构。但是,x是一个标量,所以这个表达式实际上是非法的。
四结构的存储分配
结构在内存中是如何分配呢?
1.编译器按照成员列表顺序一个接一个地给每个成员分配内存。只有当存储成员时需要满足正确的边界对齐要求时,成员之间才可能出现用于填充的额外内存空间。
2.sizeof操作符能够得出一个结构的整体长度,包括因边界对齐而跳过的那些字节。
3.如果要确定结构中某个成员的实际位置,可以使用offsetof宏(stddef.h)
offsetof(type,member);
type是结构的类型,member是该结构的成员名,表达式的结构是一个sizeof_t值。表示该指定成员的存数位置(离该结构体存储的起始位置)
eg:
#include<stdio.h>
#include<stdlib.h>
#include<stddef.h>
struct tiger {
char a;
int b;
char c;
};
int main()
{
struct tiger x;
int m;
m = offsetof(struct tiger,b);
printf(“%d\n”,m);
}
该程序输出结构为4
五.作为函数参数的结构
结构标量是一个标量,它可以用于其他标量可以使用的任何场合。因此,把结构作为参数传递给一个函数是合法的,但这种做法往往不适宜。
1.下面的程序用于操作电子现金收入记录机。下面是一个结构的声明。
typedef struct {
char product[product_size];
int quantity;
float unit_price;
float total_amount;
}transaction;
当交易发生时,需要打印收据。
void print_receipt(transaction trans )
{
printf(“%s\n”,trans.product);
printf(“%d @ %2.f \
total %2.f\n”,trans.quantity,trans.unit_price,trans.total_amount)
};
如果current_trans是一个transaction结构,我们可以像下面这样调用函数;
print_receipt(current_trans);
说明:
该方法能产生正确的结果,但它的效率很低,因为c语言的参数传值调用方式要求把参数的一份拷贝传给函数。如果product_size为20,而且在我们使用的机器上整型和浮点型都占4个字节,那么这个结构将占据32个字节的空间。要把它作为参数进行传递,必须把32个字节复制到堆栈中,以后再丢弃。
方法二:
void print_receipt(transaction *trans )
{
printf(“%s\n”,trans.product);
printf(“%d @ %2.f \
total %2.f\n”,trans.quantity,trans.unit_price,trans.total_amount)
};
该函数可以用下面方法进行调用:
print_receipt(¤t_trans);
说明:
这次传递给函数的是一个指向结构的指针。指针比整个结构要小得多,所以把它压到堆栈上效率能提高很多。传递指针另外需要付出的代价是必须在函数中使用间接访问来访问结构的成员。结构越大,把指向它的指针传递给函数的效率就越高
向函数传递指针的缺陷在于函数现在可以对调用程序的结构变量进行修改。如果不希望如此,可以在函数中使用const关键字来防止这类修改。现在通过如下方式进行调用:
void print_receipt(transaction const *trans);
2.对交易进行处理:计算应该支付的总额。你希望函数comput_total_amount能够修改结构的total_amount成员。要完成这项任务有三种方法.
1>方法1:
transaction compute_total_amount(transaction trans)
{
trans.total_amount = trans.quantity*trans.unit_price;
return trans;
}
可以使用下面形式进行调用:
current_trans = compute_total_amount(current_trans);
结构的一份拷贝作为参数传递给函数并被修改。然后一份修改后的结构拷贝从函数返回,所以这个结构被复制了两次。
2>方法2:
该方法是只返回修改后的值,而不是整个结构
float compute_total_amount(transaction trans)
{
return trans.quantity * trans.unit_price;
}
但是,这个函数必须以下面这种方式进行调用:
current_trans.total_amount
=compute_total_amount(current_trans);
此方案比返回整个结构的那个方案强,但这个技巧只适用于计算单个值的情况。如果要求函数修改结构的两个或更多成员,这样方法就无能为力了。另外,它仍然存在把整个结构作为参数进行传递这个开销。
3>方法3: www.2cto.com
传递一个指针,该方案要好的多
void compute_toatl_amount(transaction *trans)
{
trans->total_amount =trans->quantity *trans->unit_price;
}
这个函数按照下面的方式进行调用:
compute_total_amount(¤t_trans);
说明:
在程序中结构字段total_amount被直接修改,它并不需要把整个结构作为参数传递给函数,也不需要把整个修改过的结构作为返回值返回。
摘自 tiger-john
1>下面所用到的实例为:
typedef struct {
int a;
short b[2];
}ex2;
typedef struct ex {
int a;
char b[3];
ex2 c;
struct ex *d;
}ex;
2>类型为ex的结构可以用下面的图表示:
3>可以用下列的方法进行声明:
ex x = {10,”hi”,{5,{-1,25}},0};
ex *px = &x;
二.访问指针
1.表达式px的右值是:
px是一个指针变量,但此处并不存在任何间接访问操作符,所以这个表达式的值就是px的内容。
2. 表达式px的左值是
1>它表示了px的旧值将被一个新值所取取代
现在考虑表达式px+1。这个表达式并不是一个合法的左值,因为它的值并不存储于任何可标识的内存位置。
2>px+1的右值:如果px指向一个结构数组的元素,这个表达式将指向该数组的下一个结构。但,就算如此,这个表达式任然是非法的,因为我们没有办法分辨内存下一个位置所存储的是这些结构元素之一还是其他东西。
三.访问结构
可以使用*操作符对指针执行间接访问。
1.表达式*px右值是px所指向的整个结构
间接访问操作随箭头访问结构,所以使用实现显示,其结果就是整个结构。
1>你可以把这个表达式赋值给另一个类型相同的结构,2>你也可以把它作为点操作符的左操作数,访问另一个指定的成员。
3>你可以把它作为参数传递给函数,也可以把它作为函数的返回值返回(但是 :这样做效率不高)
2.表达式*px的左值是:
1>此处,该结构将接受一个新值,或者更准确的说,它将接受它的所有成员的新值。作为左值,重要的是位置,而不是这个位置所保存的值。
2>表达式*px+1是非法的,因为*px的结果是一个结构。c语言没有定义结构和整型值之间的加法运算。
3>但是*(px+1),如果x是一个数组的元素,这个表达式表示它后面的那个结构。但是,x是一个标量,所以这个表达式实际上是非法的。
四结构的存储分配
结构在内存中是如何分配呢?
1.编译器按照成员列表顺序一个接一个地给每个成员分配内存。只有当存储成员时需要满足正确的边界对齐要求时,成员之间才可能出现用于填充的额外内存空间。
2.sizeof操作符能够得出一个结构的整体长度,包括因边界对齐而跳过的那些字节。
3.如果要确定结构中某个成员的实际位置,可以使用offsetof宏(stddef.h)
offsetof(type,member);
type是结构的类型,member是该结构的成员名,表达式的结构是一个sizeof_t值。表示该指定成员的存数位置(离该结构体存储的起始位置)
eg:
#include<stdio.h>
#include<stdlib.h>
#include<stddef.h>
struct tiger {
char a;
int b;
char c;
};
int main()
{
struct tiger x;
int m;
m = offsetof(struct tiger,b);
printf(“%d\n”,m);
}
该程序输出结构为4
五.作为函数参数的结构
结构标量是一个标量,它可以用于其他标量可以使用的任何场合。因此,把结构作为参数传递给一个函数是合法的,但这种做法往往不适宜。
1.下面的程序用于操作电子现金收入记录机。下面是一个结构的声明。
typedef struct {
char product[product_size];
int quantity;
float unit_price;
float total_amount;
}transaction;
当交易发生时,需要打印收据。
void print_receipt(transaction trans )
{
printf(“%s\n”,trans.product);
printf(“%d @ %2.f \
total %2.f\n”,trans.quantity,trans.unit_price,trans.total_amount)
};
如果current_trans是一个transaction结构,我们可以像下面这样调用函数;
print_receipt(current_trans);
说明:
该方法能产生正确的结果,但它的效率很低,因为c语言的参数传值调用方式要求把参数的一份拷贝传给函数。如果product_size为20,而且在我们使用的机器上整型和浮点型都占4个字节,那么这个结构将占据32个字节的空间。要把它作为参数进行传递,必须把32个字节复制到堆栈中,以后再丢弃。
方法二:
void print_receipt(transaction *trans )
{
printf(“%s\n”,trans.product);
printf(“%d @ %2.f \
total %2.f\n”,trans.quantity,trans.unit_price,trans.total_amount)
};
该函数可以用下面方法进行调用:
print_receipt(¤t_trans);
说明:
这次传递给函数的是一个指向结构的指针。指针比整个结构要小得多,所以把它压到堆栈上效率能提高很多。传递指针另外需要付出的代价是必须在函数中使用间接访问来访问结构的成员。结构越大,把指向它的指针传递给函数的效率就越高
向函数传递指针的缺陷在于函数现在可以对调用程序的结构变量进行修改。如果不希望如此,可以在函数中使用const关键字来防止这类修改。现在通过如下方式进行调用:
void print_receipt(transaction const *trans);
2.对交易进行处理:计算应该支付的总额。你希望函数comput_total_amount能够修改结构的total_amount成员。要完成这项任务有三种方法.
1>方法1:
transaction compute_total_amount(transaction trans)
{
trans.total_amount = trans.quantity*trans.unit_price;
return trans;
}
可以使用下面形式进行调用:
current_trans = compute_total_amount(current_trans);
结构的一份拷贝作为参数传递给函数并被修改。然后一份修改后的结构拷贝从函数返回,所以这个结构被复制了两次。
2>方法2:
该方法是只返回修改后的值,而不是整个结构
float compute_total_amount(transaction trans)
{
return trans.quantity * trans.unit_price;
}
但是,这个函数必须以下面这种方式进行调用:
current_trans.total_amount
=compute_total_amount(current_trans);
此方案比返回整个结构的那个方案强,但这个技巧只适用于计算单个值的情况。如果要求函数修改结构的两个或更多成员,这样方法就无能为力了。另外,它仍然存在把整个结构作为参数进行传递这个开销。
3>方法3: www.2cto.com
传递一个指针,该方案要好的多
void compute_toatl_amount(transaction *trans)
{
trans->total_amount =trans->quantity *trans->unit_price;
}
这个函数按照下面的方式进行调用:
compute_total_amount(¤t_trans);
说明:
在程序中结构字段total_amount被直接修改,它并不需要把整个结构作为参数传递给函数,也不需要把整个修改过的结构作为返回值返回。
摘自 tiger-john
上一篇: PHP中查询一个日期是周几
下一篇: C语言数组与指针详解