1.以下程序输出的值为:
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;
}
答案是:10/5;
首先:初始化二维数组;切记:二位数组的首元素地址是第一行元素;初始化的二维数组是两行五列的数组;
&aa+1表示在首元素地址的基础之上跳过一个数组;来到下一个数组首元素的地址;强制类型转换为整型,储存在整型指针ptr1中;需要特别注意:&aa和&aa[0][0];所以 *(ptr1-1)表示下一数组的首元素地址-1,也就是第一个数组最后元素的地址;解引用得到10;
aa是一个二维数组,aa表示二维数组的首元素,也就是二维数组第一行的元素;aa+1表示二维数组第二行的元素;解引用强制类型转换为整型得到数组第二行元素的数组名,来到第二行首元素的地址;ptr2-1来到第一行最后一个元素的地址;解引用得到对应的元素;强制类型转换为整型,储存在整型指针ptr2中。所以*(ptr2-1)等于第一行最后一个元素的大小,也就是5;
注意:*(aa+1)等价于aa[1];
2.以下程序输出的结果是:
int main()
{
char *a[] = { "work", "at", "alibaba" };
char **pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
答案是:at;
首先:初始化指针数组,数组中包含三个字符串work、at、alibaba;然后把一维指针数组a赋给*pa,类型为char*;数组传参,传过去的是首元素的地址;也就是a接收的是三个字符串的首元素,也就是w、a、a;pa++;表示在首元素的基础之上+1;来到第二个字符串,所以%s打印字符串得到的结果是at;
二维数组:取两次首地址;
3.以下程序输出的结果是:
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;
}
答案是:POINT、ER、ST、EW;
仔细斟酌上述三维指针所对应的数组关系:----------%s表示打印字符串;
首先初始化指针数组得到四个字符串;数组传参,传过去的是首元素的地址;也就是char *类型指针接收到的是E/N/P/F;
二维数组 cp[] 中含有四个元素,c+0/c+1/c+2/c+3 , c 表示一维数组,char**收到的是首元素的地址,也就是c+0对应char*----ENTER;以此类推c+1、c+2、c+3,在此一定要注意:首元素的对应关系;
三维数组cpp接收到的是二维数组cp的首元素地址位置;
前置++表示先加再运算;只要加上了就对以后的程序永久适用;
printf("%s\n", **++cpp);----------表示三维指针cpp前置++;char***最早处于c+3的位置,++之后来到c+2的位置;解引用得到c+2对应的一维指针char*,再次解引用得到一维指针char*对应的元素POINT;
printf("%s\n", *--*++cpp + 3);----------表示三维指针cpp前置++;在上一个基础之上进行+1,来到c+1的地址,解引用得到c+1对应的一维指针char*;然后--;来到上一个元素的位置,解引用得到ENTER的首元素E;然后再基础之上+3;在字符串ENTER上从首元素开始+3;到达第四个元素E;%s打印以后的字符,打印的结果是ER;
特别注意:*cpp[-2]等价于*(cpp-2);cpp[-1][-1]等价于*(*(cpp-1)-1);
printf("%s\n", *cpp[-2] + 3);-----------表示cpp-2向后-2,来到c+3的位置上,解引用得到c+3对应的一维数组char*;也就得到了字符串FIRST的首元素F;然后+3,向后移三个字符;来到S的地址;打印S以后的字符,得到ST;
printf("%s\n", cpp[-1][-1] + 1);----------表示三维指针-1;向后移动一个位置;来到c+2的位置上,解引用得到c+2对应的一维数组char*,然后在一维数组的基础之上-1;来到上一个一维数组char*,得到一维数组对应的字符串NEW的首元素N,然后在基础之上+1;来到E字符的地址,%s打印E之后的字符;得到结果EW;
4.以下程序输出的结果是:
int main()
{
unsigned long pulArray[] = { 6, 7, 8, 9, 10 };
unsigned long *pulPtr;
pulPtr = pulArray;
*(pulPtr + 3) = *(pulPtr + 3) + 3;
printf("%d,%d\n", *pulPtr, *(pulPtr + 3));
return 0;
}
答案是:6 , 12;
首先:数组传参,传过去的是首元素的地址;所以在初始化数组的指针以后,把数组赋值给指针,指针得到的是数组的首元素地址,pulPtr+3表示向后移动三个地址,得到9 的地址;解引用以后得到数字9;9+3=12赋值给*(pulPtr+3),所以最后*(pulPtr+3)=12;
*pulPtr是数组直接传参以后的结果,得到的是首元素的地址;解引用得到数字6;
5.写一个函数,可以逆序字符串的内容:
思路:首先初始化数组,记住,用char;用大括号0;scanf进行手动输入;给定函数reverse,把arr数组传过去,因为定义的是字符char,所以可以不用求sz,用strlen也可以求字符串长度;记住是用%s打印字符串;
因为定义的是char字符,所以函数用char*指针来接收;交换字符串的顺序,只需要对第一个和最后一个交换,依次向前向后循环即可;需要注意的是:定义right需要用char* 来定义;参数+len-1;然后进行交换,切记left++;right--;然后在while语句中进行循环;
用指针来接收时,一定注意所有都用定义的变量来表示,即用str来表示:之所以定义char* left=str;是因为数组传参,传过去的是首元素的地址;所以定义左边是首元素;右边的定义相应定义即可;
void reverse(char *str)
{
int len = strlen(str);
char* left = str;
char* right = str + len - 1;
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main()
{
char arr[256] = { 0 };
scanf("%s", arr);
reverse(arr);
printf("%s\n", arr);
return 0;
}
6.计算求和:求Sn=a+aa+aaa+aaaa+aaaaa的和;其中a是一个数字;
原理:两个未知数,我定义a,然后定义n;每个后边的一项都是前一项*10+a以后的结果;所以每每出现一个,我就加给sum; ret = ret * 10 + a 的意思是后一项等于前一项*10+a(每后一项都和前一项是有基本运算规律的);
int main()
{
int a = 0;
int n = 0;
scanf("%d%d", &a, &n);
int sum = 0;
int i = 0;
int ret = 0;
for (i = 0; i < n; i++)
{
ret = ret * 10 + a;
sum = sum + ret;
}
printf("%d\n", sum);
}
7.用C语言打印菱形的形状;
需要注意:两个循环语句一个打印菱形的上半部分,一个打印菱形的下半部分;定义line为菱形上半部分的行数,则下半部分循环line-1;菱形一定是奇数行;
两个 i 循环打印的是行;分别打印上半部分的行和下半部分的行;
上半部分的行循环中加入两个 j 循环,分别打印 空格 和 * 号 ,但要明确,每个循环只是打印其中的一行,最后要加上换行\n;每个 j 循环只是为了打印出该行所需要打印几个 空格 和 * 号,每循环一次打印一次;所以j< ;是为了循环打印出所需的符号;
int main()
{
int line = 0;
scanf("%d", &line);
int i = 0;
for (i = 0; i <line ; i++)
{
int j = 0;
for (j = 0; j <line-1-i ; j++)
{
printf(" ");
}
for (j = 0; j <2*i+1 ; j++)
{
printf("*");
}
printf("\n");
}
for (i = 0; i <line-1 ; i++)
{
int j = 0;
for (j = 0; j <=i; j++)
{
printf(" ");
}
for (j = 0; j <2 *(line-1-i)-1; j++)
{
printf("*");
}
printf("\n");
}
return 0;
}
8.编 程 实 现:喝汽水,1元一瓶汽水,每两个空瓶子可以换回一瓶汽水,20元可以喝多少瓶汽水?
思想:20块钱可以买20瓶水,喝完20瓶水会得到20个空瓶子,所以花多少钱就会得到多少个空瓶子,花多少钱就会喝多少瓶水。只要空瓶子大于等于2,我就可以拿去换水,换来水喝掉又会得到空瓶子。
循环体中首先定义喝掉的总数是花的钱+第一次喝掉的空瓶子/2;
然后定义下一次循环体中的空瓶子数:这时需要特别注意:如果除以2留下来的空瓶子会在以后有用,所以需要计算上(如果是5瓶,除以2余1瓶;这个空瓶会和下一次换水得到的空瓶相加起来一起去换水);
int main()
{
int money = 0;
int empty = 0;
int total = 0;
scanf("%d", &money);
total = money;
empty = money;
while (empty >= 2)
{
total = empty / 2+total;
empty = empty / 2 + empty % 2;
}
printf("total=%d\n", total);
return 0;
}
9.编程实现:调整数组中数字的顺序使得数组中所有的奇数位于数组的前半部分,所有偶数位于数组的后半部分;
思想:从定义的数组左边去找偶数,从数组右边去找奇数,一旦找到,交换两个数,最终达到所有奇数都被交换都左边;但要注意,从左往右找偶数可能会出现找到数组的最后一直找不到偶数,从而出现栈溢出的现象;所以在从左往右找偶数和从右往左找奇数的过程中一定需要限制 left小于right。
主函数定义数组,求出数组元素个数,打印数组,定义交换函数,将arr和sz(数组元素个数)传过去;
交换函数:从左往右找偶数-----while循环,对二取余等于1表示是奇数,只要是奇数,left++跳过,循环结束后,默认我已经找到了偶数;从右往左找奇数是一样的;
两个循环结束后默认找到了相应的奇数偶数,但为了防止出现栈溢出的现象,left<right;然后进行交换,注意整个交换过程肯定不止一次,所以整个程序需要在循环体中进行;
void swap(int arr[], int sz)
{
int left = 0;
int right = sz - 1;
while (left < right)
{
while ((left < right) && (arr[left] % 2 == 1))
{
left++;
}
while ((left < right) && (arr[right] % 2 == 0))
{
right--;
}
if (left < right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
}
}
}
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int sz = sizeof(arr) / sizeof(arr[0]);
swap(arr, sz);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
10.输出以下程序的结果:
答案是: 1,6 ;
思想:该数组表示二维数组,&aa+1表示跳过整个数组的大小,来到下一个数组首元素的地址;强制类型转化为整型,存储在指针 ptr1 中,所以ptr1-1表示来到第一个数组最后一个元素的地址上,解引用得到最后一个元素的大小--------1;
aa+1表示在首元素的地址基础之上+1;二位数组首元素表示第一行元素的数组名,所以aa+1表示第二行元素,解引用得到第二行元素的数组名;强制类型转换为整型,传给指针ptr2,ptr2-1表示来到第一行最后一个元素的地址,解引用得到第一行最后一个元素-----6;
int main()
{
int aa[2][5] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
int *ptr1 = (int*)(&aa + 1);
int *ptr2 = (int*)(*(aa + 1));
printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}
11.实现一个函数,可以左旋字符串中的K个字符;(意思就是例如ABCD左旋一个字符,就是把A放到最后-----BCDA;左旋两个同理)
思路:首先初始化字符串,定义左旋函数,进行传参。
函数中因为定义的是 char 型数组,所以用 char* 指针去接收;定义字符串长度strlen,第一个for循环的意思是左旋的次数;然后循环体中是首先将第一个元素拿出来,数组传参,将首元素的地址取出来,然后进行循环,将第三个元素放到第二个元素的位置上,依次类推,注意循环的次数是字符串长度-1(可以用少的字符串去列一下);然后将拿出来的第一个元素放在最后一个元素的位置上;arr表示数组首元素的位置,arr+len-1解引用表示数组最后一个元素的位置;
void left_move(char *arr, int k)
{
int i = 0;
int len = strlen(arr);
for (i = 0; i < k; i++)
{
char tmp = *arr;
int j = 0;
for (j = 0; j < len - 1; j++)
{
*(arr + j) = *(arr + j + 1);
}
*(arr + len - 1) = tmp;
}
}
int main()
{
char arr[] = "abcdef";
left_move(arr,3);
printf("%s", arr);
return 0;
}
优化算法:三步翻转法:
思想:先把前k个逆序;然后把后面的几个逆序,最后整体进行逆序;abcdef前两个逆序是:bacdef;后面四个逆序是:bafedc;整体进行逆序是:cdefab-------得到预期的结果;
注意:left++和right-- ;是为了保证逆序完一对以后,进行下一对;切记,切记!
void reverse(char* left, char* right)
{
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
void left_(char* arr, int k)
{
int len = strlen(arr);
reverse(arr, arr + k - 1);
reverse(arr + k, arr + len - 1);
reverse(arr, arr + len - 1);
}
int main()
{
char arr[] = "abcdef";
left_(arr, 4);
printf("%s", arr);
return 0;
}
12.写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串:
思想:定义两个字符串进行传参;开启for循环进行判断,每次左旋1个字符,strcmp函数进行比较,一旦有左旋之后的结果相同的,strcmp输出0;return值返回1;输出YES;反之亦然;
void reverse(char *left, char* right)
{
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
void left_move(char *s1, int k)
{
int len = strlen(s1);
reverse(s1, s1 + k - 1);
reverse(s1 + k, s1 + len - 1);
reverse(s1, s1 + len - 1);
}
int is_left_move(char* s1, char* s2)
{
int len = strlen(s1);
int i = 0;
for (i = 0; i < len; i++)
{
left_move(s1, 1);
int ret=strcmp(s1, s2);
if (ret == 0)
return 1;
}
return 0;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "cdefar";
int ret = is_left_move(arr1, arr2);
if (ret == 1)
printf("Yes\n");
else
printf("No\n");
return 0;
}
优化算法思想:abcdefgabcdefg(2个数组)中包含了该数组左旋以后的所有可能性;
主要思想:首先初始化两个数组;但需要注意一定要给定arr1足够的存储空间,否则会导致追加字符串时无空间;定义函数is_left_move进行传参;
数组传参,用char* 指针进行接收,计算str1的字符串长度;
strcat:字符串追加函数;strcat只能进行不同字符串的追加,也就是可以把B字符串追加到A的字符串上面,但不能实现自身追加到自身的情况,也就是不能把A字符串追加到A上面;
strncat:字符串追加函数;相比于strcat函数,strncat可以把自身追加到自身上面,语法结构是strncat(A,A,len)---------把字符串A追加到A字符串后,第三个元素是追加字符串的长度;
strstr:找子串的函数;语法架构是strstr(A,B)-------判断B是否是A的子串,如果是,返回值是B的首元素地址(A----abcdef B-----bcd),则返回值是‘b’;如果不是,返回值是NULL----空指针;(NULL的头文件是 #include<stdio.h> )
注意:判断两个字符串的长度,如果两个字符串的长度明显不相等,那么一定不是左旋得来的,直接返回0;
int is_left_move(char *str1, char* str2)
{
int len1 = strlen(str1);
int len2 = stelen(str2);
if (str1 != str2)
return 0;
strncat(str1, str1, len1);
char *ret = strstr(str1, str2);
if (ret == NULL)
{
return 0;
}
else
return 1;
}
int main()
{
char arr1[30] = "abcdef";
char arr2[] = "cdefac";
int ret = is_left_move(arr1, arr2);
if (ret == 1)
printf("Yes\n");
else
printf("No\n");
return 0;
}