指针赋值 int a[5]={.... ...}, a 、&a[0]、 &a三者之间的区别 浅析 C/C++求职面试必备考点(五)...

C语言指针与数组详解
本文详细解析了C语言中指针与数组的关系及使用技巧,包括如何通过指针访问数组元素,指针与数组名的区别,以及不同场景下指针运算的差异。

首先,来看代码:

#include <stdio.h>
void main()
{
char a[] = "BruceLee!";
char *p = a;
printf("%c\n", *(p+4));
printf("%c\n", p[4]);
printf("%s\n", p);
printf("%c\n", a[4]);
printf("%c\n", *(a+4));
printf("%s\n", a);
}

首先程序声明了字符数组a,并且初始化,这个记得是默认后面加'\0'的。然后声明了字符指针,指向数组a的首地址,也是a[0]的地址,这里
char *p = a; 等价于char *p = &a[0]
。*(p+4) = p[4] = a[4] = *(a+4),这是最终的结果。这里需要注意的是,字符指针p和数组的名字a每个都有两种引用方法,一种是数组的引用方法如a[4],一种是*(a+4),指针的方法。

注意这里的

printf("%s\n", p);打印的内容仍然是
BruceLee!

也就是说我们仅仅是通过*(p+4),来查看里面的内容,但并没有改变p的指向。p仍然指的是首地址,所以打印出的字符串也是从首字符开始的。

如果我们再代码中,加上这两句:

printf("%c\n", *p++);
printf("%s\n", p);

第一句执行结果是打印首字符‘B’,然后p往后移一位。所以下面一句打印字符串,直接从第二个字符开始的,结果是ruceLee。

总结:(*p+4)这种方式并未改变指针p的指向。只有p++、p--或者p+=4类似这种方式,才改变指针p的指向!

下面再来看一个例子:

#include <stdio.h>
void main()
{
    int a[5] = {1, 2 ,3 , 4, 5};
    int *p = a;
    printf("%d\n", a[0]);
   printf("%d\n", *p);
   printf("%d\n", p);
   int *q = (int *)a;
   printf("%d\n", q[0]);
   
}
需要说的有两点:

1,

printf("%d\n", p);
这句话是不能正常执行的,打印出来和数组a毫无相关的数字。不要期望像printf(“%s”, p)p为首地址。这种方式企图打印整个数组a的内容!

2,int *p = a; 和 int *q = (int *)a,这两句话效果是一样的,在这里加不加前面的强制转换都一样。

再看这个迷惑性强的例子:

#include <stdio.h>
void main()
{
    int a[5] = {1, 2 ,3 , 4, 5};
     int *m = (int *)&a[0];
     printf("%d\n", *(m + 1));
    int *p = (int *)&a;
    printf("%d\n", *(p + 1));
    int *q = (int *)(&a + 1);
    printf("%d\n", *(q-1));
    int *w = (int *)(&a[0] + 1);
     printf("%d\n", *(w-1)); 

   
}
有三个要点:

1,注意上面我们说那么(int *)可有可无,但是当加了&后,在int *m = (int *)&a[0]这里,如果不加强制转换会报警,因为这里取了地址,最好强制转换一下!

2,(int*)(&a[0]) 和(int *)(&a),从打印m和p的值来看,貌似这两种操作是没有区别的,但其实并非如此!&a[0] = a,都是代表数组a的首地址,也就是a[0]的地址。但&a是整个对象,也就是a这个数组整体的首地址。紧跟其后的指针q的申明,&a + 1究竟是谁的地址呢?

我们要切记,对指针进行加1操作,得到是下一个元素的地址,而不是原有地址的数值直接加1,这点大家肯定都知道。假设类型为x,则加1后,指针向后移动sizeof(x),移动是以sizeof(x)为单位的!

我怎么越说越不明白了,其实就是a和&a[0]以及&a,三者的区别!

前两个是等价的。&a上面也说过了,把a看成一个整体,所以&a + 1是a下一个对象的地址,即&a + 1,以相对a或者&a[0]来说,移动了sizeof(a) = 5*4 = 20个字节,即这里指针q指向a[5]!所以*(q - 1)的值是5,也就是a[4] 的值。 为了对照区别,最后我取了(&a[0] + 1)来做对照,w在申明时指向a【1】,*(q-1)的值是1,也就是a[0]的值。

3int *n = a 等价于 int *n = (int *)&a[0] ,从指向上来看也等价于 int *n = (int *)&a;

但 当有指针加减操作时,两者的结果绝不相同!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

