C语言自学记录-Class10-指针(重点)-3-数组和指针

P131. 指针-3-数组和指针

说明:

本篇记录的是自学C语言的相关过程记录,参考资料是B站郝斌老师的C语言自学教程。本人之前学过一点python,但是觉得C语言还是有必要学一下的。因为刚开始学C语言,所以本篇文章会不断更新。
因为是学习记录,所以条理可能并不是很清晰,后续感觉学的差不多的时候会重新整理一下。

指针和一维数组

一维数组名:

一维数组名是个指针常量,它存放的是一维数组第一个元素的地址。

# include <stdio.h>

int main(void)
{
    int a[5]; // a 是数组名,5是数组元素的个数,元素就是变量 a[0] -- a[4]
    printf("%#X\n", &a[0]);
    printf("%#X\n", a);
    // 一维数组a的地址和第一个元素a[0]的地址是一样的。
	return 0;    
}
下标和指针的关系:

如果p是一个指针变量,则p[i]永远等价于*(p+i)

# include <stdio.h>

int main(void)
{
    /*
        数组和下标的关系:
    */
    // 未初始化:
    int a[5]; // 未初始化的数组a,包含5个元素,默认是垃圾值。
    printf("%d\n", a[0]); // 结果正是垃圾值。

    // 不完全初始化:
    int b[5] = {1,2,3}; // 不完全初始化时,未赋值的元素默认为0
    printf("%d, %d\n", b[1], b[4]); // 输出为 2, 0

    // 完全初始化:
    int c[5] = {1,2,3,4,5};
    printf("%d\n", c); // 一维数组 c 的地址
    printf("%d\n", &c[0]); // 一维数组 c 的第一个元素的地址

    // 数组与下标的关系:p[i] 永远等价于 *(p+i)
    printf("%d\n", *c); // 数组 c 存放的是 c[0] 的地址,所以 c 指向 c[0],所以 *c 就等同于 c[0],也就是 *c 的值为 1
    printf("%d\n", *(c+2)); // *(c+2) 存放的是 c[2] 的地址,(c+2)指向c[2],所以 *(c+2)等同于 c[2],也就是3

    // 由 c[0] 到 c[2],内存地址移动了2个单元,因为元素是int类型,也就是2*4=8个字节,内存地址向后移动8个字节。
    printf("%d\n", &c[0]); // 1941961344
    printf("%d\n", &c[2]); // 1941961352  二者差值正好是8
    return 0;
}

如果一个函数需要处理一个一维数组,那么需要接收该数组的那些信息?(后者说,如果要确定一个数组,那么需要哪些信息?)

答:需要两个参数(数组的首地址,数组长度)

# include <stdio.h>
/*
 利用函数处理数组,需要2个信息:数组名称和数组长度。
 详情如下所示:
*/

// 定义一个函数,读取一个一维数组的每个元素以及相应的地址。
void f(int * pArr, int len)
{
 // pArr 是一维数组名称,存放的是第一个元素的位置,pArr指向第一个元素,所以 *pArr就是数组的第一个元素。
 // len 是数组的长度。

 printf("%d\n", *pArr); // 输出值应该和数组的第一个元素一样
 printf("%d\n", pArr); // 输出的地址也应该和数组的第一个元素一样

 // 根据第一个元素的地址以及一维数组的长度,遍历数组中的每一个元素及其地址
 int i; // i 是地址增量
 for (i=0; i<len; ++i)
     printf("element = %d, index = %d, address = %d, %d, %d\n", *(pArr+i), i, pArr+i, &pArr[i], &*(pArr+i));

 /*
     这里的 pArr 是 int * 类型, i 是 int类型。所以 pArr + i 就表示从pArr的地址向后移动 i 个单元(int类型,也就是 i*4个字节).
 */
}


int main(void)
{
 int a[5] = {1,2,3,4,5};
 int b[6] = {-1,-2,-3,-4,-5,-6};
 int c[100] = {1, 99, 22, 33};
 // 一维数组名是一个指针常量,它存放的是数组中第一个元素的地址。
 // 也就是说 数组 a 的类型是 int *  所以函数的数组名称也得是 int * 类型。

 f(a, 5);
 printf("%d\n", a[0]);
 printf("%d\n", &a[0]);


 return 0;
}

根据上述代码可以学到:

**1. pArr+i,&pArr[i] 和 &*(pArr+i) 都是数组中第i+1个元素的地址; **

2. 虽然 pArr 是 int * 类型, i 是 int 类型,但是二者可以相加,也就是说此处的 pArr+i 表示内存地址向后移动 i 个单元,由于 i 是 int 类型,所以实际内存地址在数值上 + 4*i

指针变量的运算:
  1. 指针变量不能加、乘、除,只能相减,就是说两个指针之间只能做减法。
  2. 两个指针相减也是有要求的:当两个指针变量指向的是同一块连续空间中的不同存储单元,二者才可以相减(二者之间的差值是元素个数之差,不是字节之差)。
# include <stdio.h>

int main(void)
{
    int a[5];
    int * p;
    int * q;

    p = &a[1];
    q = &a[4];

    printf("p address = %d\n", p);
    printf("q address = %d\n", q);
    printf("q - p adderss = %d\n", q-p);

    return 0;
}
一个指针变量占几个字节?

答:32位操作系统占4个字节,64位操作系统占8个字节。

一个指针变量,无论它指向的变量占几个字节,该指针变量本身只占4(32位)或8(64位)个字节。

sizeof(数据类型),返回的是该数据类型所占的字节数。

sizeof(变量名称),返回的是该变量所占的字节数。

例如:sizeof(int) = 4sizeof(char) = 1sizeof(double) = 8

# include <stdio.h>

int main(void)
{
    char ch = 'A';
    int i = 99;
    double x = 66.6;

    char * p = &ch;
    int * q = &i;
    double * r = &x;

    printf("%d %d %d\n", sizeof(p), sizeof(q), sizeof(r));
    return 0;
}

/*
	郝斌老师课程中,输出是 4 4 4
	自己电脑中输出的是 8 8 8
*/

至于原因,也可以理解(以代码中的x*r为例):

  1. 首先要理解指针变量存储的是内存地址,代码中指针变量r存放的是普通变量x的内存地址(r指向x),而且x有8个字节。

  2. 在内存中,一个字节有一个地址编号,所以x有8个字节,也就有8个地址编号。

  3. 指针变量r存放的是x的内存地址,更确切地说,存放的是x中第一个字节对应的地址编号。

  4. 那么此时就有一个问题:指针变量r只存放了x中的第一个字节对应的地址编号,但是r又指向x,那么r是怎么仅仅通过第一个字节的地址编号来确定整个x的?

    答:r通过数据类型来确定长度(上述代码中x的类型是double,也就是说长度是8),由此来确定该连续空间中的后面7个字节的地址。

  5. 至于为什么此处的输出和老师课程上的输出不一致,原因也很简单:

    1. 郝斌老师那个时候电脑中CPU的控制线有32条,所以可以控制32位,也就对应这4个字节。
    2. 现在电脑中CPU控制线有64条,所以也就可以控制64位,对应8个字节(因为暂时没有学计算机组成原理,所以此处推测是64位。后续学完计组之后再来加以确认)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值