C语言习题练习5——指针

Posted Huang_ZhenSheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言习题练习5——指针相关的知识,希望对你有一定的参考价值。

目录

1.一维数组 

2.字符数组

3.二维数组

4.指针系列笔试题 (1-8题)

5.实现一个函数,可以左旋字符串中的k个字符。

字符串右旋:

6.写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串

7.有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在

1.一维数组 

int main()
{
	//sizeof(数组名)-数组名表示整个数组,计算的是整个数组的大小
	//&数组名-数组名表示整个数组,取出的是整个数组的地址
	//除此之外,所有的数组名都是数组首元素的地址
	int a[] = { 1, 2, 3, 4 };
	printf("%d\\n", sizeof(a));//16
	printf("%d\\n", sizeof(a + 0));//(a+0)是第一个元素的地址:4/8
	printf("%d\\n", sizeof(*a));//*a是数组的第一个元素:4,计算的是第一个元素的大小
	printf("%d\\n", sizeof(a + 1));//第二个元素的地址:4/8,sizeof(a+1)计算的是地址的大小
	printf("%d\\n", sizeof(a[1]));//计算的是第二个元素的大小://4

	printf("%d\\n", sizeof(&a));//&a虽然是数组的地址,但是也是地址,sizeof(&a)计算的也是一个地址的大小:4/8
	printf("%d\\n", sizeof(*&a));// int(*p)[4] = &a,解引用:16
	printf("%d\\n", sizeof(&a + 1));//跳过整个数组之后,下个空间的起始地址:4/8
	printf("%d\\n", sizeof(&a[0]));//第一个元素的地址:4/8
	printf("%d\\n", sizeof(&a[0] + 1));//第二个元素的地址:4/8
	return 0;
}

2.字符数组

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
	printf("%d\\n", sizeof(arr));//6
	printf("%d\\n", sizeof(arr + 0));//4/8
	printf("%d\\n", sizeof(*arr));//1
	printf("%d\\n", sizeof(arr[1]));//1
	printf("%d\\n", sizeof(&arr));//4/8
	printf("%d\\n", sizeof(&arr + 1));//4/8
	printf("%d\\n", sizeof(&arr[0] + 1));//b的地址 :4/8

	printf("%d\\n", strlen(arr));//不知道什么时候遇到‘\\0’:随机值
	printf("%d\\n", strlen(arr + 0));//随机值
	printf("%d\\n", strlen(*arr));//出错,传的地址有问题
	printf("%d\\n", strlen(arr[1]));//出错,传的地址有问题
	printf("%d\\n", strlen(&arr));//随机值
	printf("%d\\n", strlen(&arr + 1));//随机值
	printf("%d\\n", strlen(&arr[0] + 1));//随机值

	char arr[] = "abcdef";//[a,b,c,d,e,f,\\0]
	printf("%d\\n", sizeof(arr));//7
	printf("%d\\n", sizeof(arr + 0));//4/8
	printf("%d\\n", sizeof(*arr));//1
	printf("%d\\n", sizeof(arr[1]));//1
	printf("%d\\n", sizeof(&arr));//4/8
	printf("%d\\n", sizeof(&arr + 1));//4/8
	printf("%d\\n", sizeof(&arr[0] + 1));//4/8

	printf("%d\\n", strlen(arr));//6
	printf("%d\\n", strlen(arr + 0));//6
	printf("%d\\n", strlen(*arr));//出错
	printf("%d\\n", strlen(arr[1]));//出错
	printf("%d\\n", strlen(&arr));//6
	printf("%d\\n", strlen(&arr + 1));//随机值
	printf("%d\\n", strlen(&arr[0] + 1));//5

	char *p = "abcdef";
	printf("%d\\n", sizeof(p));//4/8
	printf("%d\\n", sizeof(p + 1));//4/8
	printf("%d\\n", sizeof(*p));//1
	printf("%d\\n", sizeof(p[0]));//1--->p[0] = *(p+0)
	printf("%d\\n", sizeof(&p));//4/8
	printf("%d\\n", sizeof(&p + 1));//4/8
	printf("%d\\n", sizeof(&p[0] + 1));//4/8

	printf("%d\\n", strlen(p));//6
	printf("%d\\n", strlen(p + 1));//5
	printf("%d\\n", strlen(*p));//出错
	printf("%d\\n", strlen(p[0]));//出错
	printf("%d\\n", strlen(&p));//随机值!!!
	printf("%d\\n", strlen(&p + 1));//随机值
	printf("%d\\n", strlen(&p[0] + 1));//5
	return 0;
}

