指针与数组是如何访问的——可以用extern int *p作为int p[N]的外部声明吗?

本文深入探讨了C语言中指针与数组的访问内存方式、使用指针作为数组外部声明时的问题,以及数组声明中元素个数的重要性。通过实例展示了指针与数组访问内存的区别,并说明了声明与定义匹配的重要性。

[摘要]C语言中,很多情况下指针与数组的的使用方式十分类似,使用数组名为一个指针变量赋值也是完全合法的。这造成一个假象,即数组就是指针,对于它们二者的区别是一个老生常谈的话题,本文仅从指针与数组访问内存的方式进行区分,其余不再赘述。另外还讨论了使用指针作为数组的外部声明时产生的问题,以及extern int a[]与extern int a[N]的一点小区别。

1、数组与指针访问内存的方式

数组访问:

 

指针访问


指针偏移访问:


可见,指针访问内存的方式更为灵活,但它会增加一次额外的内存读取,即先将指针的值从内存中读出来,再用它作为地址去访问数据。

2、使用指针作为数组的外部声明

例如以下代码:

file2.c
	int p[100];
        ……

file1.c
	extern int *p;
        ……
	p[0] = 1;

根据指针访问内存的方式,编译器首先提取p的值,在VC 6.0编译环境下,此处提取的是0x0000 0000,然后加上偏移量18CH,将1写入,程序崩溃。

修正方法:使声明与定义相匹配,声明为extern int p[];


3、数组声明中要不要写明元素个数

声明并不分配内存,只是告诉编译器对象的名字和类型,所以一般不需写明数组大小,但对于多维数组要写明左边一维之外的其他维的长度——给编译器足够的信息去产生代码。

但是,如果在引用变量处需要使用sizeof来取得数组大小,则必须指明,因为编译时编译器会计算出sizeof的结果。经试验,此处sizeof的结果只与声明中指定的元素个数相关,与定义处无关。

在上例中,如果按以下方式声明:

extern int p[];   //1
extern int p[100];//2
extern int p[50]; //3

三者中sizeof(p)的结果分别是0,400,200

对于3,虽然声明中p中只有50个int,但是依然可以正常引用p[99],因为p的内存是在定义处分配的,与声明无关。

### `extern int jso_obj_get_int(JSON_OBJPTR obj, const char *key, int *pValue)` 的作用 该函数用于从 JSON 对象中提取指定键的整数值。其参数含义如下: - `JSON_OBJPTR obj`:指向 JSON 对象的指针。 - `const char *key`:要查找的键名。 - `int *pValue`:用于存储提取出的整数值的指针。 函数返回一个 `int` 类型的值,表示操作是否成功,通常非零值表示成功,零表示失败。该函数在结构体 JSON 转换过程中用于将 JSON 中的整型字段映射到 C 结构体的对应字段中。 ### 结构体 JSON 转换代码中的潜在问题 在将结构体数据 JSON 格式进行转换时,需要注意以下潜在问题: 1. **类型不匹配问题**:如果 JSON 中的键值类型 `jso_obj_get_int` 期望的类型不匹配(例如该键对应的是字符串而非整数),则可能导致解析失败或错误的值被写入结构体字段中。此类错误在运行时才可能被发现,增加调试难度。 2. **键缺失问题**:如果 JSON 对象中缺少某个必要的键,则 `jso_obj_get_int` 返回失败,但如果没有对该返回值进行检查,可能导致结构体中的字段未被正确初始化,从而引入未定义行为。 3. **内存安全问题**:如果 `pValue` 是一个无效指针(如 NULL),则函数可能会尝试写入非法内存地址,导致程序崩溃或不可预测的行为。 4. **数据范围问题**:若 JSON 中的整数值超出了 C 语言中 `int` 类型的表示范围,则可能导致溢出,从而存储错误的值。例如,32 位系统中 `int` 的最大值为 2147483647,若 JSON 中的值为更大的整数,则会被截断。 5. **错误处理缺失**:如果调用者没有检查返回值,可能会忽略数据解析失败的情况,进而导致后续逻辑错误。 ### 示例代码 以下代码展示了如何安全地使用 `jso_obj_get_int` 并将其值映射到结构体字段中: ```c typedef struct { int start_minute; int end_minute; uint8_t day; } ALARM_PLAN_SECTION; int parse_alarm_plan_section(JSON_OBJPTR obj, ALARM_PLAN_SECTION *section) { int success = 1; if (!jso_obj_get_int(obj, "start_minute", &section->start_minute)) { // 处理错误,如设置默认值或记录日志 success = 0; } if (!jso_obj_get_int(obj, "end_minute", &section->end_minute)) { // 处理错误 success = 0; } int day_int; if (jso_obj_get_int(obj, "day", &day_int)) { section->day = (uint8_t)day_int; } else { // 处理错误 success = 0; } return success; } ``` 上述代码在调用 `jso_obj_get_int` 后检查返回值,并在失败时进行适当处理,确保结构体字段不会被错误数据污染。 ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值