完善指针(1)

理解指针

    1、指针的本质:地址
    2、指针的类型:type+*
    3、指针的解引用:解引用后所占空间大小由指针的type决定
    4、二级指针:对指针解引用就是其所指向的变量
    5、指针表达式:左值(代表变量的存储空间)和右值(内容)
    6、指针运算:
        指针+-整数(实质是加上其所指向变量类型的大小*整数);
        指针-指针(两个指针之间的元素个数(元素的类型由指针的type决定));
        指针的比较(后两个运算的前提是两个指针必须指向同一块内存)
    7、应用:
        利用指针将数组的元素翻转存储;
        利用指针数组排序(冒泡);
    8、两个练习:
         一个数组中只有两个数字是出现一次,其他所有数字都出现了两次, 找出这两个数字;
         喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水,给20元,可以有多少瓶汽水。
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<Windows.h>

/*
指针的存在意义:
	指针让地址有地方存放,指针让内存的访问更加方便
指针是存放地址才出现的,地址是为了标示一块地址空间的
*/

//指针(类型)就是地址(指向:由地址找到)
//地址就是指针(可以通过地址找到变量)
//指针变量是变量
//变量指针是变量的地址(指针就是地址,地址就是指针)
void point1()
{
	int a = 10;
	int *p = &a;//存放在指针变量中的内容都被当做地址(指针)处理
	//同放在int变量中的内容都被当做int型处理
}

//指针的类型:type + *
//指针+-整数:实质是+-(所指类型(type)的大小*整数)
void point2()
{
	int n = 10;
	int *p = &n;
	char *cp = (char *)&n;
	printf("%p\n", &n);//n的整个地址
	printf("%p\n", p);//n的整个地址
	printf("%p\n", p + 1);//下一个n的整个地址
	printf("%p\n", cp);//n的最低一个字节(小端)地址
	printf("%p\n", cp + 1);//n的第二个字节地址
}

//指针解引用
//解引用后所占空间大小与其类型(type)大小相同
void point3()
{
	int n = 0x11223344;
	int *p = &n;
	char *cp = (char *)&n;
	*cp = 0x66;//n = 0x11223366
	*p = 0;//n = 0
}

//二级指针
void point4()
{
	int a = 10;
	int *p = &a;
	int **pp = &p;
	printf("%d\n", pp);
	printf("%d\n", pp + 1);//下一个(int*)指针的地址(+4)
	//int **pp:一个指向int *(type)类型的一级指针
	//所以,多级指针在32位平台下+1都是+4
	
	//对指针解引用就是其所指向的变量
	//对pp解引用就是p(*pp:p)
	//*pp = 20;//表示p = 20;(左值:代表存储空间)
	//int n = *pp;//表示n = p = 20;(右值:代表变量内容)
	printf("%d\n", *pp);
	printf("%d\n", *pp + 1);//表示p+1;即加上p所指向的a的类型大小(+4)
	printf("%d\n", (char*)*pp + 1);//表示p+1;此时p的类型为char:所以+1

	//对pp解引用是p;再对p解引用就是a(*(*pp):a)
	**pp = 30;//表示a = 30;
	int m = **pp;//表示m = a = 30;
	printf("%d\n", **pp);
	printf("%d\n", **pp + 1);//表示a+1;(int)就是+1
}

//指针表达式
void point5()
{
	//左值:代表存储空间,右值:代表变量内容
	char ch = 'a';
	char *cp = &ch;
	//&ch;//ch的地址;不能做左值;可以做右值(地址也是数据)
	//cp;//存放ch地址的指针变量;可做左值(变量就有开辟的空间);可做右值(cp中存放的是ch的地址)
	//&cp;//指针变量cp的地址;不可做左值;可做右值;
	//*cp + 1;//ch + 1 = 'a' + 1;是常量;不可做左值;可做右值;
	//*(cp + 1);//cp+1代表cp指向下一个ch空间,解引用后就代表下一个ch;可做左值;可做右值
	//++cp;//cp的内容自增;变量的++不能做左值;可做右值;
	//cp++;//cp的内容自增;变量的++不能做左值;可做右值;
	//*++cp;//先++,后*:代表下一个ch的空间;可做左值;可做右值;
	//*cp++;//先++,后*:同上;
	//++*cp;//代表++ch;变量的++不能做左值(对变量的自增是对变量内容的自增);可做右值
	//(*cp)++;//ch++;同上;
	//++*++cp;//++(ch+1):是对下一个ch的内容进行前置++;不能做左值;可做右值
	//++*cp++;//对ch内容的前置++,同时也进行后置++;不能做左值;可做右值
}

