指针和数组分析

数组的本质:
(1)数组是一段连续的内存空间
(2)数组的大小为sizeof(array_type)*array_size
(3)数组名可看做指向数组第一个元素的常量指针

指针的运算
指针与整数的运算规则为:

p+n;	(unsigned int)p+n*sizeof(*p);

指针之间的减法运算
(1)指针之间只支持减法运算
(2)参与减法运算的指针类型必须相同

p1-p2;    ((unsigned int)p1 - (unsigned int)p2) / sizeof(type)

注意:
1.只有当两个指针指向同一个数组中的元素时,指针相减才有意义,其意义为指针所指元素的下表差
2.当两个指针指向的元素不在同一个数组中时,结构未定义
3.指针也可以进行关系运算(<,<=<.,>=)
4.指针关系运算的前提是同时指向同一个数组中的元素
5.任意两个指针之间的比较运算(==,!=) 无限制
6.参与比较运算的指针类型必须相同

指针运算的应用:
数组的边界位置,数组元素最后一个元素的后一个元素位置,这个语法合法

#include <stdio.h>

#define DIM(a) (sizeof(a) / sizeof(*a))

int main()
{
    char s[] = {'H','e','l','l','o','w'};
    char* pBegin = s;
    char* pEnd = pBegin + DIM(s);
    char* p = NULL;
    
    printf("pBegin = %p\n", pBegin);
    printf("pBegin = %p\n", pEnd);
    printf("size = %d\n", pEnd  - pBegin);

    for(p = pBegin; p < pEnd; p++)
        printf("%c", *p);
    
    return 0;
}

下标形式vs指针形式
(1)指针以固定增量在数组中移动时,效率高于下标形式
(2)指针增量为1且硬件具有硬件增量模型时,效率更高
(3)下标形式与指针形式的转换
a[n] == *(a+n)
*(n+a) == n[a];
数组可以当做常量指针使用,指针也可以当做数组名使用

int a[] = {1,2,3,4,5};  //a的地址0x601040
extern int a[];	//正确
extern int* a;		//段错误

#include <stdio.h>

int main()
{
    extern int* a;  //仅仅声明
    
    printf("&a = %p\n", &a); //a的地址,去a这个标识符的地址值
    printf("a = %p\n", a);		//a是指针变量,保存地址值,然后到0x601040地址中取四个字节,也就是0001,打印出0x1(a指针,所以到指针所对应的地址中取4个字节)
    printf("*a = %d\n", *a);	//0x1地址是预留给操作系统使用,用户访问这个地址的值就会产生段错误
    
    return 0;
}

在这里插入图片描述在这里插入图片描述

a和&a的区别:
a为数组首元素的地址
&a为整个数组的地址
a和&a的区别在于指针运算

a+1  ==  (unsigned int)a + sizeof(*a)
&a+1  ==  (unsigned int)(&a) + sizeof(*&a)  ==  (unsigned int)(&a) + sizeof(a)
#include <stdio.h>

int main()
{
    int a[5] = {1, 2, 3, 4, 5};
    int* p1 = (int*)(&a + 1); 
    int* p2 = (int*)((int)a + 1);
    int* p3 = (int*)(a + 1);
    
    printf("%d, %d, %d\n", p1[-1], p2[0], p3[1]);
    
    return 0;
}

在这里插入图片描述在这里插入图片描述0x0200000000十进制 = 33554432

linux操作系统是小端模式

数组参数
数组作为函数参数时,编译器将其编译成对应的指针

void f(int a[]); ==  void f(int* a)
void f(int a[5]); ==  void f(int* a)
#include <stdio.h>

void func1(char a[5])
{
    printf("In func1: sizeof(a) = %d\n", sizeof(a));
    
    *a = 'a';
    
    a = NULL;
}

void func2(char b[])
{
    printf("In func2: sizeof(b) = %d\n", sizeof(b));
    
    *b = 'b';
    
    b = NULL;
}

int main()
{
    char array[10] = {0};
    
    func1(array);
    
    printf("array[0] = %c\n", array[0]);
    
    func2(array);
    
    printf("array[0] = %c\n", array[0]);
    
    return 0;
}

结论:
一般情况下,当定义的函数中有数组参数时,需要定义另一个参数来表示数组的大小
(1)数组名和指针仅使用方式相同
数组名的本质不是指针,指针的本质不是数组
(2)数组名并不是数组的地址,而是数组首元素的地址
(3)函数的数组参数退化为指针

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言中的结构体是一种自定义的数据类型,可以用于存储不同类型的数据项。结构体中的数据项称为成员,可以是整型、字符型、浮点型等任意类型。我们可以通过定义结构体变量来使用结构体,并访问其成员。 指针则是存储内存地址的变量,可以指向任意类型的数据。通过指针,我们可以间接访问和修改存储在内存中的数据。结合结构体和指针的特性,可以实现对结构体的灵活操作。 结构体与指针的应用非常广泛。首先,我们可以通过指向结构体的指针来传递结构体作为函数参数,从而避免在函数调用过程中复制整个结构体的开销。这样的用法在处理大型结构体或者结构体数组时尤为重要。 其次,结构体的成员也可以是指针类型,这样可以实现动态内存分配和数据管理。例如,可以使用指向结构体的指针来创建动态大小的结构体数组,并通过指针来访问和操作数组的元素。 此外,结构体指针也常用于实现数据结构,如链表、树等。通过指针的相互连接,可以实现复杂的数据结构,并对其进行插入、删除、遍历等操作。 总结起来,结构体与指针在C语言中的应用非常灵活和广泛。通过结构体指针,我们可以实现对结构体的动态分配和管理,节省内存开销。同时,结构体指针也为实现复杂的数据结构和算法提供了便利。因此,学习和掌握结构体与指针的应用对于C语言的程序开发非常重要。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值