C经典笔记

C语言博大精深,很多看似简单的却暗含杀机

如果你感到你的C语言学的差不多了,那说明你的C一无所知:

下面就看过的C做一些总结,文中都是以图片的形式给出,也花费了我很多宝贵的时间

之所以用图片就是为了迫使大家自己在编译器上敲一遍代码

由于编译器和系统的差异,可能结果有点不一样,而且很多都没有解释,自己看,如有问题,下面评论留言::

<本文出自www.lfsblack.com>

 

0,

 

 

1,

 

2,

 

3,

4,

 

5,

 

6,

 

7,

 

8,

 

9,

 

10,

 

11,

 

12,

 

13,

 

14,

 

15,

 

16,

 

 

22,

23,

 

24,

 

25,

 

26,

 

27,

 

28,

 

29,

 

30,

 

31,

 

32,

 

33,

 

34,

 

35,

 

36,

 

37,

 

38,

 

39,

 

40,

 

41,

 

42,

 

43,

 

44,

 

45,

 

46,

 

47,

 

48,

 

49,

 

50,

 

51,

 

52,

 

53,

 

54,

55,

 

56,

 

57,

 

58,

 

59,

 

60,

 

61,

 

62,

 

63,

 

64,

65,

 

66,

 

67,

 

68,

 

69,

 

70,

 

71,

 

72,

 

73,

 

74,

 

75,

 

76,

 

77,

 

78,

 

79,在字符串中找出连续最长的数字串,返回长度,最长数字串放在outputstr

 

80,

 

81,

 

82,

windows下的结果:

 

83,

但是这个地方和系统和编译器有很大关系:在windows下结果如下:我们姑且这样认为(linux下默认4字节对齐)

 

84,

windows下的结果:

 

85,

windows下结果:

 

86,

windows下的结果:

87,

windows下结果:

88,

 

89,

 

90,

 

91,

 

92,

 

93,

 

94,

 

95,

 

96,

 

97,

 

98,

C++程序中调用被C编译器编译后的函数,为什么要加extern "C"?

  C++语言支持重载,C不支持。函数被C++编译后在库中的名字与C的不同。

  C++提供了C链接交换指定符号extern "C"解决名字匹配问题

 

99,

头文件ifndef/define/endif有什么作用?

  防止该头文件被重复引用

 

100,

编程去掉代码中的注释:

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

void remove_comment(char *buf,size_t size) {
   char *p,*end,c;
   char *sq_start,*dq_start;
   char *lc_start,*bc_start;
   size_t len;
   p = buf;
   end = p + size;
   sq_start = dq_start = lc_start = bc_start = NULL;

   while(p < end) {
      c = *p;
      switch(c) {
      case '\'':
         if(dq_start || lc_start || bc_start) {
            p ++;
            continue;
         }
         if(sq_start == NULL)
            sq_start =  p ++;
         else {
            len = p ++ - sq_start;
            if(len == 2 && *(sq_start+1) == '\\') {
               continue;
             }
            sq_start = NULL;
         }
         break;
      case '\"':
         if(sq_start || lc_start || bc_start ) {
            p ++ ;
            continue;
         }
         if(sq_start == NULL)
            dq_start = p ++;
         else {
            if(*(p ++ -1) == '\\') 
               continue;
            dq_start = NULL;
         }
         break;
      case '/':
         if(sq_start || dq_start || lc_start || bc_start) {
            p ++;
            continue;
         }
         c = *(p+1);
         if(c == '/') {
            lc_start = p;
            p += 2;
         }else if(c == '*') {
            bc_start = p ;
            p += 2;
         } else
            p ++;
         break;
      case '*':
         if(sq_start || dq_start || lc_start || bc_start == NULL) {
              p ++;
              continue;
         }
         if(*(p+1)  != '/') {
            p ++;
            continue;
         }
         p += 2;
         memset(bc_start, ' ',p - bc_start);
         bc_start = NULL;
         break;
      case '\n':
         if(lc_start == NULL) {
            p ++;
            continue;
         }
         c = *(p-1);
         memset(lc_start,' ',(c == '\r' ? (p ++ -1) : p++) - lc_start);
         lc_start = NULL;
         break;
      default:
         p ++;
         break;
      }
   }
   if(lc_start) 
      memset(lc_start,' ' ,p - lc_start);
  }

int main(int argc, char *argv[]) {
   int fd,n;
   char buf[102400];
   fd = open("1.txt",O_RDONLY,0);
   if(fd == -1)
      return -1;
   n = read(fd,buf,sizeof(buf));
   if( n == -1 || n == 0) {
      close(fd);
      return -1;
   }
   remove_comment(buf,n);
   *(buf + n) = '\0';
   printf(buf);
   close(fd);
   return 0;
}

测试文件1.txt:

 

测试结果:

 

101,

用一个宏,求一个结构体里某个变量相对于struct的偏移量

  #define FIND(struc,e) (size_t)((struct *)0)->e)

102,

