C/Python经典code片段之学习总结

摘要

本文目的是总结平时学习过程中,遇到的经典代码,看到写得好的代码,可以作为参考模板的,为了方便自己查询借鉴,所以记录在这里。欢迎大家一起来学习。

1. Python decorator

  • Python装饰器
    作用:在不改变原函数的情况下,扩展函数功能。
  • 核心思想
    首先要形成闭包,并且函数之间要有引用,函数返回的是函数。
def timer(func):
	def wrapper(*args, **kwds):
		t0 = time.time()
		func(*args, **kwds)
		t1 = time.time()
		print("time cosumption is ", (t1-t0))
	return wrapper

@timer
def do_something():
	print("start to do something...")
	time.sleep(4)
	print("finished to do something")


do_something()

2. C copyStr func

C语言中没有字符串复制,这是一个经典的字符串复制Implementation。

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

//此处可用指针函数也可以用普通函数
const char* const copyStr(const char *src, char *des) {
	assert(src != NULL && src != NULL);

	char *temp = des;
	while((*des++ = *src++));
	return temp;
}

int main() {
	char p1[12] = "Hello World"; //字符串的存储用数组
	char p2[10]; //注意数组的初始化,可用memset()
	memset(p2, 0, sizeof(p2));
	
	printf("Before calling the copyStr func *p1 = %s\n", p1);
	copyStr(p1, p2);
	printf("After calling the copyStr func *p2 = %s\n", p2);
}

3. C macro function

宏函数的定义模板

#include<stdio.h>

//define macro function
//note the parenthese for every parameter
#define MAX(a, b) ((a)>(b)?(a):(b))
#define SWAP(a, b) \
a = a + b; \
b = a - b; \
a = a - b;


int main() {
	double x = 20.5;
	int y = 10;

	SWAP(x, y);
	printf("After swap x = %f, y = %d\n", x, y);

	double max = MAX(x, y);
	printf("The max number is max = %f\n", max);
}

4. C function pointer

函数指针
作用:用于指向函数的指针。

#include<stdio.h>

//one line function
int max(int x, int y) {return (x>y?x:y);}

int main() {
	//define a function pointer
	//why: can pointer different function
	int (*func_p)(int, int);

	int a = 20;
	int b = 30;
	int c = 0;

	func_p = &max; //also can be func_p = max;
	c = func_p(a, b);

	printf("The max number is max = %d\n", c);
}

5. C initialization of string pointer

C常用的指针初始化的方法
1.採用NULL或空指针常量,如:int *p = NULL;或 char *p = 2-2; 或float *p = 0;
2.取一个对象的地址然后赋给一个指针,如:int i = 3; int *ip = &i;
3.将一个指针常量赋给一个指针,如:long *p = (long *)0xfffffff0;
4.将一个T类型数组的名字赋给一个同样类型的指针,如:char ary[100]; char *cp = ary;
5.将一个指针的地址赋给一个指针,如:int i = 3; int *ip = &i;int **pp = &ip;
6.将一个字符串常量赋给一个字符指针,如:char *cp = “abcdefg”;

#include<stdio.h>

int main() {
	//method 1 for initialization
	char* ptr1 = "Hello World!"; //constant string returns a pointer head address
	ptr1 = "can't modify"; //constant string

	//method 2 for initialization
	//assignment for pointer address
	char *ptr2 = (char *)0x12;  //must use forced type conversion

	//important
	//error: can't modify the constant string
	//*ptr1 = "modify"; 

	printf("ptr1 = %s, the address of ptr2 = 0x%p\n", ptr1, ptr2);
}

6. C static linkedList && dynamic linkedList

  • C 语言中的单向静态链表
  1. 单向静态链表结构图
    在这里插入图片描述

  2. 链表和数组的对比
    链表不需要一次性分配连续存储空间(动态链表),数组是一次性分配连续的存储空间。
    链表插入删除效率高,数组插入删除效率低。

  3. 静态链表
    存储空间静态的,一次性分配好足够的空间,模拟实现数组的功能。

  4. 代码示例

#include<stdio.h>

typedef struct linkList {
	int data;
	struct linkList *next;
}LinkList;

int main() {

	//define a static linkedlist
	LinkList link1 = {10, NULL};
	LinkList link2 = {20, NULL};
	LinkList link3 = {30, NULL};

	//configure the linkedlist
	link1.next = &link2;
	link2.next = &link3;
	//tail node must set NULL
	link3.next = NULL;

	//define the head node
	struct linkList *head = &link1;

	while(head != NULL) {  //also can be while(head)
		printf("The data from the node [%d]\n", head->data);
		//pointer the next node
		head = head->next;
	}
}
  • C 语言中的动态链表
  1. 动态链表
    存储空间不连续,动态申请内存,每个节点物理地址不连续。
#include<stdio.h>
#include<stdlib.h>

typedef struct linkList {
	int data;
	struct linkList *next;
}LinkList;

