抓住指针的精髓,才算掌握了 C 语言的灵魂!

本文深入探讨C语言中的指针与数组概念,解析数组传参的实质,揭示数组首元素地址与整个数组地址的区别,以及变量在内存中不同区域的存放方式。通过实例演示,帮助读者理解指针与数组的复杂应用。

作者 | 五道杠的小屁孩wwk

责编 | 夕颜

出品 | 优快云博客

学习C肯定会碰到指针,指针是C的灵魂。所以学好指针很关键,这里写一些指针方面的容易错的或者易混淆的知识点还有自己不会的盲点,以便之后复习时用。

数组传参和数组形参

1.1 数组传参

如果函数遇到数组传参的,不论是什么形式的形参,只要是数组,那么被调函数都将这个形参都当做指针来使用。

#include "stdio.h"




PrintArray(int *a, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%5d", a[i]);
}
printf("\n");
}




int main(void)
{




int a[] = { 3,4,5,6,7,7,8 };




int num = sizeof(a) / sizeof(a[0]);
PrintArray(a, num);




system("pause");
}

一般我们使用数组传参。

下面还有一种形参表示方法也很常用,效果其实是一样的。

#include "stdio.h"




PrintArray(int *a, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%5d", a[i]);
}
printf("\n");
}








PrintArray1(int a[], int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%5d", a[i]);
}
printf("\n");
}
int main(void)
{




int a[] = { 3,4,5,6,7,7,8 };




int num = sizeof(a) / sizeof(a[0]);
PrintArray(a, num);




PrintArray1(a, num);
system("pause");
}

甚至还有一种方法:

#include "stdio.h"




PrintArray(int *a, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%5d", a[i]);
}
printf("\n");
}




PrintArray1(int a[], int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%5d", a[i]);
}
printf("\n");
}




PrintArray2(int a[7], int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%5d", a[i]);
}
printf("\n");
}
int main(void)
{




int a[] = { 3,4,5,6,7,7,8 };




int num = sizeof(a) / sizeof(a[0]);
PrintArray(a, num);




PrintArray1(a, num);




PrintArray2(a, num);
system("pause");
}

1.2 数组传参实质

数组实质传的都是指针,不论什么表现形式。

#include "stdio.h"




PrintArray(int *a, int num)
{
int i,num1;
num1 = sizeof(a) / sizeof(a[0]);
printf("num = %5d",num1);




for (i = 0; i < num; i++)
{
printf("%5d", a[i]);
}
printf("\n");
}




PrintArray1(int a[], int num)
{
int i,num1;
num1 = sizeof(a) / sizeof(a[0]);
printf("num = %5d", num1);
for (i = 0; i < num; i++)
{
printf("%5d", a[i]);
}
printf("\n");
}




PrintArray2(int a[7], int num)
{
int i,num1;
num1 = sizeof(a) / sizeof(a[0]);
printf("num = %5d", num1);
for (i = 0; i < num; i++)
{
printf("%5d", a[i]);
}
printf("\n");
}
int main(void)
{




int a[] = { 3,4,5,6,7,7,8 };




int num = sizeof(a) / sizeof(a[0]);
PrintArray(a, num);




PrintArray1(a, num);




PrintArray2(a, num);
system("pause");
}

可以看到num1的值均为1。

实参都是数组,形参都是指针,无论什么形式。

数组首元素地址和整个数组地址

#include "stdio.h"




int main(void)
{
int a[10];




printf("a的大小 = %d\n", sizeof(a));




printf("a = %d\n", a);




printf("a + 1 = %d\n", a + 1);




printf("&a = %d\n", &a);




printf("&a + 1 = %d\n", &a + 1);
system("pause");
}

从这组输出我们可以看到几点:

  • a数组大小是40。因为一个int是4字节,一共10个。

  • 数组a和&a值一样

  • 但是a是数组首元素地址,而&a是整个数组地址。

  • 这个原因也导致另外两个值不同。a+1就是第二个元素地址,偏移4字节

  • &a+1是相当于偏移整个数组大小,也就是40字节。