用预处理定义一个常数,用以表明1年中有多少秒

    要考虑有可能溢出,因此用UL 

   #define SECOND_PER_YEAE    (60*60 * 24 * 365)UL

103,

用宏返回两个数中较小的一个

  #define MIN(A,B)   ((A) <= (B) ? (A) : (B))

104,

const在C中有什么用途?

  1,可以定义const常量

  2,const可以修饰函数的参数和返回值,甚至函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性

105,

const和#define区别?

  const常量有数据类型,宏没有。编译器可以对前者进行 类型安全检查,而后者只能进行字符替换,并且替换中还有可能发生意想不到的错误

  有些集成化的调试工具对const常量进行调试,但是不能对宏常量进行调试。在C++中const完全取代了宏常量

106,

  常量引进在早期的C++版本,当时标准C规范正在制定。那时,常量被看做一个好的思想而被包含在C中。但是,C中的const的意思是“一个不能被改变的普通变量”。在C中,它总占用

内存,而且名字的全局符。C编译器不能把const看成一个编译期间的常量。在C中如果写:

 

但是可以这样写: const bufsize;

而这种写法在C++中是不允许的。C编译器则把它作为一个声明,这个声明指明在别的地方内存分配。因为C默认const是外部连接的,C++默认const是内部连接的,这样,如果C++

中想完成与C中同样的事,必须用extern把内部连接改成外部连接:

      extern const buffer;

107,

 

108,

 

109,

 

 

110,

 

111,

#include <iostream>
using namespace std;

class A1 {
public:
   int a;
   static int b;
   A1();
   ~A1();
};


class A2 {
public:
   int a;
   char c;
   A2();
   ~A2();
};
class A3 {
public:
   float a;
   char c;
   A3();
   ~A3();
};
class A4 {
public:
   float a;
   int b;
   char c;
   A4();
   ~A4();
};
class A5 {
public:
   double d;
   float a;
   int b;
   char c;
   A5();
   ~A5();
};

void main() {
   cout << sizeof(A1) << endl << sizeof(A2) << endl << sizeof(A3) 
    << endl << sizeof(A4) << endl << sizeof(A5) << endl;
}

 

112,

sizeof和strlen的区别?

1>sizeof操作符的结果类型是size_t,它在头文件中的typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小

2>sizeof是运算符,strlen是函数

3>sizeof可用类型做参数,strlen只能用char *做参数,且必须是以'\0'结尾,sizeof还可以用函数做参数

4>数组作为sizeof参数不退化,传递给strlen就退化为指针

5>大部分编译程序编译的时候就把sizeof计算过了,是类型或是变量的长度。这就是sizeof(x)可以用来定义数组的尾数原因

  

6>strlen的结果要在运行的时候才能计算出来,用来计算字符串的长度,而不是类型占内存的大小

7>sizeof后如果是类型必须加括号,如果是变量名可以不加括号。这是因为sizeof是个操作符而不是个函数

8>当使用一个结构类型或变量时,sizeof返回实际的大小。当使用一静态的空间数组时,sizeof返回全部数组的尺寸。sizeof操作符不能返回动态

分配的数组或外部的数组的尺寸

9>数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址

10>sizeof操作符不能用于函数类型、不完全类型或字段。不完全类型指具有未知存储大小数据的数据类型,如:未知存储大小的数组类型,未知内容的结构或联合类型,void类型

 

113,

sizeof的使用场合:

1>sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信

2>用它可以看看某种类型的对象在内存中所占的单元字节

3>在动态分配一个对象时,可以让系统知道分配多少内存

4>便于一些类型的扩充,在windows中有很多结构类型就有一个专用的字段用来存放该类型的字节大小

5>由于操作数的字节数在实现时可能会出现变化,在涉及操作数字节大小时也用sizeof代替常量计算

6>如果操作数是函数中的数组形参或函数类型的参数,sizeof给出其指针的大小

 

114,

 

115,

 

 

116,

 

117,

 

118,

 

119,

 

120,

 

 

121,

交换:

#include <iostream>
using namespace std;

void swap1(int p,int q) {
   int temp ;
   temp = p;
   p = q;
   q = temp ;
}

void swap2(int *p,int *q) {
   int *temp ;
   *temp = *p;
   *p = *q;
   *q = *temp;
}

void swap3(int *p,int *q) {
   int *temp ;
   temp = p;
   p = q;
   q = temp;
}

void swap4(int *p,int *q) {
   int temp;
   temp = *p;
   *p = *q;
   *q = temp;
}

void swap5(int &p,int &q) {
   int temp;
   temp = p;
   p = q;
   q = temp;
}

int main() {
   int a = 1,b = 2;
   swap1(a,b);
   cout << a << '\t' << b << endl;
  // swap2(&a,&b);  //有错误
  // cout << a << '\t' << b << endl;
   swap3(&a,&b);
   cout << a << '\t' << b << endl;
   swap4(&a,&b);
   cout << a << '\t' << b << endl;
   swap5(a,b);
   cout << a << '\t' << b << endl;

   return 0;
}