int main() {

	//dynamicly apply for 3 linkedlist
	struct linkList *link1 = (struct linkList*)malloc(sizeof(LinkList));
	struct linkList *link2 = (struct linkList*)malloc(sizeof(LinkList));
	struct linkList *link3 = (struct linkList*)malloc(sizeof(LinkList));

	//initialization for link node
	link1->data = 10;
	link2->data = 20;
	link3->data = 30;

	//define a head node
	struct linkList *head;

	//make head node pointer the first node
	//initialization for head node
	head = link1; //must initial, if not, will prompt error

	//configuration for the relationship for linkedlist
	link1->next = link2;
	link2->next = link3;
	link3->next = NULL;

	while(head != NULL) {
		printf("Current head data: head->data = %d\n", head->data);
		head = head->next;
	}
}

7. C identify big/little mode

二进制存储方式有大端模式和小端模式。
通过联合体结构元素来判断大小端模式。
注意:不可以通过移位运算,&按位与运算来确定大小端模式,因为移位运算,&按位与运算都是编译器提供的方法,与二进制的存储方式无关。

#include<stdio.h>

typedef union data {
	int a;
	short b;
}dataU;


//identify if big end mode
int main() {
	dataU num;
	num.a = 0x12345678;

	if (num.b == 0x1234) {
		printf("Big mode\n");
	} else {
		printf("Little mode\n");
	}
}

8. Python produce all year day

产生任意一年的所有日期,主要是针对time模块的练习。
常用函数:
time.mktime():返回以秒为单位的时间
time.strptime(): 字符串时间
time.strftime(): 可以指定格式的字符串时间

import time

#生成出生当年所有日期
def dateRange(year):
    fmt = '%Y-%m-%d'
    bgn = int(time.mktime(time.strptime(year+'-01-01',fmt)))
    end = int(time.mktime(time.strptime(year+'-12-31',fmt)))
    list_date = [time.strftime(fmt,time.localtime(i)) for i in range(bgn,end+1,3600*24)]

    #return [i.replace('-','') for i in list_date]

    #list_year = [i for i in range(bgn, end+1, 3600*24)]
    #print(list_year)

    return [i for i in list_date]

data_time  = dateRange('1993')
print(data_time)

9. Python reverse an integer

反转一个整型数据,比如-123反转之后变成321。
同时也是对python类的练习。

class Solution(object):
	def reverse(self, x):
		if -10<x<10:
			return -x
		x_str = str(x)
		if x_str[0] == "-":
			#here can use oneline implementation
			#eg: x = int(x_str[1:][::-1])
			x_str = x_str[1:4]
			return int(x_str[::-1])
		else:
			x = int(x_str[::-1])
			return x

s = Solution()
reverse_int = s.reverse(-987)
print(reverse_int)

11. C Bit-Field

  • 位域与联合体的使用
    为了不浪费存储空间,在定义变量的时候,按bit分配存储空间,用多少分配多少。
#include<stdio.h>
#define bool _Bool
struct BitField {
	short a:12;
	bool b:1;  //note: if type is short here, it will prompt error
};

union Union {
	struct BitField BF;
	short n;
};

int main() {
	union Union ubf;

	ubf.n = 0;
	ubf.BF.a = 0x7ee;
	ubf.BF.b = 0x01;
	printf("the size of the ubf = %d Byte, ubf.BF.a = 0x%x, ubf.BF.b = 0x%x, ubf.n = 0x%x\n", sizeof(ubf), ubf.BF.a, ubf.BF.b, ubf.n);
}
//--------------------------------------------联合体(共用体) 定义
typedef union
  {
	//使用位域
  	struct
  	{
	  unsigned b0                 : 1;
	  unsigned b1                 : 1;
	  unsigned b2                 : 1;
	  unsigned b3                 : 1;
	  unsigned b4                 : 1;
	  unsigned b5                 : 1;
	  unsigned b6                 : 1;
	  unsigned b7                 : 1;
  	}bit_type;
  	unsigned char byte;
   }FLAG;
 
FLAG FLAG0;		//结构变量声明
 
//--------------------------------------------结构类型变量位域宏定义
#define flag_0	FLAG0.bit_type.b0 
#define flag_1	FLAG0.bit_type.b1
#define flag_2	FLAG0.bit_type.b2
#define flag_3	FLAG0.bit_type.b3
#define flag_4	FLAG0.bit_type.b4
#define flag_5	FLAG0.bit_type.b5
#define flag_6	FLAG0.bit_type.b6
#define flag_7	FLAG0.bit_type.b7

12. C shell sort(fake shellSort)

说明:在我后来看了知乎上的一篇希尔排序算法之后,我觉得这里的算法,不算希尔排序,我把它称之为结合了希尔算法的选择排序算法。

  • 希尔排序算法原理
    通过指定的步长,做插入排序,直到步长为1为止。
    又名缩小增量排序,是直接插入排序算法的更高效的改进版本,希尔排序是非稳定排序算法。
  • 实现
    方式一:shellSort1
    参考网上资料,不过原文有错,这里已经更正了。希尔排序参考原文