3.二维数组

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int a[3][4] = { 0 };
	printf("%d\\n", sizeof(a));//48
	printf("%d\\n", sizeof(a[0][0]));//4
	printf("%d\\n", sizeof(a[0]));
	//数组名a[0]单独放在sizeof内部:16
	//a[0]表示的整个第一行,sizeof(a[0])计算的就是第一行的大小
	printf("%d\\n", sizeof(a[0]/*第一个元素的地址*/ + 1));//4
	//a[0]作为数组名并没有单独放在sizeof内部,也没有取地址,所以a[0]就是第一行第一个元素的地址
	printf("%d\\n", sizeof(*(a[0] + 1)));//4
	printf("%d\\n", sizeof(a + 1));
	//a是二维数组的数组名,并没有取地址
	//也没有单独放在sizeof内部,所以a就表示二维数组首元素的地址,即第一行的地址:4
	printf("%d\\n", sizeof(*(a + 1)));//*(a+1) = a[1] :16
	printf("%d\\n", sizeof(&a[0] + 1));//4
	printf("%d\\n", sizeof(*(&a[0] + 1)));//16
	printf("%d\\n", sizeof(*a));//16
	printf("%d\\n", sizeof(a[3]));//16
	//a[3]其实是第四行的数据名(如果有的话)
	//所以其实是不存在的,也能通过类型计算大小
	//sizeof()内部的表达式是不算的
	return 0;
}

下面代码的输出结果是2,5,因为sizeof()内部不参与计算! 

int main()
{
	short s = 5;
	int a = 4;
	printf("%d\\n",sizeof(s = a+6));
	printf("%d\\n",s);
	return 0;
}

总结:数组名的意义

1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小

2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址

3.除此之外的所有的数组名都表示首元素的地址

4.指针系列笔试题 (1-8题)

第一题:

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int *ptr = (int *)(&a + 1);
	printf("%d,%d", *(a + 1), *(ptr - 1));
	return 0;
}

第二题:

//考察的是:指针类型决定指针的运算!
//由于还没学习结构体,这里告知结构体的大小是20个字节
struct Test
{
	int Num;
	char *pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
int main()
{
	printf("%p\\n", p + 0x1);
	//结构体类型指针+1,0x100014
	printf("%p\\n", (unsigned long)p + 0x1);
	//P强制转化成整型类型 加1就是加1:0x100001
	printf("%p\\n", (unsigned int*)p + 0x1);
	//p指向无符号整型指针,加1跳过一个整型变量大小即加4:0x100004
	return 0;
}

第三题:

int main()
{
	int a[4] = { 1, 2, 3, 4 };
	int *ptr1 = (int *)(&a + 1);
	int *ptr2 = (int *)((int)a + 1);
	printf("%x,%x", ptr1[-1], *ptr2);
	return 0;
}

 0x20---> 32   int+1 = 33--->0x21---->向后走了一个字节

 第四题:

int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int *p;
	p = a[0];//表示的是首元素的地址
	printf("%d", p[0]);//p[0] = *(p+0)
	return 0;
}

第五题:

