C语言——指针

一、作用域

栈帧:每个函数只能看到自己的;(作用域)
例1:

void f(int a,int b)
{
	/*作用域1:j 在作用域2中创建 只能在作用域2中访问 作用域1看无法访问*/
	int i;
	for(i = 0 ; i< a+b ; i++)
	{
		/*作用域2:可访问外层作用域值 i a b*/
		int j;
	}
}

例2:

void f(int a,int b)
{
	/*作用域1:j 在作用域2中创建 只能在作用域2中访问 作用域1看无法访问*/
	int i;
	for(i = 0 ; i< a+b ; i++)
	{
		/*作用域2:可访问外层作用域值 i a b*/
		int j;
	}
}

void f2(int a,int b)
{
	/*作用域3:与f1中的实参毫无关系,他们是互不重叠的作用域*/
	f1(a+b,a-b);
}

例3:

void f(int a,int b)
{
	/*作用域1:j 在作用域2中创建 只能在作用域2中访问 作用域1看无法访问*/
	int i;
	for(i = 0 ; i< a+b ; i++)
	{
		/*作用域2:可访问外层作用域值 i a b*/
		int j;
		int u;/*内层作用域中创建另一个相同名字变量合法;影子变量*/
		u = 5;
	}
	/*修改作用域2中的u,不会改变作用域1中的u,影子变量是不好的编程类型 gcc编译器会提醒-Wshadow警告*/
}

二、swap函数

一个函数只能返回一个值,返回值可以修改调用函数中一项内容;
例:

int f1(int a,int b)
{
	return (a+b);
}

void f2(void)
{
	int a;
	a = f1(2,3);
	/*RL A*/
}

想要改变调用函数多个变量值(指针)
例:

void swap(int x,int y)
{
	/*将s与y进行交换*/
}

void f2(void)
{
	int a = 2;
	int b = 37;
	swap(a,b);
}

三、指针

引入指针概念:通过指针概念来解决上述问题;指针是一个变量(或是一个实参),其值为一个内存地址。为创建指针,在类型后面加上*;

type * ptr

int * iptr;  //名称 iptr 值 一个地址 地址中内容 一个整型
char * cptr; //名称 cptr 值 一个地址 地址中内容 一个字符
double *dptr;//名称 dptr 值 一个地址 地址中内容 一个双精度浮点数

程序员不能控制具体地址分配,为获取有效地址,提供了特殊语法:在变量前加&;

int a = 16//a是一个整型数
int * iptr;  //iptr是一个指针
iptr = &a;   //iptr的值是a的地址
//标识符 iptr 地址 101 值100
//标识符 a    地址 100 值16
//注:每次运行地址都发生改变 我们可以改变变量值,但是不能改变变量地址

**指针作用:**指针像其他变量类型一样,可以为同一个值;

检索存于指针所指地址处的值:

int a = 120;
int * iptr;
int c;
iptr = &a;
c = *iptr;/*把iptr的值看作一个地址来读取;到那个地址处读取并将其值赋给C*/
printf("%d",*iptr);
//如果*iptr在赋值符号(=)右边(RHS):解引指针;赋值符号不是必须的 读取地址所指向的值
//如果*iptr在赋值符号(=)左边(LHS):会以一种相似却相反的方式工作 修改地址所指向的值

讨论swap函数

void swap(int *a ,int *b/*a和c的地址*/) //函数实参必须是储存这些地址的指针
{
	/*将s与y进行交换*/
	int c = *a;
	*a = *b;
	*b = c;
}

void f2(void)
{
	int a = 2;
	int b = 37;
	swap(a,b);
}
//通过指针,一个函数可以访问(读写)在另一个栈帧的变量值;
int * f1(void)
{
	int m = 0;
	return &m;
}
void f2(void)
{
	int * iptr = f1();
	/*RL*/
	*iptr = 7;
}
//不能把m值从0改为7,因为m值存在f1栈帧中;
//指针进行读写只能在一个方向起作用;通过指针,一个函数可以读写储存在函数帧或它晓媚的栈帧中的值,读写栈帧上方帧中的值是不可能的

**指针类型与变量类型不一致:**不要这样去做;gcc编译器会出现-Wall;

四、数组和指针

  1. 数组下标总是从0开始的;
  2. 数组与指针之间是有着一种特殊关系的,在许多情况下数组和指针是没有区别的;
int c;
int arr[5];//arr的值看做一个指针,其值作为数组第一个元素的地址;
arr[2] = 9;//2是[]里面的索引,叫地址偏移量;
c = arr[2];
//1、arr的值看作一个指针,其值为数组第一个元素的地址
//2、找到那个地址之后两个元素的地址得到一个新的地址。2为地址偏移
//3、读取那个地址的值9
//4、把9写道c的值中

//arr总是可以看作一个指针,其值为数组第一个元素的地址。
//arr == &arr[0]

例:把一个数组中的元素添加在一起

int sumarr(int * intarr,int len)
{
	int ind;
	int sum2 = 0;
	for(ind = 0; ind < len ;ind ++)
	{
		sum2 += intarr[ind];
	}
	return sum2;
}
void f(void)
{
	int sum = 0;
	int arr[5];
	arr[0] = 4;
	arr[1] = -7;
	arr[2] = 2;
	arr[3] = 3;
	arr[4] = 9;
	sum = sumarr(arr , 5);
	/*RL*/
	printf("sum = *d \n",sum);
}

类型规则:

  1. 如果var类型是t,那么&var的类型是t*;
  2. 如果ptr的类型是t*,那么*ptr的类型是t;
  3. 如果arr是一个类型t的数组,那么每个元素储存着一个类型t的值;
  4. 如果arr是一个类型t的数组,那么arr(没有任何下标)的类型数t*,因为arr等效&arr[0];\
  5. 数组的名字总是一个指针;
  6. 指针不一定必须是数组;禁止野指针操作;

五、指针运算

指针可以通过(访问)数组的元素从而实现迭代:

#include <stdio.h>
#include <stdlib.h>

int main(int argc ,char * *argv)
{
  int arr1[] ={7, 2, 5, 3, 1, 6, -8, 16, 4};//【】之间不添加任何内容,就可以创建一个常量数组,编译器会自动计算数组长度
  char arr2[] ={'m', 'q' , 'k', 'z', '%', '>'};
  double arr3[] ={3.14, -2.718, 6.626, 0.529};

  int len1 = sizeof(arr1) / sizeof(int);//这种长度计算只对常量数组有效,malloc创建的不起作用
  int len2 = sizeof(arr2) / sizeof(char);
  int len3 = sizeof(arr3) / sizeof(double);

  printf("lengths = %d , %d , %d \n", len1,len2,len3);

  int * iptr = arr1;
  char * cptr = arr2;
  double * dptr = arr3;

  printf("values = %d , %c , %f \n",*iptr,*cptr,*dptr);

  iptr++;//指针增1,实际值增4
  cptr++;//指针增1,实际值增1
  dptr++;//指针增1,实际值增8

  printf("values = %d , %c , %f \n",*iptr,*cptr,*dptr);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值