1.杨氏矩阵

 

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

int Findnum(int arr[3][3], int key, int rows, int cols)
{
    int row = 0;//右上角下标
    int col = cols-1;
    while ((row >= 0) && (col <= cols-1))
    {
        if (key < arr[row][col])
        {
            col--;
        }
        if (key > arr[row][col])
        {
            row++;
        }
        if (key == arr[row][col])
        {
            return 1;
        }
    }
    return 0;
}

int main()
{
    int arr[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 10};
    int key = 9;
    int ret = Findnum(arr, key, 3, 3);
    if (ret == 0)
    {
        printf("no\n");
    }
    else if (ret == 1)
    {
        printf("yes\n");
    }
    system("pause\n");
    return 0;
}
#include <stdio.h>
 
int findnum(int a[][3], int x, int y, int f) //第一个参数的类型需要调整
{
	int i = 0, j = x - 1; //从右上角开始遍历
 
	while (j >= 0 && i < y)
	{
		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;
}

2.有序序列合并

输入两个升序排列的序列,将两个序列合并为一个有序序列并输出。

数据范围: 1 \le n, m \le 1000 \1≤n,m≤1000  , 序列中的值满足 0 \le val \le 30000 \0≤val≤30000 

输入描述:

输入包含三行,

第一行包含两个正整数n, m,用空格分隔。n表示第二行第一个升序序列中数字的个数,m表示第三行第二个升序序列中数字的个数。

第二行包含n个整数,用空格分隔。

第三行包含m个整数,用空格分隔。

输出描述:

输出为一行,输出长度为n+m的升序序列,即长度为n的升序序列和长度为m的升序序列中的元素重新进行升序序列排列合并。

输入:

5 6
1 3 7 9 22
2 8 10 17 33 44

输出:

1 2 3 7 8 9 10 17 22 33 44
#include <stdio.h>
int main()
{
    int a,b,c[100],temp;
    scanf("%d",&a);
    scanf("%d",&b);
    for(int i=1;i<=a+b;i++)
    {
        scanf("%d",&c[i]);
    }
    for (int i = 1; i <= a+b; i++)
	{
		for (int j = 1; j <= a+b - i; j++)
		{
			if (c[j] > c[j + 1])
			{
				temp = c[j];
				c[j] = c[j + 1];
				c[j + 1] = temp;
			}
		}
	}
    for(int i=1;i<a+b+1;i++)
    {
        printf("%d ",c[i]);
    }
    return 0;
}

3.空心三角形图案

输入描述:

多组输入,一个整数(3~20),表示输出的行数,也表示组成三角形边的“*”的数量。

输出描述:

针对每行输入,输出用“*”组成的“空心”三角形,每个“*”后面有一个空格。

输入:

4

输出:

*       
* *     
*   *   
* * * * 
#include <stdio.h>
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j = 1;j<2*i+1;j++)
            {
                if(i==n)
                {
                    if(j&1==1)
                    printf("*");
                else
                    printf(" ");
                    continue;
                }
                if(j==1||j==2*i-1)
                    printf("*");
                else
                    printf(" ");
            }
            printf("\n");
        }
    }
    return 0;
}
#include<stdio.h>
void fun(int n)
{
	int i = 0;
	int count = 0;
	if (n >= 1)
	{
		printf("* \n");
	}

	for (i = 2; i <= n - 1; i++)
	{
		int j = 0;
		for (j = 1; j < 2; j++)
		{
			printf("* ");

			if (i >= 3 && i < n)
			{
				count++;
				int k = 0;
				for (k = 1; k <= 2 * count; k++)
				{
					printf(" ");

				}
			}
			printf("* ");
		}
		printf("\n");
	}
	for (i = 0; i < n&&n >= 2; i++)
	{
		printf("* ");
	}
	printf("\n");
}
int main()
{
	
	int count = 0;
	int n = 0;
	while (scanf("%d", &n) == 1)
	{
		fun(n);
    }

}

4.X形图案

输入描述:

多组输入,一个整数(2~20),表示输出的行数,也表示组成“X”的反斜线和正斜线的长度。

输出描述:

针对每行输入,输出用“*”组成的X形图案。

示例1

输入:

5

输出:

*   *
 * * 
  *  
 * * 
