出参传递数组指针_每天一点C / 一维数组和指针

ddfc18998d0c6a69099f24200e85e54c.png

哈喽,我是老吴,继续记录我的学习心得。

每天一点系列是我对微习惯的践行。现在能做到每天一点 C,将来就会有更多的每天一点系列,没人规定嵌入式软件工程师就只能学习 C 语言和折腾 Linux,不要给自己设限。

为什么是每天一点?
养成写作习惯的第一步:放弃追求大段的、固定的、安静的写作时间,培养随时写作的能力。

同样的技巧也能应用到技术学习上,工程师也可以放弃追求大段的、固定的、安静的看书写代码的时间。遇到一个新知识,第一时间找到相关资料,找到切入点并将其记录在自己的技术笔记中,并且定期复查及完善。


一、每天一点C / 数组和指针

正文目录:

1. 数组名是该数组首元素的地址
2. 用指针操作数组
3. 数组和指针的关系密切
4. 编写处理一维数组的函数:传递数组起始地址+数组长度
5. 编写处理一维数组的函数:传递数组起始地址+结束地址

学习环境:

  • Ubuntu 16.04
  • gcc version 5.4.0

1. 数组名是该数组首元素的地址

演示 demo:

#define MONTHS 12
int main(void){
    int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};
    
    if (days == &days[0])
        printf("TRUE\n");
    
    return 0;
}

运行效果:

$ gcc array_name.c -o array_name

$ ./array_name 
TRUE

相关要点:

  • 数组名和该数组首元素的地址都是常量,在程序的运行过程中,不会改变。

2. 用指针操作数组

演示 demo:

