C语言学习入门第六节————指针初阶(下)

系列文章目录

C语言学习入门第六节————指针初阶(下)

指针初阶

  1. 指针是什么
  2. 指针和指针类型
  3. 野指针
  4. 指针运算
  5. 指针和数组
  6. 二级指针
  7. 指针数组



一、指针和数组

指针: 指针变量就是指针变量,不是数组,指针变量的大小是 4/8 个字节,是专门用来存放地址的。
数组: 数组就是数组,不是指针,数组是一块连续的空间,可以存放1个或者多个类型相同的数据。 ( 数组的类型多种多样,int arr[10] 和 int arr[8] 的数组类型就是不一样的,前者的数组类型是 int [10] ,
后者的数组类型是 int [8] )

指针和数组的联系:

  1. 数组中,数组名其实是数组首元素的地址,数组名 == 地址 == 指针
  2. 当我们知道数组首元素的地址的时候,因为数组又是连续存放的,所以通过指针就可以遍历访问数组,数组是可以通过指针来访问的。

两种数组名不是首元素地址的情况:

  1. sizeof(数组名):数组名单独放在sizeof()内部,这里的数组名表示整个数组,计算的是整个数组的大小
  2. &数组名:这里的数组名也表示整个数组,取出的是整个数组的地址
#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
 
	int* p = arr; //使用指针变量存放数组首元素地址
 
	for ( i = 0; i < sz; i++)
	{
		//打印数组地址
		printf("%p == %p\n", p+i, &arr[i]);
		// 使用指针变量 访问数组地址 == 使用数组下标 访问数组地址
	}
 
	printf("\n");
 
	for ( i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
		//使用指针访问 数组元素(指针和数组的联系)
	}
 
	return 0;
}

在这里插入图片描述

二、二级指针

概念:
二级指针变量就是用来存放一级指针变量的指针变量(例如下图中的pp)

(解引用:二级指针解引用找到一级指针,再对一级指针解引用找到变量内容)

  1. 调用指针数组访问里面元素,即指针,找到指针对应的整型数组,其用法类似二维数组的使用方式,即 指针数组名[下标][下标] ,如上图的:parr [i] [j]

  2. 指针数组调用整型数组时,用法和二维数组的使用方式类似。但两者有区别,前者的数组元素在内存中是不连续存放的,而后者的数组元素在内存中是连续存放的。原因是:指针数组存放的元素,即指针,来自于不同的整型数组的地址。

#include <stdio.h>
int main()
{
	int a = 10;
 
	int* p = &a; 
	//p是一级指针变量,指针变量也是变量,变量是在内存中开辟空间的,是变量就有地址
 
	int** pp = &p;
	//pp就是二级指针变量,二级指针变量就是用来存放一级指针变量的指针变量
 
	*(*pp) = 100; 
	//(*pp):解引用找到p,对p再解引用找到 a
	//二级指针解引用找到一级指针,一级指针解引用找到变量内容
	printf("%d\n", a);
 
 
	return 0;
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.二级指针的应用:

#include <stdio.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "hello world";
	char arr3[] = "cuihua";
	//使用 一级指针 存放这三个字符数组的首元素
	char* parr[] = { arr1,arr2,arr3 }; //分别存放三个字符数组的首元素地址 
	//使用 二级指针 存放该一级指针
	char** p = parr; //放的是一级指针的首元素地址
	return 0;
}

三、指针数组

概念:
指针数组 就是 存放指针 的 数组(本质就是一个数组,只不过存放的是指针)

1.指针数组存放字符串数组并打印

#include <stdio.h>
int main()
{
	char arr1[] = "moriyadi";
	char arr2[] = "hello world";
	char arr3[] = "one ";

	//使用 指针数组 存放这三个字符数组的首元素
	char* parr[] = { arr1,arr2,arr3 }; //分别存放三个字符数组的首元素地址

	//使用 指针数组 循环打印三个首地址,再通过首地址打印三个字符串
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		printf("%s\n", parr[i]);
		// %s:通过字符串首元素地址就可以打印字符串,通过元素地址找到字符串
	}

	return 0;
}

在这里插入图片描述

2.指针数组存放整型数组并打印


