strlen函数用于计算字符串的长度,以下是一个模拟实现:
int strlen(char *str)
{
int len = 0;
while (*str != '\0')
{
len++;
str++;
}
return len;
}
该函数通过一个while循环来遍历字符串,每遍历一个字符,计数器len就加1。当遍历到字符串的结尾字符'\0'时,循环结束,函数返回计数器的值,即字符串的长度。
strcpy
是C语言标准库中的函数,用于将字符串复制到另一个字符串中。
以下是模拟实现strcpy
的代码:
char* strcpy(char* dest, const char* src) {
char* p_dest = dest;
while (*src != '\0') {
*p_dest++ = *src++;
}
*p_dest = '\0'; // 添加字符串结尾符
return dest;
}
strcpy
的工作原理是遍历源字符串,逐个字符地复制到目标字符串中,遇到字符串结尾符\0
时停止复制并在目标字符串末尾添加一个\0
。在模拟实现中,使用指针p_dest
指向目标字符串,每复制一个字符,就将指针后移一位;使用指针src
指向源字符串,每读取一个字符,就将指针后移一位。最后返回指向目标字符串的指针dest
。
void swap(char* buf1, char* buf2, size_t size)
{
int i = 0;
for (i = 0; i < size; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void* e1, const void*e2))
{
//冒泡排序的趟数
int i = 0;
for (i = 0; i < num - 1; i++)
{
//一趟冒泡排序
int j = 0;
for (j = 0; j < num - 1 - i; j++)
{
if(cmp((char*)base + j * size, (char*)base + (j + 1) * size)<0)
{
//交换
swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
}
}
}
}
例如:ABCD左旋一个字符得到BCDA
ABCD左旋两个字符得到CDAB
设计循环使其可以旋1次,然后让他执行n次是一个最简单的思路:
void leftRound(char * src, int time)
{
int i, j, tmp;
int len = strlen(src);
time %= len; //长度为5的情况下,旋转6、11、16...次相当于1次,7、12、17...次相当于2次,以此类推。
for (i = 0; i < time; i++) //执行k次的单次平移
{
tmp = src[0];
for(j = 0; j < len - 1; j++) //单次平移
{
src[j] = src[j + 1];
}
src[j] = tmp;
}
}
改进一:
这个思路当然可以,但是一次一次转毕竟太麻烦,就不能一次到位么?
当然可以,我们可以选择拼接法,一次到位:
void leftRound(char * src, int time)
{
int len = strlen(src);
int pos = time % len; //断开位置的下标
char tmp[256] = { 0 }; //更准确的话可以选择malloc len + 1个字节的空间来做这个tmp
strcpy(tmp, src + pos); //先将后面的全部拷过来
strncat(tmp, src, pos); //然后将前面几个接上
strcpy(src, tmp); //最后拷回去
}
改进二:
这个方法要用到一个数组形成的辅助空间,让人觉得有点不爽,还可以有更好的选择,例如ABCDEFG,左旋3次后变成DEFGABC,有一个特殊的操作方式:
先将要左旋的前三个家伙逆序(CBADEFG),然后将后半段也逆序(CBAGFED),最后整体逆序(DEFGABC)即可。这样只需要做数值交换即可,可以写一个函数帮我们完成局部逆序,代码如下:
void reverse_part(char *str, int start, int end) //将字符串从start到end这一段逆序
{
int i, j;
char tmp;
for (i = start, j = end; i < j; i++, j--)
{
tmp = str[i];
str[i] = str[j];
str[j] = tmp;
}
}
void leftRound(char * src, int time)
{
int len = strlen(src);
int pos = time % len;
reverse_part(src, 0, pos - 1); //逆序前段
reverse_part(src, pos, len - 1); //逆序后段
reverse_part(src, 0, len - 1); //整体逆序
}
例如:给定s1 =AABCD和s2 = BCDAA,返回1
给定s1=abcd和s2=ACBD,返回0.
AABCD左旋一个字符得到ABCDA
AABCD左旋两个字符得到BCDAA
AABCD右旋一个字符得到DAABC
解析:
本题当然可以将所有旋转后的结果放到一个数组里,然后进行查找,但是这种做法既不好操作,也太费事,但是这题有一个很简单的做法:
其实ABCDE无论怎么旋,旋转后的所有结果,都包含在了ABCDEABCD这个字符串里了。
所以做法很简单,只需要将原字符串再来一遍接在后面,然后找一找待查找的字符串是不是两倍原字符串的子集即可。
int findRound(const char * src, char * find)
{
char tmp[256] = { 0 }; //用一个辅助空间将原字符串做成两倍原字符串
strcpy(tmp, src); //先拷贝一遍
strcat(tmp, src); //再连接一遍
return strstr(tmp, find) != NULL; //看看找不找得到
}
方法二
int is_left_move(char* str1, char* str2)
{
int len1 = strlen(str1);
int len2 = strlen(str2);
if (len1 != len2)
return 0;
strncat(str1, str1, len1);
if (strstr(str1, str2) == NULL)
return 0;
else
return 1;
}
int main()
{
char arr1[20] = "abcdef";//abcdefabcdef
//bcdefa
//cdefab
//defabc
//efabcd
//fabcde
//abcdef
char arr2[] = "cdef";
int ret = is_left_move(arr1, arr2);//判断arr2是否是arr1旋转所得
if (ret == 1)
printf("Yes\n");
else
printf("No\n");
return 0;
}
有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。
要求:时间复杂度小于O(N);
#include <stdio.h>
int findnum(int a[][3], int x, int y, int f) //第一个参数的类型需要调整
{
int i = 0, j = y - 1; //从右上角开始遍历
while (j >= 0 && i < x)
{
if (a[i][j] < f) //比我大就向下
{
i++;
}
else if (a[i][j] > f) //比我小就向左
{
j--;
}
else
{
return 1;
}
}
return 0;
}
int main()
{
int a[][3] = { {1, 3, 5},
{3, 5, 7},
{5, 7, 9} }; //一个示例
if (findnum(a, 3, 3, 2))
{
printf("It has been found!\n");
}
else
{
printf("It hasn't been found!\n");
}
return 0;
}
方法二,可返回所求值的坐标
int Find(int arr[3][3], int *px, int *py, int k)
{
int x = 0;
int y = *py - 1;
while (x <= *px - 1 && y >= 0)
{
if (arr[x][y] < k)
{
x++;
}
else if (arr[x][y] > k)
{
y--;
}
else
{
*px = x;
*py = y;
return 1;
}
}
*px = -1;
*py = -1;
return 0;
}
int main()
{
int arr[3][3] = { 1,2,3, 4,5,6, 7,8,9 };
int k = 0;
int x = 3;
int y = 3;
scanf("%d", &k);//7
int ret = Find(arr, &x, &y, k);//存在返回1,如果不存在返回0
if (ret == 1)
{
printf("Yes\n");
printf("%d %d\n", x, y);
}
else
{
printf("No\n");
printf("%d %d\n", x, y);
}
return 0;
}
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; } A.1, 6 B.10, 5 C.10, 1 D.1, 5
&aa的类型是int (*)[2][5],加一操作会导致跳转一个int [2][5]的长度,直接跑到刚好越界的位置。减一以后回到最后一个位置1处。*(aa + 1)相当于aa[1],也就是第二行的首地址,自然是5的位置。减一以后由于多维数组空间的连续性,会回到上一行末尾的6处。故选A。
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
int* arr[3] = {arr1, arr2, arr3};
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
//printf("%d ", *(arr[i] + j));
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
#include <stdlib.h>
//
int main()
{
int **arr = (int**)malloc(3*sizeof(int*));
int i = 0;
for (i = 0; i < 3; i++)
{
*(arr + i) = (int*)malloc(5*sizeof(int));
}
//初始化
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
arr[i][j] = 1;
}
}
//打印
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
//释放
for (i = 0; i < 3; i++)
{
free(arr[i]);
}
free(arr);
arr = NULL;
return 0;
}
/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个字节
//X86 环境下演示
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
} * p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
//0x开头的数字是16进制的数字
int main()
{
p = (struct Test*)0x100000;
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
#include <stdio.h>
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] = { (0, 1), (2, 3), (4, 5) };//实际初始化为1 3 5,为逗号表达式取两者中的最大值
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 - int(*)[5] //p - int(*)[4]
//%p是打印地址,认为内存中存储的补码就是地址
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;
}
#include <stdio.h>
//阿里的笔试题
int main()
{
char* a[] = { "work","at","alibaba" };
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
P++ 跳过一个char*的指针
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;
}