已剪辑自: https://mp.weixin.qq.com/s/vvdvVMVmx3i_6eXjUUYfBQ

本文汇总了50条C语言奇技淫巧,希望能对大家有所帮助。

01. 宏定义用do{}while(0)

如果定义的宏函数后面有多条语句,使用这样的方式会有问题:

 #define FUNC()  func1(); func2()if(bRunF)FUNC();

展开宏定义后会变成:

 if(bRunF)func1();func2();

逻辑就不对了。可以用这一的方式解决,非常好用:

 #define FUNC()  do{func1(); func2();}while(0)
02. 数组的初始化

假如给arr的第2~6元素初始化为5,也许你会

 int arr[10] = {0, 5, 5, 5, 5, 5, 0, 0, 0, 0};

现在告诉你C99可以这样:

 int arr[10] = {[1... 5] = 5};
03. 数组的访问

你想取数组的第6个元素(下标为5),教科书教你这样做:

 int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};int n1 = arr[5];int n2 = *(arr+5);

其实你可以:

 int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};int n = 5[arr];

也不会有错,实际上arr[5]对应*(arr+5),而5[arr]对应*(5+arr),没多大区别。

04. 结构体的初始化

结构体的初始化,传统的做法是:

 typedef struct{int a;int x;int y;int z;char b;short c;}S;S s = {100, 0, 0, 0, 'A', 0x12);

对于C99,其实你可以:

 typedef struct{int a;int x;int y;int z;char b;short c;}S;S s = {.a = 100, .b = 'A', .c = 0x12};
