C语言-对指针的理解(2)

1.数组指针(指向数组的指针)

数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element)。数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存。

  • 以int arr[] = { 99, 15, 100, 888, 252 };为例,该数组在内存中的分布如下图所示:
    在这里插入图片描述
  • 定义数组时,要给出数组名和数组长度,数组名可以认为是一个指针,它指向数组的第 0 个元素。在C语言中,我们将第 0 个元素的地址称为数组的首地址。以上面的数组为例,下图是 arr 的指向:

在这里插入图片描述
下面的例子演示了如何以指针的方式遍历数组元素:

#include <stdio.h>

int main(){
    int arr[] = { 99, 15, 100, 888, 252 };//[]内的数字由后面的内容自动生成 
    int len = sizeof(arr) / sizeof(int);  //求数组长度
    //sizeof(arr) 会获得整个数组所占用的字节数,sizeof(int) 会获得一个数组元素所占用的字节数,
    //它们相除的结果就是数组包含的元素个数,也即数组长度。
    int i;
    for(i=0; i<len; i++){
        printf("%d  ", *(arr+i) );  
        //arr为数组首元素地址;arr+i 指向数组的第 i 个元素;
        //*(arr+i) 表示取第 i 个元素的数据,它等价于 arr[i]。
    }
    printf("\n");
    return 0;
}

在这里插入图片描述

我们也可以定义一个指向数组的指针,例如:
int arr[] = { 99, 15, 100, 888, 252 };
int *p = arr;

  • arr (数组名)本身就是一个指针,可以直接赋值给指针变量 p。arr 是数组第 0 个元素的地址,所以int *p = arr;也可以写作int *p = &arr[0];。也就是说,arr、p、&arr[0] 这三种写法都是等价的,它们都指向数组第 0 个元素,或者说指向数组的开头。

如果一个指针指向了数组,我们就称它为数组指针(Array Pointer)。数组指针指向的是数组中的一个具体元素,而不是整个数组

#include <stdio.h>

int main(){
    int arr[] = { 99, 15, 100, 888, 252 };
    int i;
	int* p = arr;
	//定义一个指向数组的指针,我们把这个指针p称为数组指针 
	int len = sizeof(arr) / sizeof(int);
    for(i=0; i<len; i++){
        printf("%d  ", *(p+i) );
    }
    printf("\n");
    return 0;
}

在这里插入图片描述
引入数组指针后,我们就有两种方案来访问数组元素了,一种是使用下标,另外一种是使用指针。

  1. 使用下标
    也就是采用 arr[i] 的形式访问数组元素。如果 p 是指向数组 arr 的指针,那么也可以使用 p[i] 来访问数组元素,它等价于 arr[i]。
  2. 使用指针
    也就是使用 *(p+i) 的形式访问数组元素。另外数组名本身也是指针,也可以使用 *(arr+i) 来访问数组元素,它等价于 *(p+i)。

不管是数组名还是数组指针,都可以使用上面的两种方式来访问数组元素。不同的是,数组名是常量,它的值不能改变,而数组指针是变量(除非特别指明它是常量),它的值可以任意改变。也就是说,数组名只能指向数组的开头,而数组指针可以先指向数组开头,再指向其他元素。

更改上面的代码,借助自增运算符来遍历数组元素:

#include <stdio.h>

int main(){
    int arr[] = { 99, 15, 100, 888, 252 };
    int i, *p = arr, len = sizeof(arr) / sizeof(int);

    for(i=0; i<len; i++){
        printf("%d  ", *p++ );
    }
    printf("\n");
    return 0;
}

在这里插入图片描述

*p++ 应该理解为 *(p++),每次循环都会改变 p 的值(p++ 使得 p 自身的值增加),以使 p 指向下一个数组元素。该语句不能写为 *arr++,因为 arr 是常量,而 arr++ 会改变它的值,这显然是错误的。

2.字符串指针(指向字符串的指针)

字符数组归根结底还是一个数组,关于指针和数组的规则同样也适用于字符数组。使用指针的方式来输出字符串:

#include <stdio.h>
#include <string.h>

int main(){
    char str[] = "http://c.biancheng.net";
    char *pstr = str;
    int len = strlen(str), i;

    //使用*(pstr+i)
    for(i=0; i<len; i++){
        printf("%c", *(pstr+i));
    }
    printf("\n");
    //使用pstr[i]
    for(i=0; i<len; i++){
        printf("%c", pstr[i]);
    }
    printf("\n");
    //使用*(str+i)
    for(i=0; i<len; i++){
        printf("%c", *(str+i));
    }
    printf("\n");

    return 0;
}