各种排序算法的时间复杂度、空间复杂度以及稳定性总结
在这里插入图片描述

#include<stdio.h>
#include<math.h>
 
#define MAXNUM 6
 
int main()
{
    void shellSort1(int array[], int n);
    int array[MAXNUM], i;

    for(i=0;i<MAXNUM;i++)
        scanf("%d",&array[i]);

    //shell sort algorithm
    shellSort1(array,MAXNUM);

    for(i=0;i<MAXNUM;i++)
        printf("%d ",array[i]);
    printf("\n");
}


void shellSort1(int array[], int n)   //希尔排序 
{
	void swap(int* x, int* y);
	if(array && n>1)
	{
		int i,j,step;
		for(step = n/2; step > 0; step >>= 1)
		{
			printf("Current step value is step = %d\n", step);
			for(i = step; i < n; i += step)
			for(j = i; j > 0; j -= step)
			{
				printf("the i = %d, j = %d\n", i, j);
				if(array[j] < array[j - step])
				swap(&array[j], &array[j - step]);
			}
		}
	}
}

void swap(int *a, int *b)
{
	int temp = 0;
	temp = *a;
	*a = *b;
	*b = temp;
}

方式二:shellSort2
经过自己优化,时间复杂度明显优于方式一。

#include<stdio.h>
#include<math.h>
 
#define MAXNUM 6
 
int main()
{
    void shellSort(int array[], int n);
    int array[MAXNUM], i;

    for(i=0;i<MAXNUM;i++)
        scanf("%d",&array[i]);

    //shell sort algorithm
    shellSort(array,MAXNUM);

    for(i=0;i<MAXNUM;i++)
        printf("%d ",array[i]);
    printf("\n");
}

void shellSort(int array[], int n)
{
	void swap(int *x, int *y);

	//通过这两个循环对方式一做了优化
	for (int step = MAXNUM/2; step > 0; step--)
	{
		printf("Current step value: step = %d\n", step);
		for (int i = 0; i+step < MAXNUM; i++)
		{
			printf("The %dth times to loop\n", i);
			if (array[i+step] < array[i])
				swap(&array[i], &array[i+step]);
		}
	}
}

void swap(int *a, int *b)
{
	int temp = 0;
	temp = *a;
	*a = *b;
	*b = temp;
}

13. C Bubble Sort && Select Sort

冒泡排序和选择排序的类比学习

  • 冒泡排序算法
    冒泡排序思想就是小的数据往上浮,大的数据往下沉,分为内外两层循环,外循环为比较趟数,内层循环为每一趟需要比较的次数。
#include<stdio.h>
#define ARRAY_LENGTH 6

void bubbleSort(int array[], int n)
{
	int i, j;
	int temp = 0;
	for (i=0; i<n; i++)
	{
		for (j=0; j<n-1-i; j++)  // important: j < n -1 - i
		{
			if (array[j+1] < array[j])
			{
				temp       = array[j];
				array[j]   = array[j+1];
				array[j+1] = temp;
			}
		}
	}
}

int main()
{
	int array[ARRAY_LENGTH] = {9, 8, 7, 6, 5, 4};
	printf("Original array is:\n");

	for (int i=0; i<ARRAY_LENGTH; i++)
	{
		printf("Original number is: array[%d] = %d\n", i, array[i]);
	}

	bubbleSort(array, ARRAY_LENGTH);

	printf("After bubble sort, the ordered number is:\n");
	for (int j=0; j<ARRAY_LENGTH; j++)
	{
		printf("Ordered number is: array[%d] = %d\n", j, array[j]);
	}
}
  • 选择排序算法
    核心思想
    选择一个元素出来,跟出自己外的所有元素比较,一旦遇到比自己小(升序排列)的数字就做交换。
    在做交换的时候有两种算法
    第一种:
    一旦遇到需要交换的时候,就交换两个数字。
    第二种:
    为了提升运算速度,在需要交换的时候,只是标记较小值得下标。在每一趟比较完之后,才交换最后的数值。

  • 选择排序的代码实现

//Select Sort method_1
void selectSort(int array[], int length)
{
	for (int i=0; i<length; i++)
	{
		for (int j=i+1; j<length; j++)
		{
			if (array[j] < array[i])
				swap(&array[j], &array[i]);
		}
	}
}

//Select Sort method_2
void selectSort2(int* arr, int length)
{
	int minValueIndex;
	for (int i=0; i<length - 1; i++)   //**important : i < length -i**
	{
		minValueIndex = i;
		for (int j=i+1; j<length; j++)
		{
			if (arr[i] > arr[j])
				minValueIndex = j;
		}
		swap(&arr[i], &arr[minValueIndex]);
	}
}

14. C Insertion Sort && Quick Sort