05. 用include的方式初始化大数组
 double array[SIZE][SIZE] = {#include "float_values.txt"}
06. Debug时输出文件名、函数名、行号等
 #define DEBUG_INFO() fprintf(stderr,"[DEBUG]%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
07. C语言有-->“趋向于…”操作符?
 int main(void){int n = 10; while(n --> 0 ) // n goes to 0{ printf("%d ", n);}printf("\n");}

实际上C语言没有这个-->操作符,是-->的组合而已

         while( n--  >  0 )
08. 获得任意类型数组的元素数目
 #define NUM_OF(arr) (sizeof (arr) / sizeof (*arr))
09. 判断运行环境的大小端

Linux有以下代码:

     static union { char c[4]; unsigned long l; } endian_test = { { 'l', '?', '?', 'b' } };#define ENDIANNESS ((char)endian_test.l)printf("ENDIANNESS: %c\n", ENDIANNESS);
10. 编译时做条件检查

Linux Kernel有以下代码

 /* Force a compilation error if condition is true */#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

例如,在某些平台为了防止内存对齐问题,检查一个结构体或者一个数组的大小是否为8的倍数。

 BUILD_BUG_ON((sizeof(struct mystruct) % 8) != 0);

除了这个,还有

 #define BUILD_BUG_ON_ZERO(e)  (sizeof(struct{int : -!!(e);}))#define BUILD_BUG_ON_NULL(e)  ((void*)sizeof(struct{int : -!!(e);}))#define BUILD_BUG_ON(condition)  ((void)BUILD_BUG_ON_ZERO(condition))#define MAYBE_BUILD_BUG_ON(condition)  ((void)sizeof(char[1 - 2 * !!(condition)]))
11. 用异或运算实现数据交换

交换俩变量数据,一般做法是:

 // 方法1temp = a;a = b;b = temp;// 方法2a=a+b;b=a-b;a=a-b;

方法1需要第三个变量,方法二存在数据溢出可能,可以尝试下以下方法:

a = a ^ b;
b = a ^ b;
a = a ^ b;
12. 判断语句中把const数值放在前面

通常条件语句写成

if(n == 0){ /*...*/ }

但是,有可能手误写成

if(n = 0){ /*...*/ }

这种错误只有机器在运行时候知道,而人不一定能发现这种bug。把数值放在前面就不怕了,==写成=,编译器就知道

if(0 == n){ /*...*/ }
13. 用冒号表达式替代if...else...语句

这个用法应该很普遍了,不算什么特别的技巧了。

 if(y < 0){x = 10;}else{x = 20;}

可以改成以下一行代码即可

 x = (y < 0) ? 10 : 20;
14. 判断一个整数是否为2的幂

也许你会不断地将这个数除以2,除到底,然而Linux kernel有个巧妙的办法:

 #define is_power_of_2(n) ((n) != 0 && ((n) & ((n) - 1)) == 0)

((n) & ((n) - 1)) == 0这个不理解?那先想想2的X次方的值的二进制是怎样的。

15. 静态链表

直接看代码

     struct mylist {int a;struct mylist* next;};#define cons(x, y) (struct mylist[]){{x, y}}struct mylist *list = cons(1, cons(2, cons(3, NULL)));struct mylist *p = list;while(p != 0) {printf("%d\n", p->a);p = p -> next;};
16. 柔性数组
#include <stdlib.h>
#include <string.h>struct line
{int length;char contents[0];
};
struct line *thisline = (struct line *) malloc (sizeof (struct line) + this_length);
thisline->length = this_length;struct f1 { int x; int y[]; } f1 = { 1, { 2, 3, 4 } };
struct f2 { struct f1 f1; int data[3]; } f2 = { { 1 }, { 2, 3, 4 } };

详见6.18 Arrays of Length Zero

17. 数组之间直接赋值
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int b[10] = {0};
b = a;

这样是非法的,但是你可以放数组穿个马甲:

typedef struct
{int n[10];
}S;
S a = {{0,1,2,3,4,5,6,7,8,9}};
S b = {0};
b = a;
18. #include的不一定是要.h文件

#include后面跟的可以是任意后缀的,但文件内容一定要是合法的。例如

#include "test.fxxk"
19. 自动获取变量类型
#define var(left, right) __typeof__(right) left = (right)var(s, 1LL); // 相当于 long long s = 1LL;

是不是有点像C++ 11的auto类型?

20. 宏定义函数MIN(x,y)的终极做法
#define MIN(x, y)   x < y? x : y    // 这样给0分#define MIN(x, y)   (x < y? x : y)  // 这样给50分
// 不信你试试这个
int n = 3 * MIN(3, 4 < 5 ? 4 : 5);#define MIN(x, y)   ((x) < (y)? (x) : (y))  // 这个给90分
// 不信你试试这个
double xx = 1.0;
double yy = MIN(xx++, 1.5);
printf("xx=%f, yy=%f\n",xx,yy);// 以下放大招了,看看GNU的
#define MIN(A,B)    ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __a : __b; })
double xx = 1.0;
double yy = MIN(xx++, 1.5);
printf("xx=%f, yy=%f\n",xx,yy);

也许你知道用__LINE__可以输出行号,然而你试下这个:

 #line 12345 "abcdefg.xxxxx"    printf("%s line: %d\n", __FILE__, __LINE__);    printf("%s line: %d\n", __FILE__, __LINE__);

不单止行号被改了,文件名也被改了,是不是我们可以用这个干点啥……想想?

22. C和C++代码混合编译

在C的头文件上面

#ifdef __cplusplus
extern "C" {
#endif

然后再头文件下面

#ifdef __cplusplus
}
#endif
23. 用查表法实现hex2str

直接上代码

void hex2str(const unsigned char* hex, int size, char* str)
{char char_arr[17] = "0123456789ABCDEF";for(int i = 0; i < size; i++){str[3*i] = char_arr[hex[i]>>4];str[3*i+1] = char_arr[hex[i]&0x0F];str[3*i+2] = ' ';}
}
24. 用sprintf实现hex2str

直接上代码

void hex2str(const unsigned char* hex, int size, char* str)
{for(int i = 0; i < size; i++){sprintf(&str[3*i], "%02X ", hex[i]);}
}
25. 将变量名变字符串

如果想打印一个变量名和它的值,也许会这样:

unsigned int program_flag = 0xAABBCCDD;
printf("program_flag: 0x%08X\n", program_flag);

对于你有很多这样的变量要打印,建议你做个宏函数:

#define PRINT_HEX_VAR(var)  printf("%s: 0x%08X\n", #var, var);
unsigned int program_flag = 0xAABBCCDD;
PRINT_HEX_VAR(program_flag);
26. 获取结构体元素的偏移
#define offsetof(type, member) ( (size_t)&((type*)0->menber) )typedef struct
{char a;int b;}S;offsetof(S, b);
27. 根据结构体成员获取结构体变量指针
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
/*** container_of - cast a member of a structure out to the containing structure* @ptr:        the pointer to the member.* @type:       the type of the container struct this is embedded in.* @member:     the name of the member within the struct.**/
#define container_of(ptr, type, member) ({                      \const typeof( ((type *)0)->member ) *__mptr = (ptr);    \ (type *)( (char *)__mptr - offsetof(type,member) );})

这个怎么玩?看看链表:

 struct list_head {struct list_head *next;struct list_head  *prev;};struct ipstore{unsigned long time;__u32 addr[4];struct list_head list;};container_of(ist1->list, struct ipstore, list)scanf(“%[^,]”, a); // This doesn’t scrap the commascanf(“%[^,],”,a); // This one scraps the commascanf(“%[^\n]\n”, a); // It will read until you meet  '\n', then trashes the '\n'scanf(“%*s %s”, last_name); // last_name is a variable

这是啥意思,正则表达式先了解下?然后自己试试,理解会更深入。

29. 两个数相加可以不用+号?
 int Add(int x, int y){if (y == 0)return x;elsereturn Add( x ^ y, (x & y) << 1);}
30. 调试的时候打印数组

你是不是曾经为打印数组而烦恼,每次都要将元素一个个取出来?

#define ARR_SIZE(arr)               (sizeof(arr)/sizeof(*arr))
#define PRINT_DIGIT_ARR(arr)    do{\printf("%s: ", #arr); \for(int i=0; i < ARR_SIZE(arr); i++) \printf("%d ", arr[i]);\printf("\n");\}while(0)int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
PRINT_DIGIT_ARR(arr);
31. 感受下这个0x5F3759DF
float Q_rsqrt( float number )
{long i;float x2, y;const float threehalfs = 1.5F;x2 = number * 0.5F;y  = number;i  = * ( long * ) &y;                       // evil floating point bit level hackingi  = 0x5f3759df - ( i >> 1 );               // what the fuck?y  = * ( float * ) &i;y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration//      y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removedreturn y;
}
32. switch-case的特殊玩法

直接看代码:

void send(uint8* to, uint8 from, uint16 count)
{uint16 n = (count + 7) / 8; switch (count % 8) { case 0: do { *to = *from++; case 7: *to = *from++; case 6: *to = *from++; case 5: *to = *from++; case 4: *to = *from++; case 3: *to = *from++; case 2: *to = *from++; case 1: *to = *from++; } while (--n > 0);
}

实际上它是:

void send(uint8* to, uint8 from, uint16 count)
{do { *to = *from++; } while (--count > 0);
}

使用最上面的switch-case的形式大大提高了运行效率。理解不了?汇编看看。还是理解不了?那就网上自行搜索“Duff’s Device”。

33. 防止头文件重复包含导致问题

这个用法很常见了,而且非常有用。

// xxx.h
#ifndef _XXX_H_
#define _XXX_H_//  Header file contents...#endif

当然,如果你的编译器支持的话,也可以。

// xxx.h
#pragma once//  Header file contents...

不过,为了更好的兼容性,还是建议你用第一种方法。

34. 2的N次幂ROUNDUP
#define ROUNDUP(a, size) (((a) & ((size)-1)) ? (1+((a) | ((size)-1))) : (a))

其中,size是2的整数次幂,而:

  1. a & (2^n-1)检查a的低位是否有值;
  2. a | (2^n - 1) 将a的低n位赋值为1;
  3. 1 + a | (2^n -1) 为a最近的下一个2^n倍值。
 ROUNDUP(10, 8);     // 结果为16ROUNDUP(10, 16);   // 结果为16ROUNDUP(10, 32);   // 结果为32ROUNDUP(16, 16);   // 结果为16

有什么用?申请内存的时候可以按某字节对齐,减少内存碎片啊!

35. 某整数的ROUNDUP
 #define VAL_ROUNDUP(size, val_size)     (((size)+val_size-1)/val_size*val_size)

这个不是按2的次幂ROUNDUP的,而是按某个整数的倍数ROUNDUP,例如:

 VAL_ROUNDUP(10, 8);     // 结果为16VAL_ROUNDUP(16, 8);   // 结果为16VAL_ROUNDUP(8, 10);   // 结果为10VAL_ROUNDUP(16, 16);   // 结果为16

这个又有什么用?EEPROM或者Flash的page大小对齐的时候就非常有意义。

想想,memcpy函数为什么要用void*

 void *memcpy(void *dest, const void *src, size_t n);

因为,它不关心你传什么类型的指针过来,我void统统都接纳。

无为而无不为。

再看看这个:

 void *p1;int *p2;p1 = p2; // 这个没问题p2 = p1; // 这个是错的

因为“空类型”可以包容“有类型”,而“有类型”则不能包容“空类型”。

所以,适可而止,不要滥用哦!

    typedef struct {}StructNull;sizeof(void);sizeof(StructNull);

正所谓:

空即是色,色即是空。

在C语言上,sizeof(void); 的值为1;而sizeof(StructNull);为0。C++的情况请自行验证,别瞎猜,哈哈哈。

38. 布尔变量的判断

正确的做法:

if(bValue)

以下是瞎搞:

if(bValue == TRUE)

为啥?布尔类型中只有两个值:假和真。请问:假是什么,真又是什么?

假是0,而真是非0。那么非0是什么?-1,1,2,……除了0的一切。

所以再想想以下代码中的两个叹号是否可以去掉?

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

我们知道##是用来连接字符的,看看RTX怎么用,感受一下:

/// Create a Thread Definition with function, priority, and stack requirements.
/// \param         name         name of the thread function.
/// \param         priority     initial priority of the thread function.
/// \param         instances    number of possible thread instances.
/// \param         stacksz      stack size (in bytes) requirements for the thread function.
///       macro body is implementation specific in every CMSIS-RTOS.// define the object
#define osThreadDef(name, priority, instances, stacksz)  \
const osThreadDef_t os_thread_def_##name = \
{ (name), (priority), (instances), (stacksz)  }/// Access a Thread definition.
/// \param         name          name of the thread definition object.
///       macro body is implementation specific in every CMSIS-RTOS.
#define osThread(name)  \
&os_thread_def_##name

代码比较简单,我就不解释了,自行思考下。

40. 传值和传址

看两个例子:

 void swap(int a; int b){int t = 0;t = a;a = b;b = t;}int x = 100;int y = 200;swap(x, y);

请问,这个swap可以交换x, y的值吗?

再看看一个常见的面试题:

 void GetMemory(char *p){p = (char *)malloc(100);}void Test(void){char *str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);}

这个程序能输出“hello world”吗?

此处没有答案,为了加深理解,建议感兴趣的朋友请自行动手验证和思考。

41. 形参到底传值好还是传址好

接着上一条,我们从另一个角度看。函数定义一个结构体类型形参,传值好还是传址好?

 void func1(struct tStructType param){}void func2(struct tStructType* param){}

实际上两种方式都行,但你要明白形参实际上就是一个临时变量,不管传值还是传址都有一个复制给临时变量的过程。这个仿真汇编看看就知道了。很明显,如果tStructType这个类型占用空间很大,那么肯定用tStructType*比较合算。

42. bit翻转的几个方法

bit翻转是从MSB->LSB到LSB->MSB, 所有的Bit都必须反转。例如:

1010 0001 => 1000 0101

a. 运算实现32位bit翻转

 unsigned intreverse(register unsigned int x){x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));return((x >> 16) | (x << 16));}