/*指针运算
指针-指针:代表两个指针之间的元素个数(元素的类型由指针的type决定)
指针与指针比较
:此上两种指针运算前提是两个指针必须指向同一块内存
*/
int point6(const char *s)
{
	//求字符串长度:指针-指针
	char *p = s;
	while (*p){
		p++;
	}
	return p - s;//p:字符串尾部;s:字符串头部
}
void point7()
{
	//清空数组:指针比较
	int str[5];
	int *p = str;
	while (p < &str[5]){
		*p++ = 0;
	}
	//标准规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较
	//但不允许与指向第一个元素前面的那个内存位置的指针进行比较
	//所以在使用时,建议从前向后访问
}

//利用指针将数组翻转存储
void pracPointer1(int arr[], int size)
{
	int *start = arr;
	int *end = arr + size - 1;
	while (start < end){
		*start ^= *end;
		*end ^= *start;
		*start ^= *end;
		start++;
		end--;
	}
}

//利用数组和指针两种方式进行排序
void pracPointer2(int arr[], int size)
{
	数组形式:冒泡
	//for (int i = 0; i < size - 1; i++){//外层循环控制轮数
	//	int flag = 0;//优化
	//	for (int j = 0; j < size - 1 - i; j++){//内层循环控制每轮比较次数
	//		if (arr[j] > arr[j + 1]){
	//			flag = 1;
	//			arr[j] ^= arr[j + 1];
	//			arr[j + 1] ^= arr[j];
	//			arr[j] ^= arr[j + 1];
	//		}
	//	}
	//	if (!flag){
	//		break;
	//	}
	//}
	//指针形式:冒泡
	int *start = NULL;
	int *end = arr + size - 1;
	while (end > &arr[0]){//外层
		int flag = 0;//优化
		start = arr;
		for (; start < end; start++){//内层
			if (*start > *(start + 1)){
				flag = 1;
				*start ^= *(start + 1);
				*(start + 1) ^= *start;
				*start ^= *(start + 1);
			}
		}
		if (!flag){
			break;
		}
		end--;
	}
}

//一个数组中只有两个数字是出现一次,其他所有数字都出现了两次, 找出这两个数字
void practice1(int arr[], int size, int *num1, int *num2)
{
	int i = 0;
	int ret = 0;
	int temp = 0;
	int pos = 0;
	while (i < size){
		ret ^= arr[i];
		i++;
	}//最终的ret的值为两个只出现一次的异或值
	temp = ret;
	while (ret){
		if (ret % 2){//1
			break;
		}
		pos++;
		ret >>= 1;//右移一位
	}//最终的pos位为1:找出的pos位是num1和num2不同的位
	//用num1来存放该位为1的数据,num2来存放该位为0的数据
	for (i = 0; i < size; i++){
		if ((arr[i] >> pos) & 1){
			*num1 ^= arr[i];
		}//取出数组中该位为1的数据(根据此位将数组分为两组:即该位为1(包含num1)和该位为0(包含num2)两组)
		//现在该问题就转化为求一个数组中仅有一个数据出现一次,其他数据都出现两次的情况。
	}
	*num2 = temp^*num1;//temp = *num1^*num2
}

//喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水,给20元,可以有多少汽水
int practice2(int money)
{
	int n = money;
	int count = n;
	while (n > 1){//当拥有的瓶数大于等于2,才可以继续换
		count += n / 2;
		n = n / 2 + n % 2;
	}
	return count;
}

int main()
{
	//point2();
	//point3();
	//point4();
	/*char *str = "asassad";
	point6(str);*/

	//int arr[10] = { 2, 3, 5, 1, 3, 2, 6, 7, 4, 8 };
	//int size = sizeof(arr) / sizeof(arr[0]);
	pracPointer1(arr, size);
	//pracPointer2(arr, size);

	int num1 = 0;
	int num2 = 0;
	int arr[12] = { 2, 6, 8, 15, 3, 5, 6, 8, 4, 2, 3, 5 };
	int size = sizeof(arr) / sizeof(arr[0]);
	practice1(arr, size, &num1, &num2);
	printf("%d %d\n", num1, num2);

	/*int money = 3;
	printf("%d\n", practice2(money));*/

	system("pause");
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值