将插入排序和快速排序放在一起讨论,因为两种算法可以类比学习,方便理解记忆。

  • 插入排序
    首先选择一个需要插入(insertionValue)的值,然后将其插入正确的位置。

  • 快速排序
    分两步
    第一步:先分区,分区的思路就是先选择一个轴值(pivotValue), 然后将其插入正确的位置。
    第二步:递归快速排序

  • 时间复杂度
    在最坏的情况下,就是倒序的情况下,时间复杂度为O(n^2)和选择排序一个效率,在比较理想的情况下时间复杂度为O(nlogn).

  • 代码实现
    插入排序和快速排序代码写在一起的。代码如下:

#include<stdio.h>
#include<ASSERT.H>
#define ARRAY_LENGTH 6

void swap(int *x, int* y)
{
	int temp = 0;
	temp = *x;
	*x = *y;
	*y = temp;
}

//类比下插入排序算法
void insertionSort(int* arr, int length)
{
	int i, j;
	int insertionValue;
	for (i=1; i<length; i++)
	{
		insertionValue = arr[i];
		for (j=i; j>0 && arr[j-1]>insertionValue; j--)
		{
			arr[j] = arr[j-1];
		}
		arr[j] = insertionValue;
	}
}

int partition(int* array,int left,int right)
{
	int *pivot = &array[right]; //注意此处指针的使用,如果不要指针试试会出什么错?
	while (left < right)
	{
		while(left < right && array[left] <= *pivot)
		{
			left++;
		}
		while(left < right && array[right] >= *pivot)
		{
			right--;
		}
		
		if (left != right)
		{
			swap(&array[left], &array[right]);
		}
	}
	assert(pivot); //必须用指针
	swap(&array[left], pivot);

	return left;
}

void quickSort(int* array,int left,int right)
{
	assert(array);

	if(left >= right) //表示已经完成一个组
	{
		return;
	}

	//快速排序的第一步就是 分区
	int index = partition(array,left,right); //枢轴的位置
	//真正快排
	quickSort(array,left,index - 1);
	quickSort(array,index + 1,right);
}

int main()
{
	int array[ARRAY_LENGTH] = {9, 8, 7, 6, 5, 4};

	printf("Original array is:\n");
	for (int i=0; i<ARRAY_LENGTH; i++)
	{
		printf("Original number is: array[%d] = %d\n", i, array[i]);
	}

	printf("After Quick Sort, the ordered number is:\n");
	quickSort(array, 0, ARRAY_LENGTH-1);

	for (int j=0; j<ARRAY_LENGTH; j++)
	{
		printf("Ordered number is: array[%d] = %d\n", j, array[j]);
	}
}

15. C ShellInsertSort && BinaryInsertSort

  • 排序算法分三类

  • 选择排序:简单选择,二元选择排序,堆排序

  • 交换排序:冒泡,快排

  • 插入排序:直接插入,希尔插入,二分插入

  • 希尔插入与二分插入排序算法
    希尔插入排序和二分插入排序算法都是在直接插入算法的基础上作的优化。实现方式有异曲同工之处,可以对比学习。

  • 希尔插入排序算法
    希尔插入排序算法,实际上是指定步长排序。直接插入排序可以看成是希尔插入排序的一个特例,即直接插入排序算法的步长为固定值“1”。

  • 希尔插入排序算法的实现

#include <stdio.h>
#include <stdint.h>
#define ARR_LENGTH 10

void ShellInsertSort(int *arr_p, int step)
{
	int i, j;
	int insertionValue;

    //如果这里的step = 1, 就是直接插入排序的特例
	for (i = step; i < ARR_LENGTH; i++)
	{
		//add this to make efficiency
		if (arr_p[i] < arr_p[i - step])
		{
			insertionValue = arr_p[i];
			for (j = i - step; j >= 0 && insertionValue < arr_p[j]; j = j -step)
			{
				arr_p[j + step] = arr_p[j];
			}

			arr_p[j + step] = insertionValue;
		}
	}
}

void ShellSort(int *arr_p, int length)
{
	int step = 0;
	step = length / 2;
	while (step >= 1)
	{
		ShellInsertSort(arr_p, step);
		step = step >> 1;
	}
}

int main()
{
	int array[ARR_LENGTH] = {10, 12, 9, 5, 3, 7, 18, 11, 40, 50};
	printf("Before use Shell Insert Sort\n");
	for (int i = 0; i < ARR_LENGTH; i++)
	{
		printf("array[%d] = %d\n", i, array[i]);
	}

	ShellSort(array, ARR_LENGTH);

	printf("After use Shell Insert Sort\n");
	for (int j = 0; j < ARR_LENGTH; j++)
	{
		printf("array[%d] = %d\n", j, array[j]);
	}
	return 0;
}
  • 二分插入排序算法的实现
    二分插入排序算法在于作插入排序的时候,通过二分法,快速找到插入区间,然后插入操作,以此减少遍历循环的次数。