b. 查表法bit翻转

 static const unsigned char BitReverseTable256[] = {0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF};unsigned int v; // reverse 32-bit value, 8 bits at timeunsigned int c; // c will get v reversed// Option 1:c = (BitReverseTable256[v & 0xff] << 24) | (BitReverseTable256[(v >> 8) & 0xff] << 16) | (BitReverseTable256[(v >> 16) & 0xff] << 8) |(BitReverseTable256[(v >> 24) & 0xff]);// Option 2:unsigned char * p = (unsigned char *) &v;unsigned char * q = (unsigned char *) &c;q[3] = BitReverseTable256[p[0]]; q[2] = BitReverseTable256[p[1]]; q[1] = BitReverseTable256[p[2]]; q[0] = BitReverseTable256[p[3]];
43. BOOL判断

面试题:如何判断一个bool变量如果你写成if(b_flag == TRUE)可能会给你0分。为什么?因为非假即真,假是0,即非0即真。可以写成if(b_flag)或者if(!b_flag)如果是函数呢?例如:

 int flag = 0;BOOL is_flag_true(void){return flag;}

这样可以吗?也许可以,也许不可以。如果BOOL是一个unsigned char怎么办?那就这样的:

 BOOL is_flag_true(void){return !!flag;}
44. goto的使用

