环境:CLion 2021.3;64位macOS Big Sur
char* myStrcpy2(char* dest,const char* src)
{
assert(src != NULL);//断言,表达式为假报错
assert(dest != NULL);//断言,表达式为假报错
char* ret = dest;
while (*dest++ = *src++)
{
;
}
return ret;
}
(1)计数器实现
size_t myStrlen(const char* str)
{
assert(str != NULL);
//assert(str);
size_t len = 0;
while (*str++ != '\0')
{
len++;
}
return len;
}
(2)递归实现
int myStrlen(char *a)
{
if ('\0' != *a)
return 1 + myStrlen(a + 1);
else
return 0;
}
(3)指针运算实现
int myStrlen(char* str)
{
char* start = str;
while('\0' != str)
{
str++;
}
return str - start;
}
char* myStrcat(char *dest,const char *src)
{
assert(dest && src);
char *p = dest;//不操作起始地址
//找 \o
while(*p)
{
p++;
}
//赋值,包括\0
while( *p++ == *src++)
{
;
}
return dest;
}
int strcmp( const char *str1, const char *str2 )
{
assert( str1 && str2 );
while( *str1 == *str2 )
{
if( '\0' == *str1 )
return 0;//相等,返回0
str1++;
str2++;
}
return *str1 - *str2;//小于返回正数;否则返回负数
}
char *strstr( const char* str, const char* substr )
{//返回字串首次出现的首地址
assert( str && substr );
//记录每次比较的开始位置和substr的起始位置
const char* pstr = str;
const char* psub = substr;
//substr是空串
if( '\0' == *substr)
return (char*)str;
while( *pstr )
{
str = pstr;
substr = psub;
while( (*str == *substr) && *substr && *str )
{//逐个字符比较
str++;
substr++;
}
//找到了
if( '\0' == *substr )
return (char*)pstr;
//本趟未找到,开始下一次
pstr++;
}
return NULL;
}
void* myMemcpy( void* dest, const void* src, size_t count )
{
//只实现不重叠的情况,重叠的情况在myMemmove中实现
assert( dest && src);
void* tmp = dest;
while(count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
//注意不能使用*(char*)dest++的方式自增,因为强制类型转换是一个临时的状态,
//当++运行时(不论是前置还是后置),dest不再是char*了而是void*,自增不知道应该加多少
}
return tmp;
}
void *myMemmove(void *dest, const void *src, size_t count)
{
assert( dest && src);
void* tmp = dest;
//为了防止数据被覆盖的情况,分两种情况赋值
if(dest < src)
{//前 -> 后 赋值
while(count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{//后 -> 前 赋值
while(count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return tmp;
}
enum
{
INVALID,
VALID,
}state = INVALID;//非法的情况较多,因此将非法设置为默认状态
//将状态设置为全局变量,使用的时候只要在主函数中判断一下状态,即可知道是正常转换还是非正常转换
int myAtoi(const char *string)
{
int flag = 1;//标记正负号
//空指针检查
if(NULL == string)
return 0;
//空字符串检查
if(*string == '\0')
return 0;
//移除空白字符
while(isspace(*string))//isspace()函数用于检查是否为空格,制表符等空白字符
++string;
//检查正负号
if(*string == '-')
{
flag = -1;
++string;
}
else if(*string == '+')
++string;
//正常情况,开始转换
long long num = 0;
while(isdigit(*string))
{
num = 10 * num + flag * (string - '0');
//数字过大或过小
if(num > INT_MAX || num < INT_MIN)
return (int)num;
string++;
}
//判断while循环是否正常结束
if(*string == '\0')
{
state = VALID;//正常转换的结束
return (int)num;
}
else
return (int)num;
}
int numOf1(int n)
{
int count = 0;
while(n)
{
n = n & (n - 1);
count++;
}
return count;
}
int isPower2(int n)
{
int flag = 0;
if(0 == n & (n - 1))
flag = 1;
return flag;
}
int dif(int m,int n)
{
int res = m ^ n;
int count = 0;
for(int i = 0;i < 32;i++)
{
if(1 == (1 & (res >> i)))
count++;
}
return count;
}
void oddAndEven(int n)
{
for(int i = 31;i >= 1;i-=2)
printf("%d",1 & (n >> i));
for(int i = 30;i >= 0;i-=2)
printf("%d",1 & (n >> i));
}
int leastMul(int m,int n)
{
for(int i = 0; ;i++)
{
if(m * i % n == 0)
return m * i;
}
}
void reverse(char* left,char* right)
{
while(left < right)
{
int tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
void reverseWord(char* str)
{
char* start = str;
while(*start)
{
char* end = str;
while(' ' != *end && '\0' != *end)
{
end++;
}
reverse(start,end - 1);
if(' ' == *end)
start = end + 1;
else
start = end;
}
}
int Sn(int a,int bit)
{
int sum = 0;
int res = 0;
for(int i =0;i < bit;i++)
{
res = res * 10 + a;
sum += res;
}
return sum;
}
void ziMi()
{
for(int i = 0;i < 100000;i++)
{
int bit = 1;
int tmp1 = i
while(tmp1 / 10)
{
bit++;
tmp1 /= 10;
}
int sum = 0;
int tmp2 = i;
for(int j = 0;j < bit;j++)
{
sum += pow(tmp2 % 10,bit);
tmp2 /= 10;
}
if(i == sum)
printf("%d ", i);
}
}
int drink(int money)
{
int drink = money;
int empty = drink;
int total = money;
while(empty >= 2)
{
drink = empty / 2;
empty = empty % 2 + drink;
total += drink;
}
return total;
}
void yangHui()
{
int arr[10][10] = { 0 };
for(int i = 0; i < 10; i++)
{
for(int j = 0; j <= i; j++)
{
if(0 == j || i == j)
arr[i][j] = 1;
else
arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
}
}
for(int i = 0; i < 10; i++)
{
for(int j = 0; j <= i; j++)
{
printf("%-3d",arr[i][j]);
}
printf("\n");
}
}
5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果
A:B第二,我第三;
B:我第二,E第四;
C:我第一,D第二;
D:C最后,我第三;
E:我第四,A第一。
四人中每人说对了一半,请确定名次
void order()
{
for(int a = 1; a <= 5; a++)
{
for(int b = 1; b <= 5; b++)
{
for(int c = 1; c <= 5; c++)
{
for(int d = 1; d <= 5; d++)
{
for(int e = 1; e <= 5; e++)
{
if((2 == b) ^ (3 == a)
&& (2 == b) ^ (4 == e)
&& (1 == c) ^ (2 == d)
&& (5 == c) ^ (3 == d)
&& (4 == e) ^ (1 == a))
if(120 == a * b * c * d * e)
printf("a=%d b=%d c=%d d=%d e=%d",a,b,c,d,e);
}
}
}
}
}
}
有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的(不要求等差递增)
编写程序在这样的矩阵中查找某个数字是否存在,要求时间复杂的小于O(N),若找到返回1,且需要这个元素的位置信息,没找到返回0
int fingYang(char arr[][3], char* px, char* py, int n)
{
assert(px);
assert(py);
int x = 0;
int y = *py- 1;
while(x < *px && y >= 0)
{
if (arr[x][y] > n)
y--;
else if (arr[x][y] < n)
x++;
else
{
*px= x;//通过指针将位置信息带回去
*py= y;
return 1;
}
}
return 0;
}
实现一个函数,可以左旋字符串中的n个字符
void strRotate(char* pch, int n)
{
assert(pch);
int len = strlen(pch);
for(int i = 0; i < n; i++)//需要旋几次
{
char tmp = *pch;
for(int j = 0; j < len - 1; j++)//移动元素
{
*(pch + j) = *(pch + j + 1);
}
*(pch + len - 1) = tmp;
}
}
void reverse(char* left, char* right)
{
assert(left && right);
while(left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
void strRotate(char* pch, int n)
{
assert(pch);
int len = strlen(pch);
reverse(pch, pch + n - 1);
reverse(pch + n, pch + len - 1);
reverse(pch, pch + len - 1);
}
是返回1,否则返回0
int isRotate(char* pch1,char* pch2)
{
assert(pch1 && pch2);
int len = strlen(pch);
for(int i = 0; i < len; i++)//有几个元素就旋几次,暴力求解
{
char tmp = *pch;
for(int j = 0; j < len - 1; j++)//移动元素
{
*(pch + j) = *(pch + j + 1);
}
*(pch + len - 1) = tmp;
if(0 == strcmp(pch1,pch2))//每旋完一次就判断一次
return 1;
}
return 0;
}
int isRotate(char* pch1,char* pch2)
{
if( strlen(pch1) != strlen(pch2) )
return 0;//长度不一样一定不是旋转得到的
int len = strlen(pch1);
strncat(pch1, pch1, len);//追加一个自己本身,此时包含了所有旋转的情况
char* p = strstr(pch1,pch2);//若是子串,则返回子串在母串中第一次出现的位置,否则返回空指针
return p != NULL;
}
int check()
{
int a = 1;
char* pa = (char*)&a;
if(1 == *pa)
return 1;//小端
else
return 0;//大端
}
int check()
{
union U
{
int i;
char c;
}u;
u.i = 1;
return u.c;//小端返回1,大端返回0
}
int FindOne(int arr[],int size)
{
int ret = 0;
for(int i = 0; i < size; i++)
{
ret ^= arr[i];//相同的数字做异或结果为0,0与任何数字异或都是那个数字本身
//因此最后就只剩下一个不一样的数字
}
return ret;
}
假设数组中的元素为1234561234,返回5,6
void Find(int arr[], int size, int *px, int *py)
{
int tmp = 0;//记录一下两个不同的数异或的结果
for(int i = 0; i < size; i++)
{
tmp ^= arr[i];
}
//找两个数字第一个不同的二进制位的位置(其实也不一定非得第一个,只要找到不同就可以)
int firDifPos = 0;//位置从0开始记录
while((tmp & 1) != 1)
{
tmp >> 1;
++firDifPos;
}
//按照第firDifPos位是否为0分组,并将结果带回
for(int i = 0; i < size; i++)
{
if(((arr[i] >> firDifPos) & 1) == 0)
*px ^= arr[i];
else
*py ^= arr[i];
}
}
#define SWAP(num) (((num & 0xaaaaaaaa) >> 1) + ((num & 0x55555555) << 1))
0xaaaaaaaa转换为二进制就是10101010 10101010 10101010 10101010,将num与之做按位与运算,会将num的偶数位全部置为0(若按照0-31位计算),然后右移一位,相当于将num的奇数位移到了偶数位上;
0x55555555转换为二进制就是01010101 01010101 01010101 01010101,将num与之做按位与运算,会将num的奇数位全部置为0(若按照0-31位计算),然后左移一位,相当于将num的偶数位移到了偶数位上;
最后将上述的两个移位后的结果相加,其实就是num奇数位和偶数位交换后的结果。
#define OFFSETOF(struct_name,mem_name) ((int)&(((srtuct_name*)0)->mem_name))
首先将0强制类型转换为struct_name类型的指针,再用它访问目标成员,访问到后取地址,将这个地址在强制类型转换为int型,此时得到的就是目标成员相对于结构体首地址的偏移量。
在内存中的地址比如0x0000aabb,其实也就是一个十六进制的数而已,因此将0看作为地址也没什么;
这里的用法只是假设0为地址,并没有访问实际地址为0的空间,这样做的便利之处在于不必每次都用目标成员的地址减去起始地址,因为其实地址已经是0了。