#include <stdio.h>
#include <stdint.h>
#define ARR_LENGTH 10

void BinaryInsertSort(int *arr_p, int length)
{
	int i, j;
	int insertionValue;
	for (i = 1; i < length; i++)
	{
		insertionValue = arr_p[i];
		int left = 0;
		int right = i - 1;
		int mid = 0;

		while (left <= right)
		{
			mid = (left + right) / 2;
			if (insertionValue < arr_p[mid])
				right = mid - 1;
			else
				left = mid + 1;
		}

		for (j = i - 1; j >= left; j--)
		{
			arr_p[j + 1] = arr_p[j];
		}

		//这里加一个判断,可以减少不必要的交换
		if (left != i)
		{
			arr_p[left] = insertionValue; //arr_p[j + 1] = insertionValue;
		}
	}
}


int main()
{
	int array[ARR_LENGTH] = {10, 12, 9, 5, 3, 7, 18, 11, 40, 50};
	printf("Before use Binary Insert Sort\n");
	for (int i = 0; i < ARR_LENGTH; i++)
	{
		printf("array[%d] = %d\n", i, array[i]);
	}

	BinaryInsertSort(array, ARR_LENGTH);

	printf("After use Binary Insert Sort\n");
	for (int j = 0; j < ARR_LENGTH; j++)
	{
		printf("array[%d] = %d\n", j, array[j]);
	}
	return 0;
}

16. C++/Python Bucket Sort

  • 桶排序算法
  • 核心思想
    将需要排序的数字,放入以这个数字大小为编号的桶中。
  • 算法的优缺点
    时间复杂度低,但是空间复杂度高。
  • C++代码实现
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;

#ifndef ARRAY_LENGTH
#define ARRAY_LENGTH 5
#endif

//bucketLength 一定要大于等于待排数据的最大元素的值,否则vector内存溢出(这个必须是已知的)
void bucketSort(int array[], int bucketLength)
{
	vector<int> vectorArray[bucketLength];  //if no initialization, must use push_back to fill

	//put the value to corresponding bucket
	for (int i=0; i<ARRAY_LENGTH; i++)
	{
		vectorArray[array[i]].push_back(array[i]); //other method: vectorArray[array[i]].push_back(1)//just a flag
	}

	//put the ordered number to array
	int h=0;
	for (int x=0; x<bucketLength; x++)
	{
		for (int y=0; y<vectorArray[x].size(); y++)
		{
			//printf("The vectorArray value is: vectorArray[%d][%d] = %d\n", x, y, vectorArray[x][y]);
			array[h] = vectorArray[x][y];
			h++;

		}
	}
}

int main()
{
	int arr[ARRAY_LENGTH] = {29, 15, 27, 9, 18};

	//bucket sort
	//bucketLength 这个值必须大于需要存储的值中的最大值,不然vector会内存溢出
	bucketSort(arr, 30);

	for (int j=0; j<ARRAY_LENGTH; j++)
	{
		printf("After Bucket Sort, the ordered number is arr[%d] = %d\n", j, arr[j]);
	}

}
  • 运行结果:
After Bucket Sort, the ordered number is arr[0] = 9
After Bucket Sort, the ordered number is arr[1] = 15
After Bucket Sort, the ordered number is arr[2] = 18
After Bucket Sort, the ordered number is arr[3] = 27
After Bucket Sort, the ordered number is arr[4] = 29
[Finished in 1.9s]
  • Python 代码实现
  • Note
    在有重复数据的时候,如果需要一并输出重复的数据的时候,代码中的实现细节。
def bucketSort(source_list):
	bucket_list = [0 for i in range(100)]
	dest_list = []
	for item in source_list:
		bucket_list[item] = 1 if bucket_list[item] == 0 else bucket_list[item] + 1
	for item_idx, item_value in enumerate(bucket_list):
		if item_value != 0:
			for reproduced_num in range(item_value):
				dest_list.append(item_idx)
	return dest_list

original_data_list = [90, 80, 80, 70, 70, 60, 50, 40, 30]
order_data_list = bucketSort(original_data_list)
print(order_data_list)
  • 运行结果
[30, 40, 50, 60, 70, 70, 80, 80, 90]
[Finished in 0.2s]

17. C generic

  • C中的泛型
    同一个函数可以处理不同的数据类型,这种方法就是泛型方法。

  • 实现方式

  1. 使用void来实现
  2. 使用宏定义来实现
  • 使用void来实现
#include <stdio.h>
#include <stdint.h>
#include <string.h>

//使用strcpy函数时候,需要指定拷贝的字节数
void swap(void *x, void *y, const uint16_t n_byte)
{
    char temp[n_byte];
    strcpy(temp, (char *)x);
    strcpy((char *)x, (char *)y);
    strcpy((char *)y, temp);
}