如:int *n = (int *)(&a[0] + 1)绝不等于 int *n = (int *)(&a + 1)。




<think> 我们正在讨论的问题是关于C语言中指针和结构体的正确用法。用户之前询问了`*p = &amp;data.a`这种写法的正确性,并得到了详细解答。现在用户提出了一个新的问题:“我想确认 'int *p = &amp;data.a' 这种写法是否可以为指针p赋予地址 请问int *p = &amp;data.a 写法能否为指针p赋地址”。 根据之前的讨论,我们已经明确: - `int *p = &amp;data.a;` 是定义指针变量p的同时将其初始化为`data.a`的地址,这是正确的写法。 - 而之前讨论的错误写法是`*p = &amp;data.a;`(注意这里的星号在左边,表示对指针解引用后赋值)。 现在用户的问题明确指向了正确的写法:`int *p = &amp;data.a;`。因此,我们需要确认这种写法是否合法。 引用[1]中有一个类似的例子: > 例如: int a = 10; // 定义一个整数变量 a > int *p = &amp;a; // 定义一个指针变量 p,并让它指向 a 的地址 这个例子与用户的问题几乎一致,只是用户使用的是结构体成员`data.a`,而引用[1]使用的是普通变量`a`。原理相同:`&amp;data.a`取得结构体成员`a`的地址,然后将其赋值给一个整型指针变量`p`。因此,这种写法完全正确。 另外,引用[3]提到: > *p是数值,p是地址 这进一步说明,在定义指针变量时,我们直接使用`p`(不带星号)来接收地址。而`int *p`中的星号只是表示`p`是一个指针类型。 因此,回答如下: </think> ### ✅ 正确写法:`int *p = &amp;data.a` 这种写法**完全正确**,能够为指针 `p` 正确赋予 `data.a` 的地址。以下是详细分析: #### 1. **语法解析** ```c int *p = &amp;data.a; ``` - `&amp;data.a`:获取结构体成员 `data.a` 的**内存地址**(类型为 `int*`) - `int *p`:声明指向整型的指针变量 `p` - **赋值操作**:将 `data.a` 的地址(`int*` 类型)赋值指针 `p`(`int*` 类型),类型完全匹配[^1] #### 2. **正确性验证** ```c #include <stdio.h> struct Data { int a; } data = {10}; // 初始化结构体 int main() { int *p = &amp;data.a; // ✅ 正确:p指向data.a的地址 printf("data.a地址:%p\n", &amp;data.a); // 输出地址 printf("指针p的值:%p\n", p); // 与data.a地址相同 printf("通过p访问值:%d\n", *p); // 输出10(解引用正确) *p = 20; // ✅ 通过指针修改data.a的值 printf("修改后data.a:%d\n", data.a); // 输出20 return 0; } ``` **输出结果**: ``` data.a地址:0x7ffd42a3e5dc 指针p的值:0x7ffd42a3e5dc 通过p访问值:10 修改后data.a:20 ``` #### 3. 与错误写法的对比 | 写法 | 类型分析 | 结果 | |------|----------|------| | **`int *p = &amp;data.a;`** | `p`(int*) = `&amp;data.a`(int*) | ✅ 正确<br>指针存储地址 | | **`*p = &amp;data.a;`** | `*p`(int) = `&amp;data.a`(int*) | ❌ 错误<br>类型不匹配 | #### 4. 核心原则 1. **指针变量存储地址** `p` 是**指针变量**,应直接存储地址值(需用 `&amp;` 取址) 2. **解引用操作访问数据** `*p` 是**解引用操作**,访问指针指向的实际数据(不能赋值地址) 3. **结构体成员取址规则** 结构体成员的地址需通过 `&amp;` 获取,语法为:`&amp;(结构体变量.成员名)`[^1] --- ### 相关问题 1. 如果结构体指针是动态分配的,`int *p = &amp;(dp->a)` 是否安全? 2. 当结构体作为函数参数时,指针初始化方式有何变化?参考引用[4][^4] 3.指针和空指针访问结构体成员时会产生什么具体错误?参考引用[2][^2] 4. 为什么数组名可直接作为指针使用而结构体变量名不行?参考引用[1][^1] [^1]: 例如:`int a = 10; int *p = &amp;a;` 中,指针 `p` 存储 `a` 的地址,类型匹配[^1]。 [^2]: 未初始化的指针解引用会导致未定义行为,如访问已释放内存 `printf("%d\n", *p);`[^2]。 [^4]: 函数参数传递涉及栈操作,指针作为参数传递时需确保有效性[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值