变量在内存中的位置

变量在内存中有四个地方可以存放,读取修改变量实质都是通过指针修改。

3.1 变量存放的区域

3.2 常量例子

#include "stdio.h"




char *GetChar1(void)
{
char *p1 = "abcdefg";
return p1;
}




char *GetChar2(void)
{
char *p2 = "abcdefg1";
return p2;
}




int main(void)
{
char *p1 = NULL;
char *p2 = NULL;




p1 = GetChar1();
p2 = GetChar2();
//打印数据
printf("p1 = %s\n", p1);   
printf("p2 = %s\n", p2);
//打印地址
printf("p1 = %5d\n", p1);
printf("p2 = %5d\n", p2);
system("pause");
}

在内存中表示为:

因为GetChar函数里面都是指针所以都放在栈区,而常量都在全局区。

当被调函数return之后,上面两个指针被释放,然后将地址赋给main函数里面的指针,他们就指向相应的值。

接下来,还有一个易错的点!!!

#include "stdio.h"




char *GetChar1(void)
{
char *p1 = "abcdefg1";
return p1;
}




char *GetChar2(void)
{
char *p2 = "abcdefg1";
return p2;
}




int main(void)
{
char *p1 = NULL;
char *p2 = NULL;




p1 = GetChar1();
p2 = GetChar2();
//打印数据
printf("p1 = %s\n", p1);   
printf("p2 = %s\n", p2);
//打印地址
printf("p1 = %5d\n", p1);
printf("p2 = %5d\n", p2);
system("pause");
}

main函数里面指针地址是一样的

3.3 堆和栈例子

用户自己申明的变量是在堆中存放的,只有用户释放。

#include "stdio.h"




char *GetString(int num)
{
char *s = NULL;
s = (char *)malloc(sizeof(char)*num);
if (s == NULL)
{
return NULL;
}
return s;
}
int main(void)
{
char *p1 = NULL;
p1 = GetString(10);
if (p1 == NULL)
{
return;
}
strcpy(p1, "abcdefg");
printf("%s\n", p1);
system("pause");
}

内存中分布:

当GetString()被调用后,s释放之后,malloc分配的空间还是存在,所以还能继续打印。

接下来的问题在实际写的过程中会犯错:

#include "stdio.h"








char *GetString(int num)
{
char *s = NULL;
s = (char *)malloc(sizeof(char)*num);
if (s == NULL)
{
return NULL;
}
return s;
}




char *GetString1(void)
{
char s1[10];
strcpy(s1, "qwerty");
printf("%s\n", s1);
return s1;
}
int main(void)
{
char *p1 = NULL;
char *p2 = NULL;
p1 = GetString(10);
if (p1 == NULL)
{
return;
}
p2 = GetString1();
strcpy(p1, "abcdefg");
printf("%s\n", p1);
printf("%s\n", p2);
system("pause");
}

这时的p2其实打印不出来或者程序死机了。这是因为GetString1()中的s1变量是申明在栈区中,当调用结束后,被释放了,那块区域中的qwerty就没了。但是地址还是那个10字节的起始地址,并没有全部return出来。

其他

内存中的栈是开口向下的。


版权声明:本文为优快云博主「五道杠的小屁孩wwk」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.youkuaiyun.com/weixin_36101480/article/details/106181096


【END】

更多精彩推荐
☞尤雨溪:重头来过的 Vue 3 带来了什么?
☞原来 Kylin 的增量构建,大有学问!| 原力计划
☞可怕!CPU 竟成了黑客的帮凶!
☞如何用NLP辅助投资分析?三大海外机构落地案例详解
☞这 10 个云计算错误,会让你的业务一蹶不振!
☞好扑科技结合区块链行业发展趋势,重磅推出“好扑区块链合伙人”计划
点击阅读原文,精彩继续。
你点的每个“在看”,我都认真当成了喜欢
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值