int main()
{
    //整数交换
    uint16_t value1 = 10;
    uint16_t value2 = 20;
    printf("before swap: value1 = %d, value2 = %d\n", value1, value2);

    swap((void *)&value1, (void *)&value2, sizeof(uint16_t)); //also -> swap(&value1, &value2, sizeof(uint16_t))
    printf("after swap: value1 = %d, value2 = %d\n", value1, value2);

    return 0;
}
  • 使用宏定义来实现泛型
    使用宏定义来定义不同数据类型的数组
#include <stdio.h>
#include <stdint.h>
#include <string.h>


#define CREATE_ARRAY(ARRAY_NAME, ELE_TYPE, N_ELE) \
    static ELE_TYPE ARRAY_NAME[N_ELE]


int main()
{
    //创建整型数组
    CREATE_ARRAY(arrayInt, int, 10);
    printf("arrayInt buff size = %d\n", sizeof(arrayInt)); //buff size = 10*4

    //创建char数组
    CREATE_ARRAY(arrayChar, char, 10);
    printf("arrayChar buff size = %d\n", sizeof(arrayChar)); //buff size = 10*1
    return 0;
}

18. bit manipulation

  • 位操作
    在嵌入式系统中,经常需要操作寄存器的某一个bit位,可以通过"|=" 和 “&=~” 来设置/清除指定的bit位。
  • 代码示例
    如果想操作第3个bit位,则可以通过宏,指定到第3个bit位,代码如下。
#include <stdio.h>

#define BIT3 0x01 << 3

int main()
{
	int val_1 = 0;
	int val_2 = val_1;
	
	val_1 |= BIT3;
	val_2 &=~BIT3;
	printf("The value of the val_1 = 0x%x, val_2 = 0x%x\n", val_1, val_2);
}

19. memcpy func

  • 内存拷贝函数
    C语言中经常会遇到拷贝字符串的场景,这个时候就要用到memcpy函数。
  • 知识点
    内存拷贝的时候,注意判断内存覆盖的场景,当buffer有覆盖的时候,可以从高地址往低地址方向拷贝。
  • 代码示例
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>


void * memcpy(void * des, const void * src, size_t count)
{
	assert(des != NULL && src != NULL);

	void* retVal = des;

	if (des <= src || des >= (src + count))
	{
		/*
		 *non-overlapping buffers
		 *copy from lower address to higher address
		 */
		while (count--)
		{
			*(char *)des++ = *(char *)src++;
		}
	}
	else
	{
		/*
		 *over-lapping buffers
		 *copy from higher address to lower address
		 */

		des = des + count - 1;
		src = src + count - 1;
		while (count--)
		{
			*(char *)des-- = *(char *)src--;
		}
	}
	return retVal;
}


int main()
{
	char str1[20] = "goodGoodStudy";
	memcpy((str1+2), str1, 3);

	printf("string str1 = %s\n", str1);
}

20. LOG_ERR

通过可变参数定义自己的log_err函数。

  • 代码示例
#include <stdio.h>
#include <stdint.h>

#define LOG_ERR(fmt, ...) do{\
	printf("[ERROR]  " fmt "  [line:%d] [%s]\n", __VA_ARGS__, __LINE__, __FUNCTION__);\
}while(0);

#define LOG_WARN(fmt, ...) do{\
	printf("[WARNING]  " fmt "  [line:%d] [%s]\n", ##__VA_ARGS__, __LINE__, __FUNCTION__);\
}while(0); 

int main()
{
	int a = 10;
	int b = 10;

	LOG_ERR("buf is NULL!  a = %u, b = %u", a, b);
	return 0;
}

21. C print chinese

C语言默认是不支持中文字符的,如果要识别中文字符,需要引用头文件#include <locale.h>
注意:c++默认情况是支持中文字符的

下边代码是,去除中文字符中多余的NA
C Code

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

int main()
{
	setlocale(LC_ALL, "chs");

	wchar_t strArr[20] = {L"好好NA学习,天天NA向上"};

	wchar_t des[20];
	memset(des, 0, sizeof(des));

	for (int i = 0, counter = 0; i < 20; ++i)
	{
		if (strArr[i] == 'N' || strArr[i] == 'A')
		{
			continue;
		}

		des[counter++] = strArr[i];
	}
	wprintf(L"the result:\n%s\n", des);
	return 0;
}

C++ code

#include <cstdio>
#include <cstring>
using namespace std;

int main()
{
	char strArr[40] = {"好好NA学习,天天NA向上"};
	char des[40];
	memset(des, 0, sizeof(des));

	for (int i = 0, counter = 0; i < 40; ++i)
	{
		if (strArr[i] == 'N' || strArr[i] == 'A')
		{
			continue;
		}

		des[counter++] = strArr[i];
	}
	printf("the result:\n%s\n", des);
	return 0;
}

22. C autoGen one txt table

在工作中有时候会有这样的需求:
一个算法需要用到一张表,但是这张表又很大,手动一个一个输入的话,效率非常低下,所以就需要用到自动生成一张表(这里的表就是C中的数组)。

