C语言每日一练(1)

日刷百题,题刷百日!
归纳编程学习的感悟,
记录奋斗路上的点滴,
希望能帮到一样刻苦的你!
如有不足欢迎指正!
共同学习交流!
欢迎各位→点赞 + 收藏⭐️ + 留言​
冰冻三尺非一日之寒,水滴石穿非一日之功。

一起加油! 

序言:

c语言每日一练系列,每一期都包含5~8个小题,1~2道编程题,我会尽可能详细地进行讲解,令初学者也能听的清晰。每日一练系列会持续更新,尽情期待!

一、程序分析题

1、下面程序的运行结果是什么?

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

解析:a表示首元素地址,a+1表示第二个元素地址,*(a+1)表示第二个元素2;

&a是整个数组地址,&a+1表示跳过整个数组,指向数组后面的地址,(int *)(&a + 1)表示将(&a + 1)强制转换为整型指针,ptr为整型指针,里面放着5后面的地址,ptr是整型指针,所以ptr-1表示向后跳过四个字节,*(ptr - 1)表示解引用四个字节,即数字5

答案:2,5

2、 在X86环境下 ,假设结构体的⼤⼩是20个字节 ,程序输出的结构是啥? 

 
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
 short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}

解析:p是一个结构型指针,p+0x1相当于p+1,表示跳过一个结构体,指向结构体后面的地址----->--------->20转化为16进制为0x14,所以答案为0x100014;

 (unsigned long)p将p强制类型转化为无符号长整型,所以(unsigned long)p + 0x1表示0x100000+1==0x100001;

(unsigned int*)p将p强制类型转化为无符号整型指针,(unsigned int*)p + 0x1表示跳过一个无符号整型大小的地址———>0x100000+4==0x100004

答案:

3、下面程序的运行结果是什么?
#include 
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;
}

解析:ptr1整型指针中存储整个数组a后面的地址,ptr1[-1]------>*(ptr1-1)表示元素4;

(int)a + 1将首元素的地址强制转化为整型然后加1, (int *)((int)a + 1)再强制类型转换为整型指针,ptr2为数组第二个字节的地址,*ptr2表示向后读取四个字节数字。

答案:

C语言每日一练(1)_第1张图片

4、下面程序的运行结果是什么?

#include 
int main()
{
 int a[3][2] = { (0, 1), (2, 3), (4, 5) };
 int *p;
 p = a[0];
 printf( "%d", p[0]);
 return 0;
}

解析:二维数组里面元素实际为逗号表达式,相当于int a[3][2]={1,3,5},a[0]为第一行数组名,表示首元素地址,p里面为1的地址,p[0]==*(p+0)。

答案:1

5、假设环境是x86环境,程序输出的结果是啥?

#include 
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;
}

解析:a是二维数组数组名,表示第一行数组地址,而p是存放四个元素的一维数组指针,&p[4]表示p+4,p每次加一跳过一个int [4],p+4如图所示;&p[4][2]表示&p[4]向后在找2个元素的地址,如图所示;

 &p[4][2] - &a[4][2]表示指针-指针为俩地址之间元素个数,用整型打印出来为-4;

用地址打印出来,则是-4在内存中的存储,-4在内存以补码形式存储,转化十六进制为ff ff ff fc。

 

C语言每日一练(1)_第2张图片

C语言每日一练(1)_第3张图片

答案:

6、下面程序的运行结果是什么?

#include 
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));
 printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
 return 0;
}

解析:&aa+1表示跳过整个二维数组的地址;ptr1-1表示向前跳过一个整型的地址, *(ptr1 - 1)即元素10;

*(aa + 1)==aa[1],第二行数组名相当于第二行第一个元素地址,即6的地址;*(ptr2 - 1)表示向前跳过一个整型的地址然后解引用,即5.

答案:

7、下面程序的运行结果是什么?

#include 
int main()
{
 char *a[] = {"work","at","alibaba"};
 char**pa = a;
 pa++;
 printf("%s\n", *pa);
 return 0;
}

解析:常量字符串作为表达式时,它的值是字符首元素的地址,a为指针数组数组名,表示'w'的地址的地址,pa++表示跳过一个char*的地址,即'a'的地址的地址,*pa表示'a'的地址,打印结果at。

答案:at

8、下面程序的运行结果是什么?

#include 
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);
 printf("%s\n", cpp[-1][-1]+1);
 return 0;
}

解析:c数组里面的元素依次是'E','N','P','F'的地址(char*),cp数组里面的元素依次是'F','P','N','E'的地址的地址(char**),cpp里面的元素是首元素的地址(charr***);

++cpp是cp中第二个元素地址,*++cpp是第二个元素,**++cpp是'P'的地址,打印出来即POINT;

++cpp是cp中第三个元素地址,*++cpp表示cp第三元素(c+1),--*++cpp表示c中第一个元素地址(c),*--*++cpp表示'E'的地址,*--*++cpp+3表示跳过三个字符的地址,打印出来即ER;

cpp[-2]==*(cpp-2)表示cpp往前跳过俩个char**后的地址再解引用,即cp首元素(c+3),

*cpp[-2]表示c中第四个元素即'F'的地址,*cpp[-2]+3表示跳过三个字符的地址,打印出来即ST;

 cpp[-1][-1]==*(*(cpp-1)-1),*(cpp-1)表示cp中的第二个元素(c+2),*(*(cpp-1)-1)表示c中第二个元素,即'N'的地址,cpp[-1][-1]+1表示跳过1个字符的地址,打印出来即EW.