结果:只有后两个可以实现

 

122,

上面程序崩溃。因为GetMemory并不能传递动态申请的内存,str一直都是NULL

 

 

123,

 

124,

 

125,

 

 

126,

 

127,

在main函数中可以不写return语句,因为编译器会隐式返回0

删除一个指针后,把它设置为空指针(0)

 

128,

int (*(*f)(int,int))(int)

f是一个函数指针,指向的函数类型是有两个int参数并且返回一个函数指针的函数,返回的函数指向一个int参数且返回int的函数

 

129,

 

130,

 

131,

 

132,

 

133,

 

134,

auto_ptr指针

 

135,

 

 

136,

 

 

137,

 

138,

 

139,

 

140,

 

141,

 

142,

 

143,

 

144,

统计字符串中,各个字符出现的次数:

 

145,

 

146,

C++代码实现,输入n输出nXn矩阵,规定沿45度线递增,形成一个zigzag数组(JPEG编码里取像素数据的排列顺序):

 

147,

两个等长数组A、B,所含元素相同,但顺序不同,只能取A数组某值和B数组某值进行比较,比较结果为大于,小于或等于。但是不能取同一数组两个值进行比较,也不能取得某数组中的某个值。写一个匹配算法(即A数组中某值与B数组中某值等值)

 

148,

标准模板库是一个基于模板的容器类库

容器是包容其他对象的对象

 

149,

从最上面输出结果看,两次调用析构函数

 

150,

C++的空类默认产生4个函数,默认构造函数,析构函数,拷贝构造汉斯,赋值函数

C++中struct和class默认访问权限是唯一区别,可以有构造和析构函数

类静态成员必须初始化赋初值!!!

151,

可见 上面第一个例子之所以错,是因为编译器把Test b();当作一个函数声明了

 

152,

 

153,

从上例子中我们可以看到析构函数可以是内敛的

 

154,

 

155,

封装可以隐藏实现细节,使得代码块化

继承可以扩展已存在的代码模块,目的是为了代码重用

多态是为了实现 接口重用

 

156,

结果:

 

结果:

 

157,

结果:

 

 

158,

 

159,

如果一个圆角矩形有直边和圆角,那么它也就多重继承了圆形和矩形,而圆形和矩形又都是从shape类里继承。问:当创建一个圆角矩形使,共创建多少shape?

答曰:如果圆形类和矩形类都不是virtual继承shape类,那么生成两个shape,一个为圆形类,一个为矩形类。

如果圆形类和矩形类都是virtual继承shape类,那么生成一个共享的shape

 

160,

结果:

 

161,

 

162,

 

163,

虚指针或虚函数指针是带有虚函数的类中,一个对象都有一个虚指针指向该类的虚函数表

C++如果阻止一个类被实例化? 

                                         使用抽象类或者构造函数被声明为private

一般在什么时候构造函数被声明成private?

                                         要阻止编译器生成默认的copy constructor的时候

什么时候编译器会生成默认copy constructor?

                                         只要自己没写,而程序中需要,就会生成

如果已经写了一个构造函数,编译器还会生成copy constructor么?

                                          会

 

164,

虚函数的入口地址和普通函数有什么不同?

每个虚函数都在vtable中占了一个表项,保存着一条跳转到它入口地址的指令(实际上就是保存了它的入口地址)。当一个包含虚函数的对象(不是对象的指针)被创建

的时候,它在头部附加一个指针,指向vtable中相应的位置。调用虚函数的时候,不管你是用什么指针调用的,它先根据vtable找的入口地址再执行,从而实现了“动态联编”

而不像普通函数那样简单的跳转到一个固定的地址

 

165,

 

 

166,

结果:

 

167,

一个C++程序员想要运行一个static_cast<char *>()。为了能够确保合法性。

应该增加函数   operator char*();

 

168,

C++中,typeid运算符的返回值为:type_info常量对象的引用

 

169,

 

170,

 

171,

 

 

172,

 

 

173,

 

 

174,

 

175,

 

176,

 

177,

 

 

178,

 

 

179,

int *ptr;

ptr = (int *)0x67a9;

*ptr = 0xaa55;

 

180,

 

 

181,

 

 

182,

 

 

183,

求补码:(貌似有问题)

unsigned short get(short x )
{
short y ;
y = x >> 15 ;
return ((x^y)-y)|(y<<15);
}

 

184,

 

185,

 

186,

 

187,

全局变量放在                                                                          数据段

函数内部变量static int ncount 放在                                             数据段

函数内部变量char *p = "AAA",p放在                                           堆栈

指向的空间放在                                                                        数据段

函数内变量char *p = new char,p放在                                          堆栈

指向空间放在                                                                           堆

 

188,

 

189,

 

 

190,

 

191,

 

posted @ 2012-10-02 14:42  lfsblack  阅读(670)  评论(0编辑  收藏  举报