今天用C实现如何生成一张表输出保存到txt文件中。
输出保存到文件用fopen这个函数。头文件为stdio.h

  • 代码示例
    C实现:
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>

uint32_t fill2ReValue(uint32_t val)
{
    uint32_t retVal = 0;

    switch(val)
    {
        case 0:  //00
            retVal = 204;
            break;
        case 1: //01
            retVal = 192;
            break;
        case 2: //10
            retVal = 12;
            break;
        case 3: //11
            retVal = 0;
            break;
        default:
            retVal = 255;
    }

    return retVal;
}

int main()
{
    char fileName[300];
    uint32_t byte0Val = 0;
    uint32_t byte1Val = 0;
    uint32_t byte2Val = 0;
    uint32_t byte3Val = 0;
    uint32_t byte4Val = 0;
    uint32_t byte5Val = 0;

    uint32_t temp0;
    uint32_t temp1;
    uint32_t temp2;
    uint32_t temp3;
    uint32_t temp4;
    uint32_t temp5;

    //open file
    FILE* fileOpen_p = fopen("C:\\Users\\xueping.guo\\Desktop\\pdschChCodeTabMap.txt", "w");

    if (NULL != fileOpen_p)
    {
        fprintf(fileOpen_p, "{\n");

        for (uint32_t idx = 0; idx < 4096; ++idx)
        {
            uint32_t reverseVal = 0;

            //reverse the 12bit number
            if (0U == idx)
            {
                reverseVal = idx;
            }
            else
            {
                reverseVal |= (((idx >> 0) & 0x01) << 11) | (((idx >> 1) & 0x01) << 10) | (((idx >> 2) & 0x01) << 9) | (((idx >> 3) & 0x01) << 8) | (((idx >> 4) & 0x01) << 7) | (((idx >> 5) & 0x01) << 6) | \
                 (((idx >> 6) & 0x01) << 5) | (((idx >> 7) & 0x01) << 4) | (((idx >> 8) & 0x01) << 3) | (((idx >> 9) & 0x01) << 2) | (((idx >> 10) & 0x01) << 1) | (((idx >> 11) & 0x01));
            }

            temp0 = (reverseVal >> 10) & 0x03;
            byte0Val = fill2ReValue(temp0);

            temp1 = (reverseVal >> 8) & 0x03;
            byte1Val = fill2ReValue(temp1);

            temp2 = (reverseVal >> 6) & 0x3;
            byte2Val = fill2ReValue(temp2);

            temp3 = (reverseVal >> 4) & 0x3;
            byte3Val = fill2ReValue(temp3);

            temp4 = (reverseVal >> 2) & 0x3;
            byte4Val = fill2ReValue(temp4);

            temp5 = reverseVal & 0x3;
            byte5Val = fill2ReValue(temp5);
            //printf("temp0 = %u, temp1 = %u, temp2 = %u, temp3 = %u, temp4 = %u, temp5 = %u\n", temp0, temp1, temp2, temp3, temp4, temp5);

            //printf("reverseVal = %u\n", reverseVal);
            fprintf(fileOpen_p, "  {0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x},\n", byte0Val, byte1Val, byte2Val, byte3Val, byte4Val, byte5Val, 0, 0);
        }

        fprintf(fileOpen_p, "};\n");
    }
    else
    {
        printf("Open file ERROR: please double check the file path\n");

        //throw an exception
        assert(1 == 2);
    }

    //close file
    fclose(fileOpen_p);

    //sprintf(fileName, "C:\\Users\\xueping.guo\\Desktop\\testResult\\log.txt\n");
    printf("SUCCESS!!!");
    return 0;
}

Python 实现

import os

def genPdschChCodeTabMap():
    byte0Val = 0
    byte1Val = 0
    byte2Val = 0
    byte3Val = 0
    byte4Val = 0
    byte5Val = 0
    byte6Val = 0
    byte7Val = 0

    with open("C:\\Users\\xueping.guo\\Desktop\\guo.txt", "w", encoding='utf-8') as file:
        file.write("{\n")
        for i in range(4096):
            reverseVal = reverseBinary(i)
            temp0 = (reverseVal >> 10) & 0x3
            byte0Val = fill2ReVal(temp0)

            temp1 = (reverseVal >> 8) & 0x3
            byte1Val = fill2ReVal(temp1)

            temp2 = (reverseVal >> 6) & 0x3
            byte2Val = fill2ReVal(temp2)

            temp3 = (reverseVal >> 4) & 0x3
            byte3Val = fill2ReVal(temp3)

            temp4 = (reverseVal >> 2) & 0x3
            byte4Val = fill2ReVal(temp4)

            temp5 = (reverseVal >> 0) & 0x3
            byte5Val = fill2ReVal(temp5)

            file.write("{}, {}, {}, {}, {}, {}, {}, {}\n".format(byte0Val, byte1Val, byte2Val, byte3Val, byte4Val, byte5Val, byte6Val, byte7Val))
        file.write("};\n")
        file.close