C语言每日一练(1)_第4张图片

C语言每日一练(1)_第5张图片

C语言每日一练(1)_第6张图片

二、编程题

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

例如:

ABCD左旋一个字符得到BCDA

ABCD左旋两个字符得到CDAB

分析:

思路一:若字符串长度为5的情况下,旋转6、11、16...次相当于1次,7、12、17...次相当于2次,以此类推。所以要对旋转次数处理,真实次数为旋转次数%字符串长度;一次左旋为从第二个字符开始一次向前挪移一位,在将第一个字符放在最后,左旋几次就循环几次

//思路一:
void leftRound(char* str, int k)
{
	int i, j, tmp;
	int len = strlen(str);
	k =k% len; //长度为5的情况下,旋转6、11、16...次相当于1次,7、12、17...次相当于2次,以此类推。
	for (i = 0; i < k; i++) //执行k次的单次左旋
	{
		tmp = str[0];
		for (j = 0; j < len - 1; j++) //单次左旋
		{
			str[j] = str[j + 1];
		}
		str[j] = tmp;
	}
}
int main()
{
	char arr[] = { "ABCDE" };
    int k = 0;
    scanf("%d", &k);
	leftRound(arr, k);
	printf("%s", arr);
	return 0;
	
}

思路二:创造一个新字符数组,将原数组分为俩部分,旋转部分和剩余部分,将剩余部分copy到新数组,将旋转部分拼接到原数组,最后copy回来。

//思路二
void leftRound(char* str, int k)
{
	int len = strlen(str);
	int pos = k % len; //断开位置的下标
	char tmp[100] = { 0 }; 

	strcpy(tmp, str + pos); //先将后面的全部拷过来
	strncat(tmp, str, pos); //然后将前面几个接上
	strcpy(str, tmp); //最后拷回去
}
int main()
{
	char arr[] = { "ABCDE" };
    int k = 0;
    scanf("%d", &k);
	leftRound(arr, k);
	printf("%s", arr);
	return 0;
	
}

思路三:

ABCDEFG,左旋3次后变成DEFGABC,有一个特殊的操作方式:先将要左旋的前三个字符串逆序(CBADEFG),然后将后半段也逆序(CBAGFED),最后整体逆序(DEFGABC)即可。这样只需要做数值交换即可,可以写一个函数帮我们完成局部逆序,代码如下:

//思路三
void leftRound(char* str, int k)
{
	int len = strlen(str);
	k = k % len; 
	int left = 0;
	int right = k - 1;
	while (left < right)
	{
		char tmp = str[left];
		str[left] = str[right];
		str[right] = tmp;
		left++;
		right--;
	}
	left = k;
	right = len - 1;
	while (left < right)
	{
		char tmp = str[left];
		str[left] = str[right];
		str[right] = tmp;
		left++;
		right--;
	}
	left = 0;
	right = len - 1;
	while (left < right)
	{
		char tmp = str[left];
		str[left] = str[right];
		str[right] = tmp;
		left++;
		right--;
	}
}
int main()
{
	char arr[] = { "ABCDE" };
    int k = 0;
    scanf("%d", &k);
	leftRound(arr, k);
	printf("%s", arr);
	return 0;
	
}

2、C语言每日一练(1)_第7张图片两个整数二进制位不同个数_牛客题霸_牛客网输入两个整数,求两个整数二进制格式有多少个位不同。题目来自【牛客题霸】icon-default.png?t=N7T8https://www.nowcoder.com/practice/16e48900851646c0b2c6cdef9d7ea051?tpId=182&tqId=34802&ru=/exam/oj

思路一:一个整型二进制共32位,将俩个整型二进制对应位分别&1

如果:
      结果是0,则最后一个比特位是0
      结果是非0,则最后一个比特位是1

俩结果比较,不同则计数1;然后让俩个二进制同时右移一位

以上内容循环32次

//思路一
#include 

int main() {
    int a, b;
    int count=0;
    while (scanf("%d %d", &a, &b) != EOF) { // 注意 while 处理多个 case
        int i=0;
        for(i=0;i<32;i++)
        {

            if((a&1)!=(b&1))
        {
            count++;
        }
        a=a>>1;
        b=b>>1;
        }
        printf("%d",count);
    }
    return 0;
}

思路二:

1. 先将m和n进行按位异或,此时m和n相同的二进制比特位清零,不同的二进制比特位为1。

2. 统计异或完成后结果的二进制比特位中有多少个1即可

//思路二
#include 
int calc_diff_bit(int m, int n)
{
	int tmp = m^n;
	int count = 0;
	while(tmp)
	{
		tmp = tmp&(tmp-1);//每进行一次则tmp少一个1,若tmp=100101,tmp = tmp&(tmp-1),则tmp=1001
		count++;
	}
	return count;
}


int main()
{
 int m,n;
 while(scanf("%d %d", &m, &n) == 2)
 {
     printf("%d\n", calc_diff_bit(m, n));
 }
 return 0;
}

今天的内容到此结束了,祝大家学有所成,天天开心!

你可能感兴趣的:(每日一练,c语言,算法,开发语言,单片机,c++,数据结构)