*   *
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
    int a;
    while(~scanf("%d",&a))
    {
        for(int i = 0;i<a;i++)
        {
            for(int j = 0;j<a;j++)
            {
                if(i == j||i+j == a-1) printf("*");
                else printf(" ");
            }
            printf("\n");
        }
    }
    return 0;
}
#include<stdio.h>
int main()
{
    int n = 0;
    int i = 0;
    int j = 0;

    while (scanf("%d", &n) != EOF)
    {
        for (i = 1; i <= n; i++)
        {
            for (j = 1; j <= n; j++)
            {
                if (j == i || j == n-i+1)
                {
                    printf("*");
                }
                else
                {
                    printf(" ");
                }
            }
            printf("\n");
        }
    }
    return 0;
}

5.序列中删除指定数字

有一个整数序列(可能有重复的整数),现删除指定的某一个整数,输出删除指定数字之后的序列,序列中未被删除数字的前后位置没有发生改变。

数据范围:序列长度和序列中的值都满足 1 \le n \le 501≤n≤50

输入描述:

第一行输入一个整数(0≤N≤50)。

第二行输入N个整数,输入用空格分隔的N个整数。

第三行输入想要进行删除的一个整数。

输出描述:

输出为一行,删除指定数字之后的序列。

示例1

输入:

6
1 2 3 4 5 9
4

输出:

1 2 3 5 9
#include<stdio.h>
int main()
{
    int n,x;
    scanf("%d",&n);
    int arr[n],i;
    for(i=0;i<n;i++)
    {
        scanf("%d",&arr[i]);
    }
    scanf("%d",&x);
    for(i=0;i<n;i++)
            arr[i]^=x;
    for(i=0;i<n;i++)
    {
        if(arr[i]!=0)
            printf("%d ",arr[i]^x);
    }
    return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include<stdlib.h>
#include<stdio.h>
int main()
{
	int num;
	scanf("%d", &num);
	int* arr = (int*)malloc(sizeof(int) * num);
	for (int i = 0; i < num; i++)
	{
		int number;
		scanf("%d", &number);
		arr[i] = number;
	}
	int pos;
	scanf("%d", &pos);
	int dst = 0, cur = 0;
	int count = 0;
	while(cur < num)
	{
		if (arr[cur] != pos)
		{
			arr[dst] = arr[cur];
			dst++;
			cur++;
			count++;
		}
		else
		{
			cur++;
		}
	}
	for (int i = 0; i < count; i++)
	{
		printf("%d ", arr[i]);
	}
}

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

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

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

AABCD左旋一个字符得到ABCDA

AABCD左旋两个字符得到BCDAA

AABCD右旋一个字符得到DAABC

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma warning(disable:4996)

// 只需要把原字符串来两遍, 包括了左旋和右旋的所有可能性 7次会到原字符串
// 再看一下待查字符串是不是它的字符串(来两遍后的字符串里面的)
// 如果是 找到了 则strstr返回值 绝不是空NULL

int strRoundStr(char* src, char* find)
{
	char tmp[256] = { 0 };

	// 使src在tmp 里来两遍
	strcpy(tmp, src);
	strcat(tmp, src);

	// 如果返回值不是空 返回1 代表找到了
	// 如果返回值为0, 则没找到
	return strstr(tmp, find) != NULL;
}
int main()
{

	char src[] = "ABCDEFG";

	char find[] = "GA";// 算左旋一个之后的结果
	printf("%d\n", strRoundStr(src, find));// 找到了

	char find1[] = "GAa";
	printf("%d\n", strRoundStr(src, find1));// 没找到

	system("pause");
	return 0;
}
#include <string.h>
#include <stdio.h>
void left_revolve(char* arr, int n,int len)
{
	n = n%len;
	int i = 0;
	for (i = 0; i < n; i++)
	{
		char copy = arr[0];
		int j = 0;
		for (j = 0; j < len - 1; j++)
		{
			arr[j] = arr[j + 1];
		}
		arr[j] = copy;
	}
}
void judge(char* arr1, char* arr2)
{
	int ret=strcmp(arr1, arr2);
	if (ret == 0)
	{
		printf("判断结果:相同\n");
	}
	else
	{
		printf("判断结果:不相同\n");
	}
}
int main()
{
	int n = 0;
	char arr1[] = "ABCD";
	char arr2[] = "CDAB";
	printf("左旋前:%s\n", arr1);
	printf("判断字符串:%s\n", arr2);
	int len = strlen(arr1);
	printf("左旋几个字符:");
	scanf("%d", &n);
	left_revolve(arr1, n,len);
	printf("左旋后:%s\n", arr1);
	judge(arr1, arr2);
	return 0;
}

7.模仿qsort的功能实现一个通用的冒泡排序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct imag //定义结构体
{
	char name[10] ;
	double grade;
	int age;
};

int int_compar (const void *p,const void *q)//比较两个数的大小
{
	return *((int *)p)-*((int *)q);
}

int struct_int_com (const void *p,const void *q)//结构体整形比较
{
	return ((struct imag*)p)->age-((struct imag*)q)->age;
}

int struct_str_com (const void *p,const void *q)//结构体字符串比较
{
	return (strcmp ((*(struct imag*)p).name, (* (struct imag*) q).name));
}

int struct_double_com (const void *p,const void *q)//结构体浮点型比较
{
	return ((*(struct imag*)p).grade > ((struct imag*)q)->grade);
}

void swap_num(void *p, void *q, int sz)//交换两个数的函数
{
	int i = 0;
	for (i=0; i<sz; i++)
	{
		char tmp = *((char *)p+i);
		*((char *)p+i)= *((char *)q+i);
	    *((char *)q+i) = tmp;
	}
}

void bubble_sort(	void * arr,/*要排序的数组*/
					int num, /*数组元素个数*/
					int size,/*每个元素占的字节数*/ 
					int(*compar)(const void *,const void *))/*函数指针,用来比较两个元素的大小,大于返回正值,等于返回零,小于返回负值*/		
{
	int i = 0;	
	int j = 0;
	for (i=0; i<num-1; i++)
	{
		for(j=0; j<num-1-i; j++)
		{
			if (compar((char *)arr+j*size, (char *)arr+(j+1)*size) > 0)
			{
				swap_num((char *)arr+j*size, (char *)arr+(j+1)*size, size);
			}
		}
	}
}

void print_num(int *arr, int sz)//打印整形数组
{
	int i = 0;
	for (i=0; i<sz; i++)
	{
		printf ("%d ", arr[i]);
	}
	printf ("\n");
}

void print_struct(struct imag arr[], int sz)//打印结构体数组
{
	int i = 0;
	printf ("姓名\t成绩\t年龄\n");
	for (i=0; i<sz; i++)
	{
		printf ("%s\t%.2lf\t%d\n",arr[i].name , arr[i].grade, arr[i].age);
	}
	printf ("\n");
}


int main()
{
	int i = 0;

	int arr_int[10] = {1, 2, 5, 8, 6, 4, 7, 3, 80, 10};
	char *arr_str[] = {"bcdef", "abcde", "efghi", "defgh", "cdefg"};

	struct imag arr_stu[3]= {{"xiaomin",96.5, 18}, {"lisi", 88.2, 19}, {"wangwu", 66.9, 15}};
	//排序整形数字
	printf ("给整形数字排序>\n");
	bubble_sort(arr_int, sizeof(arr_int)/sizeof(arr_int[0]), sizeof(arr_int[0]), int_compar);
	print_num(arr_int, sizeof(arr_int)/sizeof(arr_int[0]));
	printf ("\n");

	//排序结构体中的整形
	printf ("按结构体中的(年龄)整形排序>\n");
	bubble_sort(arr_stu, sizeof(arr_stu)/sizeof(arr_stu[0]), sizeof(arr_stu[0]), struct_int_com);
	print_struct(arr_stu, sizeof(arr_stu)/sizeof(arr_stu[0]));

	//排序结构体中的字符串
	printf ("按结构体中的(姓名)字符串排序>\n");
	bubble_sort(arr_stu, sizeof(arr_stu)/sizeof(arr_stu[0]), sizeof(arr_stu[0]), struct_str_com);
	print_struct(arr_stu, sizeof(arr_stu)/sizeof(arr_stu[0]));

	//排序结构体中的浮点型数字
	printf ("按结构体中的浮点型(成绩)排序>\n");
	bubble_sort(arr_stu, sizeof(arr_stu)/sizeof(arr_stu[0]), sizeof(arr_stu[0]), struct_double_com);
	print_struct(arr_stu, sizeof(arr_stu)/sizeof(arr_stu[0]));

	system ("pause");
	return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<math.h>

int comp(const void* a, const void* b)
{
	return *(int*)a - *(int*)b;
}
void Swap(int*a, int* b)
{
	int tmp;
	tmp = *a;
	*a = *b;
	*b = tmp;
}

void Bubblesort(int* arr, int size, int width, int(*comp)(const void* a, const void* b)){
	for (int bound = 0; bound < size; bound++)
    {
		for (int cur = size - 1; cur>bound; cur--)
        {
			int ret = comp(&arr[cur - 1], &arr[cur]);
			if (ret>0)
            {
				Swap(&arr[cur - 1], &arr[cur]);
			}
		}
	}
}

int main(){
	int arr[] = { 9, 5, 2, 7 };
	int size = sizeof(arr) / sizeof(arr[0]);
	Bubblesort(arr, size,sizeof(arr[0]),comp);
	for (int i = 0; i < size; i++)
    {
		printf("%d ", arr[i]);
	}
	system("pause");
	return 0;
}

8.练习使用库函数,qsort排序各种类型的数据

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//字符型
int cmp(const void* a, const void* b) 
{
	return *(char*)a - *(char*)b;
}
int main() 
{
	char arr[] = "akvhelb";
	int size = strlen(arr);
	for (int i = 0; i < size; i++) 
    {
		printf("s", arr[i]);
	}
	printf("\n");
	qsort(arr, size, sizeof(char), cmp);
	for (int i = 0; i < size; i++) 
    {
		printf("%s", arr[i]);
	}
	system("pause");
	return 0;
}

//double型
int cmp(const void* a, const void* b) 
{
	return *(double*)a - *(double*)b;
}

int main() 
{
	double arr2[] = {8.4, 6.3, 7.7, 9.3, 5.1, 1.0};
	int size = sizeof(arr2) / sizeof(arr2[0]);
	for (int i = 0; i < size; i++) 
    {
		printf("%f ", arr2[i]);
	}
	printf("\n");
	qsort(arr2, size, sizeof(double), cmp);
	for (int i = 0; i < size; i++) 
    {
		printf("%f ", arr2[i]);
	}
	system("pause");
	return 0;
}

//字符串型
int cmp(const void* a, const void* b) 
{
	return strcmp(*(char**)a, *(char**)b);
}


int main() 
{
	char* arr3[] = {"kkk", "hhh", "bbb", "rrr"};
	int size = sizeof(arr3) / sizeof(arr3[0]);
	for (int i = 0; i < size; i++) 
    {
		printf("%s", arr3[i]);
	}
	printf("\n");
	qsort(arr3, size, sizeof(char*),cmp);
	for (int i = 0; i < size; i++) 
    {
		printf("%s", arr3[i]);
	}
	system("pause");
	return 0;
}
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
int cmp1(const void *a, const void *b)
{
    assert(a);
    assert(b);
    return (*(unsigned char *)a - *(unsigned char *)b);
}

int cmp2(const void *a, const void *b)
{
    assert(a);
    assert(b);
    return strcmp((char *)*(int *)a, (char *)*(int *)b);
}

int cmp3(const void *a, const void *b)
{
    assert(a);
    assert(b);
    return (*(unsigned int *)a - *(unsigned int *)b);;
}

int cmp4(const void *a, const void *b)
{
    assert(a);
    assert(b);
    return (((*(double *)a - *(double *)b) > 0) ? 1 : -1);
}

int main()
{
    int i = 0;
    char c[10] = "adicfjgheb";
    char *s[5] = { "aaa", "ddd", "iii", "ccc", "fff" };
    /*char c[10] = { 'a', 'c', 'i', 'e', 'b', 'j', 'f', 'h', 'd', 'g' };*/
    int a[10] = { 1, 3, 4, 5, 8, 0, 9, 7, 2, 6 };
    double b[10] = { 0.3, 1.7, 2.5, 0.1, 3.9, 2.1, 0.4, 0.2, 1.5, 2.3 };
    qsort(c, 10, sizeof(char), cmp1);
    qsort(s, 5, sizeof(char *), cmp2);
    qsort(a, 10, sizeof(int), cmp3);
    qsort(b, 10, sizeof(double), cmp4);
    for (i = 0; i < 10; i++)
    {
        printf("%c ", c[i]);
    }
    printf("\n");
    for (i = 0; i < 5; i++)
    {
        printf("%s ", s[i]);
    }
    printf("\n");
    for (i = 0; i < 10; i++)
    {
        printf("%d ", a[i]);
    }
    printf("\n");
    for (i = 0; i < 10; i++)
    {
        printf("%lf ", b[i]);
    }
    printf("\n");
    return 0;
}

9.模拟实现strlen函数

第一种方法:使用计数器的方法
当字符数组的指针没有指向’\0’即字符串结束标志时,也就是当字符串没有结束时,让字符数组的指针一直往后移动,同时每移动一位,count的值加1一次,最后函数返回count的值,即返回了字符串的长度。

注意
1、我们传参的指针不能为空,所以要使用assert进行断言。
2、因为是判断字符串长度,所以字符串是不变的,所以用const修饰。

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
size_t my_strlen(const char * str)
{
	assert(str);
	
	int count = 0;
	while (*str)
	{
		++count;
		++str;
	}
	return count;
}
int main()
{
	
	char* p = "hello world";
	printf("%d", my_strlen(p));
	return 0;
}

第二种:使用递归的方法

先判断指针是否为空,如果为空,那么函数返回0,否则返回:1+strlen(str+1)。

  • 注意
    1、我们传参的指针不能为空,所以要使用assert进行断言。
    2、因为是判断字符串长度,所以字符串是不变的,所以用const修饰。
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
size_t my_strlen(const char * str)
{
	assert(str);
	
	if (*str == '\0')
	{
		return 0;
	}
	else
	{
		return 1 + my_strlen(str + 1);
	}

}
int main()
{
	
	char* p = "hello world";
	printf("%d", my_strlen(p));
	return 0;
}

第三种:采用指针相减的方法
我们知道,指针-指针的结果是返回之间元素的个数。所以我们可以定义一个指针变量将字符串首元素的地址存放起来, 然后当字符串指针没有找到’\0’时让指针后移,最后将字符串指针-刚才定义的首元素地址的指针,得到的就是字符串的个数。

注意
1、我们传参的指针不能为空,所以要使用assert进行断言。
2、因为是判断字符串长度,所以字符串是不变的,所以用const修饰。

include<stdio.h>
#include<stdlib.h>
#include<assert.h>
size_t my_strlen(const char * str)
{
	assert(str);
	const char*end = str;
	while (*end)
	{
		++end;
	}
	return end - str;
}
int main()
{
	
	char* p = "hello world";
	printf("%d", my_strlen(p));
	return 0;
}

10.模拟实现memmove

void * memmove ( void * dst, const void * src, size_t count)
{
  void * ret = dst;
​
  if (dst <= src || (char *)dst >= ((char *)src + count)) {
    /*
    * Non-Overlapping Buffers
    * copy from lower addresses to higher addresses
    */
    while (count--) {
        *(char *)dst = *(char *)src;
        dst = (char *)dst + 1;
        src = (char *)src + 1;
   }
 }
  else {
    /*
    * Overlapping Buffers
    * copy from higher addresses to lower addresses
    */
    dst = (char *)dst + count - 1;
    src = (char *)src + count - 1;
​
    while (count--) {
        *(char *)dst = *(char *)src;
        dst = (char *)dst - 1;
        src = (char *)src - 1;
   }
 }
​
  return(ret);
}

11.模拟实现atoi

※atoi的规则是:跳过不可见字符,碰到负号或者数字开始转换,转换到非数字字符为止。

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
//VALID 表示结果合法
//INVALID 表示结果非法
enum State
{
 VALID,//0
 INVALID//1
};
//默认结果可能非法,当正确转换后再改为合法
enum State state = INVALID;
​
int my_atoi(char *str)
{
 int flag = 1;
 long long ret = 0;
 assert(str);
 state = INVALID;
  //跳过空白字符
 while(isspace(*str))
 {
  str++;
 }
 if(*str == '\0')
 {
  return 0;
 }
  //跳过正负号
 if(*str == '+')
 {
  str++;
 }
 else if(*str == '-')
 {
  flag = -1;
  str++;
 }
  //开始转换数字字符直到非数字字符
 while(isdigit(*str))
 {
  ret = ret * 10 + flag * (*str-'0');
  if((ret > INT_MAX) || (ret < INT_MIN))
  {
   return 0;
  }
  str++;
 }
  //正常停止
 if(*str == '\0')
 {
  state = VALID;
  return (int)ret;
 }
 else
 {
    //遇到非数字字符
  return (int)ret;
 }
}
​
int main()
{
 char *p = "-1212212121212";
 printf("%d\n", my_atoi(p));
 return 0;
}
#include<stdio.h>
#include<assert.h>
#include<ctype.h>
#include<limits.h>
enum State              //标记返回的数值是否合法
{
    VALID,
    INVALID
};
static enum State state = INVALID;    //默认值为不合法
int my_atoi(const char *str)
{
    long long ret = 0; //要判断是否溢出,所以让值存储在比int大的类型中,与int能存储的最大值进行比较
    int flag = 1;               //区别正负值问题
    assert(str != NULL);         //空指针
    if (*str == '\0')            //空串
        return 0;
    //前面为空字符
    while (isspace(*str))            //头文件为ctype.h                     
    {
        str++;
    }
    //正负号问题
    if (*str == '-')                                            
    {
        flag = -1;
        str++;
    }
    else if (*str == '+')
    {
        str++;
    }
    while (*str)                                                   
    {
        //是否为数字字符问题 
        if (isdigit(*str))                                    
        {
            ret = ret * 10 + (*str - '0') * (flag);                        
            //溢出问题
            if (ret > INT_MAX || ret < INT_MIN)
            {
                return 0;
            }
        }
        else
        {
            //字符中的非数字字符
            state = VALID;
            return (int)ret;
        }
        str++;
    }
    state = VALID;
    return (int)ret;
}
int main()
{
    int ret = 0;
    char p[20] = {0};
    printf("Please input->_: ");
    scanf("%s", p);
    ret = my_atoi(p);
    if(state == VALID)    //对模拟实现的函数来说 如果转化值不合法,则不进行输出
        printf("my_atoi(p) = %d\n", ret);
    printf("atoi(p)    = %d\n", atoi(p));
    return 0;
}

12.模拟实现strncat

char * mystrncat(char * dst, const char * src, size_t n)
{
	char * tmp = dst;
   
  while (*dst)
  {
    dst++;
  }
   
  int i;
  for (i = 0; src[i] && i < n; i++)
  {
    dst[i] = src[i];
  }
   
  dst[i] = 0;
  return tmp;
}
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//模拟实现strncat函数(长度受限制的字符串拼接)
//函数原型:char* strncat(char* dest,count char* src,size_t count)
//作用:将源字符串里的count个字符拼接到目标字符串上
//注意:目标字符串空间必须足够大
void myStrncat(char* dest, const char* src, size_t count) {
//参数合法性判定
	assert(dest != NULL && src != NULL);
	//将dest地址保存起来
	char* ret = dest;
	//找到目标字符串的末尾
	while (*dest!='\0') {
		dest++;
	}
	//拼接count个
	while (count--) {
		if (*src != '\0') {
			*dest++ = *src++;
		}
	}
	*dest = '\0';
	return ret;
}
int main() {
	//目标字符串空间必须足够大,如下面的str1应写入一个足够大的数字
	//否则会提示str1被破坏(如果不写长度只有5)
	char str1[20] = "hehe";
	char str2[] = "yyy";
	myStrncat(str1, str2, 2);
	printf("%s\n", str1);
	system("pause");
	return 0;
}

13.模拟实现strncpy

char * mystrncpy(char * dst, const char * src, size_t n)
{
	int i;
  for (i = 0; src[i] && i < n; i++)
  {
    dst[i] = src[i];
  }
   
  if (i < n)
  {
  	dst[i] = 0;
  }
  return dst;
}
//模拟实现strncpy:将指定长度的字符串复制到目标字符串中
//函数原型:char* strncpy(const char* dest,const char* src,size_t n)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
void myStrncpy( char* dest, const char* src, size_t n) {
	//参数合法性判定
	assert(dest != NULL && src != NULL);
	//将dest的地址保存起来
	char* ret = dest;
	while (n--) {
		*dest++ = *src++;
	}
	return ret;
}
int main() {
	char str1[20] = "hahaha";
	char str2[10] = "eeeeee";
	int n = 0;
	printf("请输入复制个数:");
	scanf("%d", &n);
	myStrncpy(str1, str2, n);
	printf("%s\n", str1);
	system("pause");
	return 0;
}

14.一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。编写一个函数找出这两个只出现一次的数字。

找出一个只出现过一次的数字的问题处理方法就是找一个数字把里面所有的数字都异或一遍,利用异或两次等于没异或的特点来处理。那么如果有两个数字都只出现了一次,那么如此得到的应该是两个数异或的结果。首先这个结果肯定不是0(要不然就全都配对了),所以里面一定至少一位是一。找出值为1的一位,以这一位的值将结果分为两组。例如1 2 3 4 1 2,异或完的结果应该是3^4得到的111,那么随便找一位就行了。例如找最低位,那么这一位是1的有1 3 1,是0的有2 4 2,由于是利用异或结果为1的某一位分的组,所以两个待查询数字一定分别在两组中。所以再找两个变量,分别异或两组数,即可找到这两个数。

void findTwoNum(int arr[], int n, int * pnum1, int * pnum2)
{
 int i;
 int sum = 0;
​
 for (i = 0; i < 9; i++)
 {
  sum ^= arr[i];
 } //先找到两个数互相异或的结果
​
 int pos;
 for (i = 0; i < 32; i++)
 {
  if (sum & 1 << i)
  {
   pos = i;
   break;
  }
 } //再找到有分歧的一位。在这一位上,两个数一定是一个1一个0
​
 *pnum1 = *pnum2 = 0;
 for (i = 0; i < 10; i++)
 {
  if (arr[i] & 1 << pos)
  {
   *pnum1 ^= arr[i]; //这一位是1的,放在数1里
  }
  else
  {
   *pnum2 ^= arr[i]; //这一位是0的,放在数2里
  }
 }
}
void find(int arr[], int siz) {
    int  eor=0;
    for (int j = 0; j < siz; j++) {
        eor ^= arr[j];
    }
    int last = eor & (~eor + 1);
    int dsg=0;
    for (int j = 0; j < siz; j++) {
        if ((last & arr[j]) != 0) {
            dsg ^= arr[j];
        }
    }
    printf("%d %d",dsg, dsg ^ eor);
}
int main() {
    int arr[] = { 1,1,2,2,3,3,4,7,5,5,6,6};
    find(arr,sizeof(arr)/sizeof(arr[0]));
}

15.交换奇偶位

写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换。

#define SwapIntBit(n) (((n) & 0x55555555) << 1 | ((n) & 0xaaaaaaaa) >> 1)

交换奇偶位,需要先分别拿出奇偶位。既然是宏,分别拿出用循环不是很现实,那就用&这些位的方式来做。奇数位拿出,那就是要&上010101010101……,偶数位拿出,就是要&上101010101010……,对应十六进制分别是555……和aaa……,一般我们默认是32位整数,4位对应一位16进制就是8个5,8个a。通过& 0x55555555的方式拿出奇数位和& 0xaaaaaaa的方式拿出偶数位。奇数位左移一位就到了偶数位上,偶数位右移一位就到了奇数位上,最后两个数字或起来,就完成了交换。

※这个宏只能完成32位以内的整形,要想完成64位的,那就将5和a的数量翻倍即可。

16.offsetof宏

写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明

考察: offsetof宏的实现
#define offsetof(StructType, MemberName) (size_t)&(((StructType *)0)->MemberName)

StructType是结构体类型名,MemberName是成员名。具体操作方法是:

1、先将0转换为一个结构体类型的指针,相当于某个结构体的首地址是0。此时,每一个成员的偏移量就成了相对0的偏移量,这样就不需要减去首地址了。

2、对该指针用->访问其成员,并取出地址,由于结构体起始地址为0,此时成员偏移量直接相当于对0的偏移量,所以得到的值直接就是对首地址的偏移量。

3、取出该成员的地址,强转成size_t并打印,就求出了这个偏移量。

更多推荐

c语言---刷题03