def reverseBinary(inputVal):
    outputVal = 0
    outputVal = (((inputVal >> 0) & 0x01) << 11) | (((inputVal >> 1) & 0x01) << 10) | (((inputVal >> 2) & 0x01) << 9) | (((inputVal >> 3) & 0x01) << 8) | (((inputVal >> 4) & 0x01) << 7) | (((inputVal >> 5) & 0x01) << 6) | \
                 (((inputVal >> 6) & 0x01) << 5) | (((inputVal >> 7) & 0x01) << 4) | (((inputVal >> 8) & 0x01) << 3) | (((inputVal >> 9) & 0x01) << 2) | (((inputVal >> 10) & 0x01) << 1) | (((inputVal >> 11) & 0x01))
    return outputVal

def fill2ReVal(inputVal):
    retVal = 0
    if (0 == inputVal):
        retVal = hex(0xcc)
    elif (1 == inputVal):
        retVal = hex(0xc0)
    elif (2 == inputVal):
        retVal = hex(0xc)
    elif (3 == inputVal):
        retVal = hex(0)
    return retVal
        

if __name__ == "__main__":
    genPdschChCodeTabMap()

23. typedef enumerate func

自定义枚举类函数

#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <assert.h>

#define LOG_INFO printf

#define GENERATE_LOG_NUM(NUM) NUM,

#define LOG_VAL(LOG_NUM) \
        LOG_NUM(PDCCH_START) \
        LOG_NUM(PDCCH_END) \
        LOG_NUM(PDSCH_START) \
        LOG_NUM(PDSCH_END)

typedef enum
{
    LOG_START = 10,
    LOG_VAL(GENERATE_LOG_NUM)
    LOG_END

}DEBUG_LOG_E;


int main(uint32_t argc, char** argv)
{
    int fileName[30] = {1, 0};
    uint8_t testVal = (uint8_t)PDCCH_START;

    LOG_INFO("the num is %u\n", testVal);
    return 0;
}

24. float convert to unsigned long

浮点数据与整型数据之间的转化,巧妙之处是使用联合体

#include <stdio.h>
#include <stdint.h>
#include <fstream>
#include <string.h>

typedef char (*pArr)[100];
typedef union
{
   float fx;
   unsigned long ix;

}Data;

int FastLog2(int x)
{
    Data data;
    unsigned long exp;
 
    data.fx = (float)x;

   printf("dbgGuo: data.ix: %llu\n", data.ix);    

    exp = (data.ix >> 23) & 0xFF;
 
    return exp - 127;
}

int main()
{
   int8_t expVal = FastLog2(8);
   printf("dbgGuo: expVal: %d\n", expVal);
   return 0;
}

25. 代码找错

下面这段代码有什么问题 (功能是想找出数组array中的最大值) (3个严重问题)

uint32_t findMaxNum(int32_t* pAarray, uint32_t size)
{
	uint16_t i=0;
uint32_t maxValue=0;

for(i=0; i<size; i++)
{
	maxValue = *pAarray++ > maxValue ? *pAarray++ : maxValue;
}

return maxValue;
}

解析:
这段代码存在以下三个严重问题:

逻辑错误:在比较最大值时,代码使用了两次指针自增操作 (*pAarray++),这将导致跳过数组中的元素。正确的做法是只使用一次指针自增操作,以确保比较的是相邻的元素。

初始最大值设置问题:代码将最大值初始化为0,这可能导致找不到正确的最大值。如果数组中的所有元素都是负数,则0不会是最大值。应该将初始最大值设为数组的第一个元素。

数据类型不匹配:函数声明中使用了 uint32_t 类型作为返回值和 uint32_t 类型作为最大值变量类型,但是在代码中使用了 uint16_t 类型作为循环变量和比较的类型。应该将循环变量和最大值变量类型统一。

24. 获取文件夹下所有文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
VOID getFiles(char *basePath, char fileList[][NR_PHY_LOG_FILE_NAME_MAX_CHARACTER>>1], UINT8* numCnt)
{
    DIR *dir;
    struct dirent *ptr;
    CHAR base[100];

    if ((dir = opendir(basePath)) == NULL)
    {
        return;
    }

    while ((ptr = readdir(dir)) != NULL)
    {
        if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0)
        {
            continue;

        } else if (ptr->d_type == 8)
        {
            if ((*numCnt) > NR_PHY_TRACE_FILE_HIST_MAX_NUM)
            {
                break;
            }
            sprintf(fileList[(*numCnt)++], "%s", ptr->d_name);
        } else if (ptr->d_type == 4)
        {
            memset(base, '\0', sizeof(base));
            strcpy(base, basePath);
            strcat(base, "/");
            strcat(base, ptr->d_name);
            getFiles(base, fileList, numCnt);
        }
    }
    closedir(dir);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值