C语言指针总结提高(内存位置)

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

1.数组传参和数组形参

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。
实参都是数组,形参都是指针,无论什么形式。

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

#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.变量在内存中的位置

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

3.1变量存放的区域

栈区 (stack)程序局部变量,编译器自动分配
堆区(heap)Malloc new free delete 操作系统来管理 一般有程序员动态分配
全局区/静态区(static)全局变量和静态变量存放地方,程序结束后由操作系统释放
常量区常量存放区域,程序结束后由操作系统释放

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出来。

4.其他

内存中的栈是开口向下的。
在这里插入图片描述

  • 9
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值