#define SIZE 4
int main(void){
    short dates [SIZE];
    short * pti;
    short index;
    double bills[SIZE];
    double * ptf;
    
    pti = dates;    // assign address of array to pointer
    ptf = bills;
    printf("%23s %15s\n", "short", "double");
    for (index = 0; index         printf("pointers + %d: %10p %10p\n",  index, pti + index, ptf + index);
    
    return 0;
}

运行效果:

$ gcc point_array.c -o point_array

$ ./point_array
                  short          double
pointers + 0: 0x7ffc890b17c0 0x7ffc890b17d0
pointers + 1: 0x7ffc890b17c2 0x7ffc890b17d8
pointers + 2: 0x7ffc890b17c4 0x7ffc890b17e0
pointers + 3: 0x7ffc890b17c6 0x7ffc890b17e8
  • 指针的值是它所指向对象的地址,指针前面使用 * 运算符可以得到该指针所指向对象的值。

  • %p 会以十六进制显示指针的值

  • 必须声明指针所指向对象类型,原因之一:计算机既要知道储存对象的地址,又要知道储存对象需要多少字节。

  • 指针加 1 指的是增加一个数据存储单元。对数组而言,这意味着加 1 后的地址是下一个元素的地址,而不是下一个字节的地址。


3. 数组和指针的关系密切

以下关系表明了数组和指针的关系十分密切:

days + 2 == &days[2]   // TRUE,相同的地址
*(days + 2) == days[2] // TRUE,相同的值

演示 demo:

int main(void){
    int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};
    int index;
    
    for (index = 0; index         printf("Month %2d has %d days.\n", index +1, *(days + index));
    
    return 0;
}

运行效果:

$ gcc point_array2.c -o point_array2

$ ./point_array2 
Month  1 has 31 days.
Month  2 has 28 days.
...
Month 12 has 31 days.
  • C 语言在描述数组表示法时借助了指针:ar[n]的意思是*(ar + n)。

  • 可在编写程序时适时使用 数组表示法或指针表示法,这是两种功能等效的方法。大多数情况下可以用指针表示数组,反过来,也可以用数组表示指针。

  • 编译器编译这两种写法生成的代码相同。


4. 编写处理一维数组的函数:传递数组起始地址+数组长度

假设要编写一个处理数组的函数,该函数返回数组中所有元素之和,待处理的是名为 data 的 int 类型数组,应该如何调用该函数?

演示 demo:

int sum(int ar[], int n);
int main(void){
    int data[SIZE] = {20,10,5,39,4,16,19,26,31,20};
    long answer;
    
    answer = sum(data, SIZE);
    printf("The total number of data is %ld.\n", answer);
    printf("The size of data is %zd bytes.\n",
           sizeof data);
    
    return 0;
}

int sum(int ar[], int n){
    int i;
    int total = 0;
    
    for( i = 0; i         total += ar[i];
    printf("The size of ar is %zd bytes.\n", sizeof ar);
    
    return total;
}

运行效果:

$ gcc func_array.c -o func_array
func_array.c: In function ‘sum’:
func_array.c:26:53: warning: ‘sizeof’ on array function parameter ‘ar’ will return size of ‘int *’ [-Wsizeof-array-argument]
     printf("The size of ar is %zd bytes.\n", sizeof ar);
                                                     ^
func_array.c:19:13: note: declared hereint sum(int ar[], int n)
$ ./func_array
The size of ar is 8 bytes.
The total number of data is 190.
The size of data is 40 bytes.
  • 数组名是该数组首元素的地址,所以实参 data 是一个储存int 类型值的地址,那么函数 sum 的形参数就应该是一个指针。

  • 在函数声明或函数定义中,int ar[] 等效于 int *ar,本质上都应该看作是指针。

  • 只有在函数声明或函数定义中,才可以用int ar[]代替int *ar

  • 函数声明可以省略参数名,所以下面 4 种原型都是等价的:

  • 注意编译器的警告信息:warning: ‘sizeof’ on array function parameter ‘ar’ will return size of ‘int *’,这是在提示程序员你打印的是指针的 size,而不是整个数组的 size。

int sum(int *ar, int n);
int sum(int *, int);
int sum(int ar[], int n);
int sum(int [], int);
  • 一般会把数组的参数作为其中一个参数传递给处理数组的函数。

5. 编写处理一维数组的函数:传递数组起始地址+结束地址

演示 demo:

int sump(int * start, int * end);
int main(void){
    int data[SIZE] = {20,10,5,39,4,16,19,26,31,20};
    long answer;
    
    answer = sump(data, data + SIZE);
    printf("The total number of data is %ld.\n", answer);
    
    return 0;
}

int sump(int * start, int * end){
    int total = 0;
    
    while (start     {
        total += *start;
        start++;next element
    }
    
    return total;
}

运行效果:

$ gcc func_array2.c -o func_array2

$ ./func_array2
The total number of marbles is 190.

相关要点:

  • 注意 answer = sump(data, data + SIZE) 和 while (start < end),这是一种推荐用法,简洁且清晰。因为下标从 0 开始,所以 data + SIZE 指向数组末尾的下一个位置。

  • data + SIZE 是推荐的,但是 data[SIZE] 则是错误的。

  • 处理数组的函数实际上用指针作为参数,但是在编写这样的函数时,可以选择是使用数组表示法还是指针表示法。数组表示法让函数是处理数组的这一意图更加明显,而对于喜欢指针的程序员,使用指针表示法,则觉得使用指针更自然。

二、思考技术,也要思考人生

我喜欢学习技术,但我更爱学习如何生活

你和我各有一个苹果,如果我们交换苹果的话,我们还是只有一个苹果。但当你和我各有一个想法,我们交换想法的话,我们就都有两个想法了。

962eb0117e46f8e5581d3f90b3d122ab.png

如果你也对 嵌入式系统 (Linux、RTOS、OpenWrt、Android) 和 开源软件 感兴趣,并且想和更多人互相交流学习的话,请关注我的公众号:嵌入式Hacker,一起来学习吧。

无论是关注或转发,还是打赏,都是对作者莫大的支持。对了,记得点 在看和点赞 ,如果你还想看到我的推送的话。

祝各位工作顺利,家庭幸福,财源滚滚~

ps:
欢迎加入我的微信群:加我微信,我拉你进群,暗号(加群)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值