int main()
{
	int a[5][5];
	int(*p)[4];
	p = a;
	printf("%p,%d\\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	return 0;
}

第六题:

int main()
{
	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int *ptr1 = (int *)(&aa + 1);
	int *ptr2 = (int *)(*(aa + 1));
	//aa是数组名,数组名相当于首元素的地址(第一行的地址)
	//*(aa + 1)==aa[1],整型地址赋给ptr2
	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
	return 0;
}

 答案:10 和 5

第七题:

int main()
{
	char* a[] = { "work", "at", "alibaba" };
	char** pa = a;
	//a代表首元素的地址,首元素是char*,首元素的地址是char**,放到pa里面去
	pa++;
	printf("%s\\n", *pa);
	return 0;
}

 第八题(BOSS!):

int main()
{
	char* c[] = { "ENTER", "NEW", "POINT", "FIRST" };
	char** cp[] = { c + 3, c + 2, c + 1, c };
	char*** cpp = cp;
	printf("%s\\n", **++cpp);
	printf("%s\\n", *--*++cpp + 3);
	printf("%s\\n", *cpp[-2] + 3);//==> **(cpp-2)+3  同理
	printf("%s\\n", cpp[-1][-1] + 1);//*(*(cpp-1)-1)+1
	return 0;
}

答案:POINT    ER    ST    EW 

5.实现一个函数,可以左旋字符串中的k个字符。

例如:

ABCD左旋一个字符得到BCDA

ABCD左旋两个字符得到CDAB

方法1:

void left_swap(char* str, int n)
{
	int i = 0;
	int len = strlen(str);
	for (i = 0; i < n; i++)
	{
		//每次左旋转一个字符
		char tmp = *str;
		//后边的len-1个字符往前挪动
		int j = 0;
		for (j = 0; j < len; j++)
		{
			*(str + j) = *(str + j + 1);
		}
		//tmp放在最后
		*(str + len - 1) = tmp;
	}
}
int main()
{
	char arr[] = "ABCDEFG";
	int num = 0;
	printf("请输入要旋转的个数:");
	scanf(" %d",&num);
	left_swap(arr, num);
	printf("%s",arr);
	return 0;
}

方法2:(三步逆序)左边逆序,右边逆序,整体逆序

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
//1左边逆序 2右边逆序 3整体逆序
void reverse(char* left, char* right)
{
	
	assert(left);
	assert(right);
	while (left < right)
	{
		char tmp = *left;
		*left = *right;
		*right = tmp;
		left++;
		right--;
	}
}
void left_swap(char* str, int num)
{
	assert(str);
	int n = strlen(str);
	reverse(str, str+num-1);
	reverse(str+num, str+n-1);
	reverse(str, str+n-1);
}
int main()
{
	char arr[] = "ABCDEFG";
	printf("请输入要旋转的个数:");
	int num = 0;
	scanf("%d",&num);
	left_swap(arr, num);
	printf("%s\\n",arr);
	return 0;
}

字符串右旋:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
void right_roate(char* str,int num)
{
	assert(str);
	int n = strlen(str);
	int i = 0;
	for (i = 0; i < num; i++)
	{
		char tmp = *(str + n - 1);
		for (int j = 0; j < n-1; j++)
		{
			*(str + n-1-j) = *(str + n-2-j);
		}
		*str = tmp; 
	}
}
int main()
{
	char arr[] = "AABB";
	printf("请输入要旋转的数:");
	int num = 0;
	scanf("%d", &num);
	right_roate(arr,num);
	printf("%s",arr);
}

6.写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串

例如:给定s1 =AABCD和s2 = BCDAA,返回1

给定s1=abcd和s2=ACBD,返回0.

AABCD左旋一个字符得到ABCDA

AABCD左旋两个字符得到BCDAA

AABCD右旋一个字符得到DAABC

方法1:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int is_left_swap(char* str1, char* str2)
{
	int i = 0;
	int n = strlen(str1);
	for (i = 0; i < n; i++)
	{
		//每次左旋转一个字符
		char tmp = *str1;
		//后边的n-1个字符往前挪动
		int j = 0;
		for (j = 0; j < n-1; j++)
		{
			*(str1 + j) = *(str1 + j + 1);
		}
		//tmp放在最后
		*(str1 + n - 1) = tmp;
		if (strcmp(str1, str2) == 0)
		{
			return 1;
		}
	}
	return 0;
}
int main()
{
	char arr1[] = "AABCD";
	char arr2[] = "BCDAA";
	int ret  = is_left_swap(arr1,arr2);
	if (ret == 1)
	{
		printf("yes\\n");
	}
	else
	{
		printf("no\\n");
	}
	return 0;
}

方法2:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int is_left_swap(char* str1, char* str2)
{
	//长度不相等,肯定不是旋转得到的
	if (strlen(str1) != strlen(str2))
	{
		return 0;
	}
	//1.str1字符串的后边追加一个str1
	//AABCDAABCD
	int len = strlen(str1);
	strncat(str1,str2,len);
	//2.判断str2是否为str1的字串
	char* ret = strstr(str1, str2);
	return ret!= NULL;
}
int main()
{
	char arr1[] = "AABCD";//改为char arr1[20] = "AABCD",不然会出问题
	char arr2[] = "BCDAA";
	int ret  = is_left_swap(arr1,arr2);
	if (ret == 1)
	{
		printf("yes\\n");
	}
	else
	{
		printf("no\\n");
	}
	return 0;
}

7.有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在

要求:时间复杂度小于O(N); 遍历数组方法不满足

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int Find(int arr[3][3], int* r, int* c, int k)
{
	int x = 0;
	int y = *c - 1;
	while (x <= 2 && y >= 0)
	{
		if (arr[x][y] < k)
		{
			x++;
		}
		else if (arr[x][y] > k)
		{
			y--;
		}
		else
		{
			*r = x;
			*c = y;
			return 1;
		}
	}
	return 0;
}
int  main()
{
	int arr[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	int  k = 8;
	int x = 3;
	int y = 3;
//&x,&y作用:1.传入参数 2.带回值
	int ret = Find(arr, &x, &y, k);
	if (ret == 1)
	{
		printf("找到了\\n");
		printf("%d %d",x,y);
	}
	else
	{
		printf("找不到\\n");
	}
	return 0;
}

以上是关于C语言习题练习5——指针的主要内容,如果未能解决你的问题,请参考以下文章

C语言指针练习题

C语言指针练习题

C语言习题练习4

C语言总结_数组与函数传参练习题

C语言总结_数组与函数传参练习题

C语言课程设计——25道蓝桥杯练习题