除了字符数组,C语言还支持另外一种表示字符串的方法,就是直接使用一个指针指向字符串,即:字符串指针。例如
char *str = "http://c.biancheng.net";
或者
char *str; str = "http://c.biancheng.net";

  • 字符串中每个字符的类型都是char,所以 str 的类型也必须是char *。

下面的例子演示了如何输出这种字符串:

#include <stdio.h>
#include <string.h>

int main(){
    char *str = "http://c.biancheng.net";
    int len = strlen(str), i;
   
    //直接输出字符串
    printf("%s\n", str);
    //使用*(str+i)
    for(i=0; i<len; i++){
        printf("%c", *(str+i));
    }
    printf("\n");
    //使用str[i]
    for(i=0; i<len; i++){
        printf("%c", str[i]);
    }
    printf("\n");

    return 0;
}

在这里插入图片描述

3.指针变量作为函数参数

在C语言中,函数的参数不仅可以是整数、小数、字符等具体的数据,还可以是指向它们的指针

  • 用指针变量作函数参数可以将函数外部的地址传递到函数内部,使得在函数内部可以操作函数外部的数据,并且这些数据不会随着函数的结束而被销毁。
  • 像数组、字符串、动态分配的内存等都是一系列数据的集合,没有办法通过一个参数全部传入函数内部,只能传递它们的指针,在函数内部通过指针来影响这些数据集合。

  • 有的时候,对于整数、小数、字符等基本类型数据的操作也必须要借助指针,一个典型的例子就是交换两个变量的值。

例如

#include <stdio.h>
#include <string.h>
void swap(int* pa, int* pb);
//传进来的参数是指针变量,指针变量用来存放地址 
//将变量 a、b 的地址分别赋值给 pa、pb
int main()
{
	int a = 1, b = 2;
	swap(&a, &b);
	printf("a=%d, b=%d\n", a, b);
	
	return 0;
}
void swap(int* pa, int* pb)
{
	int temp;
	temp = *pa;
	*pa = *pb;
	*pb = temp;
 } 

在这里插入图片描述

数组是一系列数据的集合,无法通过参数将它们一次性传递到函数内部,如果希望在函数内部操作数组,必须传递数组指针。下面的例子定义了一个函数 max(),用来查找数组中值最大的元素:

#include <stdio.h>
#include <string.h> 
//用数组作函数参数
//在函数内部无法通过这个指针获得数组长度,因为 intArr 仅仅是一个指针,
//而不是真正的数组,所以必须要额外增加一个参数来传递数组长度。
//这就是为什么需要两个函数参数的原因 
//所以必须将数组长度作为函数参数传递到函数内部。
int max(int* arr, int len);
//需要传进来一个指针(数组名=首元素地址) 
//也可以写成int max(int arr[], int len);此时[]里面写了数字也不起效,因为不会真正传进去 
int main()
{
	int nums[3], i;
	int len = sizeof(nums)/sizeof(int);
	//读取用户输入的数据并赋值给数组元素
	for(i=0; i<len; i++)
	{
		scanf("%d", nums+i);//nums为数组名,相当于首元素地址 
		//也可以写成nums[0]+i;nums[0]为首元素地址 
	 } 
	printf("Max value is %d!\n", max(nums, len));
	//数组名传进去的是数组首元素的地址,相当于一个指针
		return 0;
}
int max(int* arr, int len)
{
	int i, maxValue = arr[0];//先假设第0个元素是最大的
	for(i=1; i<len; i++)
	{
		if(maxValue < arr[i])
			maxValue = arr[i];
	 } 
		return maxValue;
}

在这里插入图片描述

4.指针变量作为函数返回值

C语言允许函数的返回值是一个指针(地址),我们将这样的函数称为指针函数。下面的例子定义了一个函数 strlong(),用来返回两个字符串中较长的一个:

#include <stdio.h>
#include <string.h>
char* strlong(char* str1, char* str2);//函数声明 
int main()
{
	char str1[20], str2[30], *str;
	gets(str1); 
	gets(str2);
	//gets从标准输入设备读字符串函数,其可以无限读取,
	//不会判断上限,以回车结束读取,
	str = strlong(str1, str2);
	//因为返回值是地址,所以要用指针变量str去接受
	//数组名str1, str2都是代表数组首元素的地址,所以不用加&
	printf("The longer string is :%s\n", str); 
	
	return 0; 
 } 
char* strlong(char* str1, char* str2)
{
	if(strlen(str1)>=strlen(str2))
	{
		return str1;
	}else
	{
		return str2;
	}
}
 

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值