看到goto,先别慌,也忍着别吵。我们不推荐使用goto,但goto确实有它的妙用。不详细解释了,看看以下例子代码感受下吧!

 int func(void){int* p1 = (int*) malloc (100*4);if(NULL == p1) goto free1;int* p2 = (int*) malloc (200*4);if(NULL == p2) goto free2;int* p3 = (int*) malloc (300*4);if(NULL == p3) goto free3;return 0; // return to systemfree3:free (p2);free2:free (p1);free1:return -1 ;}
45. 类型定义

这个有点老套了,但是很有用。

 typedef uint8 unsigned char;typedef uint16 unsigned short;typedef uint32 unsigned int;

uint8等来定义变量比unsigned char这样的好多了,方便平台移植,特别是不用位数的单片机,这个很重要。

46. 输出预编译信息

当你想输出预编译过程中的某些信息,可以用#pragma message("message contents")

47. 输出指针地址

当你想输出指针地址的时候,往往想到的是:

 int *p = &n;printf("p: %X",(unsigned int)p);

但你还可以:

 int *p = &n;printf("p: %p",p);
48. 数组元素赋值
 uint8 data1[8] = {1,2,3,4,5,6,7,8};uint8 data2[8];memcpy(data2, data1, 8);// ordata2[0] = data1[0];data2[1] = data1[1];data2[2] = data1[2];data2[3] = data1[3];data2[4] = data1[4];data2[5] = data1[5];data2[6] = data1[6];data2[7] = data1[7];

你也可以:

 typedef union{uint64 nData;uint8 cData[8];}uData;uData data1, data2;data2.nData = data1.nData;

还有第三种办法,详见“17. 数组之间直接赋值”顺便思考下并验证以下方式是否可行?(想知道答案一定要亲自试试啊,别说我坑你。)

 uint8 data1[8] = {1,2,3,4,5,6,7,8};uint8 data2[8];*(uint64*) data2 = *(uint64*) data1;
49. likely()unlikely

Linux内核中有两个这样的东西:likely()unlikely

 #define likely(x) __builtin_expect(!!(x), 1)#define unlikely(x) __builtin_expect(!!(x), 0)

我们可以根据高概率发生的情况放在if分支,低概率的放在else分支,以提高程序运行效率。

 if(likely(XXX)){/*...*/}else{/*...*/}

或者:

 if(unlikely(XXX)){/*...*/}else{/*...*/}
50. 解放if/elseswitch/case

对于多分支的程序设计,很多人通常会这样做:

 if(XXX_VAL_1 == nVal){/*...*/}else if(XXX_VAL_2 == nVal){/*...*/}else if(XXX_VAL_3 == nVal){/*...*/}// ...

或者:

 switch(nVal){case XXX_VAL_1:/*...*/break;case XXX_VAL_2:/*...*/break;case XXX_VAL_3:/*...*/break;// ...}

几个分支还好,如果有几十个呢?尝试下这个:

 typedef void (pFunc*)(void);typedef struct{uint32 val;pFunc func;}tValFunc;tValFunc valfunc_tb[] = {{XXX_VAL_1, func1},{XXX_VAL_2, func2},{XXX_VAL_3, func3},// ...};for(int i = 0; i < sizeof(valfunc_tb)/sizeof(tValFunc); i++){if(valfunc_tb[i].val == nVal && valfunc_tb[i].func != NULL){valfunc_tb[i].func();}}

在这立个flag,后续还有要用MACRO写个比这更好的查表法!

50条C语言奇技淫巧,精品干货!相关推荐

  1. [灌水]某大侠手机存储的精品短信50条 (爆笑)

    [灌水]某大侠手机存储的精品短信50条 (爆笑) 1.老夫妇去拍照,摄影师问:"大爷,您是要侧光,逆光,还是全光?",大爷腼腆的说:"我是无所谓,能不能给你大妈留条裤衩? ...

  2. 编程语言发展70年,用50种不同语言输出「Hello World」

    「免费学习 60+ 节公开课,投票页面,点击讲师头像」 作者 | Sylvain Saurel 译者 | 风车云马 责编 | 屠敏 [导读]历经 70 年,不断出现的编程语言为开发者解决了哪些难题?其 ...

  3. 计算机学院校园文化标语,校园文化建设标语50条

    当一个人开始从自己内心开始奋斗,他就是个有经验的人.下面是学习啦的小编为你们整理的内容,希望你们能够喜欢 校园文化建设标语50条 1.有一分耕耘,就有一分收获. 2.找方法才能成功,找借口只有失败. ...

  4. 50条大牛C++编程开发学习建议

    每个从事C++开发的朋友相信都能给后来者一些建议,但是真正为此进行大致总结的很少.本文就给出了网上流传的对C++编程开发学习的50条建议,总结的还是相当不错的,编程学习者(不仅限于C++学习者)如果真 ...

  5. [转]学习c++的50条忠告

    学习c++的50条忠告(初学者必看)转自http://www.rayoko.com/article/101.htm 1.把C++当成一门新的语言学习(和C没啥关系!真的.): 2.看<Think ...

  6. 读 S. Meyers 之 《Effective STL 中文版:50条有效使用 STL 的经验》

    S. Meyers, 潘爱民, 陈铭, 邹开红. Effective STL 中文版:50条有效使用 STL 的经验. ISBN: 978-7-121-20125-7 STL (Standard Te ...

  7. 大牛C++编程开发学习建议50条

    每个从事C++开发的朋友相信都能给后来者一些建议,但是真正为此进行大致总结的很少.本文就给出了网上流传的对C++编程开发学习的50条建议,总结的还是相当不错的,编程学习者(不仅限于C++学习者)如果真 ...

  8. 小学生计算机管理员寄语,小学生家长寄语50条

    寄语是一个汉语词汇,意为所传的话语,有时也指寄托希望的话语.以下是"小学生家长寄语",希望给大家带来帮助! 家长寄语怎么写 1.这次考试成绩有长进,希望你不要骄傲,继续努力,争取有 ...

  9. c++容器使用50条总结

    第1章 容器 第1条:慎重选择容器类型. 标准STL序列容器:vector.string.deque和list. 标准STL关联容器:set.multiset.map和multimap. 非标准序列容 ...

最新文章

  1. Datawindow.net 子数据窗口出错
  2. qemu-kvm部分流程/源代码分析
  3. angularjs ngTable -Custom filter template-calendar
  4. 厉害的壁纸,亲测有效
  5. python人脸识别环境搭建_人脸识别:Windows10系统环境搭建
  6. WPR-007:WPF中窗体的透明设置
  7. python合并excel工作簿_使用Python将多个excel的多个sheet页合并到一个excel
  8. 滴滴技术总监受贿 1000 万,列入招聘黑名单,互联网大厂反腐有多强?
  9. 多选框勾选 和 后台数据处理
  10. 重装的电脑360打补丁都是智能忽略
  11. python图表制作方法_python图表制作
  12. matlab语法归纳
  13. 新浪微博平台架构(转)
  14. 极好的六个开源数据挖掘工具
  15. matlab1到100求和for_一个简单的MATLAB程序(1到100求和)
  16. ipad iphone开发_如何在iPhone或iPad上使用Adobe Flash
  17. HDU6578——blank 动态规划
  18. netdev_features_t和ip_summed说明
  19. 长江中下游先民最早驯化野生稻 国稻种芯:全球35亿人口主食
  20. Kubernetes dashboard搭建

热门文章

  1. DPDK网卡驱动流程总结
  2. Lazada选品推荐,这些爆品成了东南亚开年大赢家
  3. 459基于python的汽车维修零配件查询系统
  4. android mms流播放器
  5. 下载和阅读Android源码
  6. ghostwin7系统后只有一个盘了其它分区的资料怎么寻回
  7. 提升效率的tmux初始化脚本
  8. 华西证券:AI领强算力时代,GPU启新场景落地
  9. 计算机运行速度慢怎样解决方法,电脑运行速度慢的解决方法:瞬间加快电脑运行速度妙招...
  10. 学生成绩管理系统(软件工程大设计)