#include <stdio.h>
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 6,7,8,9,10 };
	int arr3[] = { 11,12,13,14,15 };
 
	//使用 指针数组 存放这三个整型数组的首元素
	int* parr[] = { arr1, arr2, arr3 }; //分别存放三个整型数组的首元素地址
 
	//使用 指针数组 循环打印三个首地址,再通过首地址打印三个整型数组
	int i = 0;
	for (i = 0; i < 3; i++) //指针数组大小为3
	{
		//第一个循环:找到指针数组的元素
 
		int j = 0;
		for (j = 0; j < 5; j++) //整型数组大小为5
		{
			//第二个循环:找到对应数组元素地址后,再通过该地址打印整型数组内容
 
			printf("%d ", parr[i][j]);
			//也可以写成 *(parr[i] + j)
 
			//第一个【】:找到指针数组里的指针,定位到对应整型数组
			//第二个【】:定位到对应整型数组后,再用指针访问整型数组元素
		}
 
		printf("\n"); //打印完一个数组后换行
	}
 
	return 0;
}

在这里插入图片描述

四、练习

1.写一个函数返回参数二进制中 1 的个数

第一种方法:%2 和 /2 取出每一位并判断


//比如: 13    0000 1101    3 个 1
#include <stdio.h>
 
int number_of_1(unsigned int m)//要设置成无符号的,不然无法判断 负数
{
	int count = 0; //计数器
	while (m) //如果 m 不为0,说明二进制还有1
	{
		if (m % 2 == 1)//判断最低位
		{
			count++; //为1则计数器++
		}
		m /= 2; //相当于二进制去了一位
	}
	//一直判断直到m等于0,返回统计的1的个数
	return count;
}
 
int main()
{
	int n = 0;
	//输入:
	scanf("%d", &n);
 
	//定义一个计算二进制中1个数的函数
	int ret = number_of_1(n);
	
	printf("%d\n", ret);
 
	return 0;
}

在这里插入图片描述

第二种方法:使用 移位操作符 和 位操作符 * * *

#include <stdio.h>
 
int number_of_1(int m)//要设置成无符号的,不然无法判断 负数
{
	int count = 0; //计数器
	
	int i = 0;
	for (i = 0; i < 32; i++) //二进制有32位,判断32次
	{
		if ( ( (m >> i) & 1) == 1)
		//移动 i位 后再 按位与1 ,判断最低位二进制值是否为 1
		//移动后 m 的值并没有变,所以可以一直移动
		{
			count++; //是 1 则计数++
		}
	}
 
	return count;
}
 
int main()
{
	int n = 0;
	//输入:
	scanf("%d", &n);
 
	//定义一个计算二进制中1个数的函数
	int ret = number_of_1(n);
	
	printf("%d\n", ret);
 
	return 0;
}

在这里插入图片描述

第三种方法: * * *

n = n & (n - 1) – 这个表达式会让n的二进制中最右边的1消失,所以在n变成0之前,能执行几次,
就说明n二进制上有几个1

#include <stdio.h>
 
int number_of_1(int m)//要设置成无符号的,不然无法判断 负数
{
	int count = 0; //计数器
	
	while (m)//如果 m 不为0,说明二进制还有1
	{
		m = m & (m - 1);//去掉最右边的1
		count++; //计数器++
	}
 
	return count;
}
 
int main()
{
	int n = 0;
	//输入:
	scanf("%d", &n);
 
	//定义一个计算二进制中1个数的函数
	int ret = number_of_1(n);
 
	printf("%d\n", ret);
 
	return 0;
}

在这里插入图片描述

2.打印整数二进制的奇数位和偶数位

 #include <stdio.h>
int main()
{
	int n = 0;
	scanf("%d", &n);
	int i = 0;
	
	//打印奇数位
	printf("奇数位:");
	for (i = 30; i >= 0; i -= 2)
	//循环时是 偶数位:30 28 26.。。。
	{
		printf("%d ", (n >> i) & 1);
		//这里移位后是奇数位,按位与1 取出最低位 打印
	}
 
	printf("\n");
	
	printf("偶数位:");
	//打印偶数位
	for (i = 31; i >= 1; i -= 2)
		//循环时是 偶数位:31 29 27.。。。
	{
		printf("%d ", (n >> i) & 1);
		//这里移位后是偶数位,按位与1 取出最低位 打印
	}
 
	return 0;
}

在这里插入图片描述

3.求两个数二进制中不同位的个数


//输入例子 :
//2564 1145
//输出例子 : 9
#include <stdio.h>
 
int number_of_1(int m)
{
	int count = 0; //计数器
 
	while (m)//如果 m 不为0,说明二进制还有1
	{
		m = m & (m - 1);//去掉最右边的1
		count++; //计数器++
	}
}
 
int main()
{
	int m = 0;
	int n = 0;
	
	//输入
	scanf("%d %d", &m, &n);
 
	//异或:相同为0,相异为1
	//把 m 异或 n 后,有几个相异就有几个1,再计算下二进制中有几个1即可
	int ret = number_of_1(m ^ n);
	printf("%d", ret);
 
	return 0;
}

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值