zoukankan      html  css  js  c++  java
  • C和C++语言学习总结

    知识结构:
    1、if,for,switch,goto
    2、#define,const
    3、文件拷贝的代码,动态生成内存,复合表达式,strcpy,memcpy,sizeof
    4、函数参数传递,内存分配方式,内存错误表现,malloc与new区别
    5、类重载、隐藏与覆盖区别,extern问题,函数参数的缺省值问题,宏代码与内联函数区别
    6、构造和析构的次序,String函数定义
    具体实现:
    1、if,for,switch,goto
    if:
    bool int float pointer char 变量的使用方法
    bool  bParam;
    int  iParam;
    float fParam;
    int*  pParam;
    char  cParam;
    if(bParam) ,if(!bParam);
    if(iParam == 0 ),if(iParam != 0 );
    if(fParam>= -0.00001 && fParam <= 0.00001);
    if(pParam == NULL),if(pParam != NULL);
    if(cParam == '\0'),if(cParam != '\0');
    if/else/return 的使用方法
    if(condition)  可以等价为  return (condition?x:y);
    {
    return x;
    }
    else
    {
    return y;
    }
    for:
    执行效率问题:
    int row,col,sum;
    int a[100][5];
    for(row=0;row <100;row++)  效率低于  for(col=0;col <5;col++)
    {  {
    for(col=0;col <5;col++)  for(row=0;row <100;row++)
    {  {
    sum = sum+a[row][col];  sum = sum+a[row][col];
    }  }
    }  }
    int i;
    for(i=0;i <N;i++)  效率低于  if(condition)
    {  {
    if(condition)  for(i=0;i <N;i++) 
    DoSomething();  DoSomething();
    else  }
    DoOtherthing();  else
    }  {
    for(i=0;i <N;i++) 
    DoOtherthing();
    }
    for (int x=0;x <=N-1;x++)  直观性差于  for (int x=0;x <N;x++)
    switch:
    switch(variable)
    {
    case value1: ...
    break;
    case value2: ...
    break;
    default:  ...
    break;
    }
    switch(c)中的c的数据类型可以是int,char,long,unsigned int,bool.
    variable必须是整数或者强制为整数,由于char实际上是ASCII码,所以也可以.
    c不可以是double,float,char*.
    goto:
    goto主要用于
    {...
    {...
    {....
    goto error;
    }
    }
    }
    error:
    ...
    2、#define,const
    #define和const区别
    1、#define C语言
    const  C语言 C++语言
    const常量有数据类型,编译器会进行类型安全检查,而#define没有数据类型,
    const的常量可以进行调试,但宏常量不能进行调试.
    2、const的使用方法
    在全局定义 const float PI=3.1415926
    在类中定义
    class A
    {...
    A(int size);
    const int SIZE;
    };
    A::A(int size):SIZE(size)
    {
    ...
    }
    对参数和函数的定义(const只能修饰输入参数,不能修饰输出参数)
    const int x=1;  表示x的值是1,在程序中不能改变;
    const int* x;  表示x代表的地址所指向的内容是不能改变得;
    int const* x;  与const int* x;的表示的意思一样;
    int * const x;  表示x代表的地址是不能改变的;
    当是输入参数时,不需要是void Func(const int i),void Func(const int& i),可以是void Func(int i)
    因为输入参数采用"值传递"(const int i),由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加const修饰;
    不用const int& i的原因在于内部数据类型的参数不存在构造、析构的过程,而复制也非常快,"值传递"和"引用传递"的效率几乎相当.
    当是输入参数时,不需要是void Func(const A a),void Func(A a),可以是void Func(A& a)或void Func(const A& a)
    不用const A a,A a的原因是函数的效率比较低,因为函数体内将产生A类型的临时对象用于复制参数a,而临时对象的构造、复制和析构过程都需要消耗时间
    最好用const A&a的原因是A&a中的a可以被改变,A&a和const A&a的好处在于都不会产生临时对象,效率高;
    const A Func(const A&a )const的好处
    第一个const表示返回的是个内部产生的对象,它不能被修改
    const A Func(...)
    {...}
    const A a=Func(...);//不能是A a=Func(...);
    第二个const表示输入的参数是引用传递,函数内部不会产生临时对象,而且这个对象不能被内部修改
    第三个const表示此函数内部的所涉及的数据成员不能修改
    class Stack
    {
    int m_num;
    int GetCount(void) const;
    int Pop(void);
    }
    int Stack::GetCount(void) const
    {
    m_num++;//编译错误,企图修改数据成员m_num;
    Pop();//编译错误,企图调用非const函数
    }
    3、文件拷贝的代码
    #include <stdio.h>
    int main(int argc, char* argv[])
    {
    printf("Hello World!\n");
    FILE* in;
    FILE* out;
    in=fopen("d:\\1.txt","rb");
    out=fopen("d:\\2.txt","wb");
    char ch=fgetc(in);
    while(!feof(in))
    {
    fputc(ch,out);
    ch=fgetc(in);
    }
    fclose(in);
    fclose(out);
    return 0;
    }
    动态生成内存的代码
    ------------------------------------------
    正确代码:
    void GetMemory(char **p, int num)
    {
    *p = (char *)malloc(sizeof(char) * num);
    }
    char* GetMemory2(int num)
    {
    char* p = (char *)malloc(sizeof(char) * num);
    return p;
    }
    ------------------------------------------
    错误的代码:
    void GetMemory3(char *p, int num)
    {
    p = (char *)malloc(sizeof(char) * num);
    }
    ------------------------------------------
    void Test(void)
    {
    char *str = NULL;
    GetMemory(&str, 100); // 注意参数是&str,而不是str
    strcpy(str, "hello");
    cout < < str < < endl;
    free(str);
    str=NULL;
    str=GetMemory2(100);
    strcpy(str, "hello");
    cout < < str < < endl;
    free(str);
    str=NULL;
    GetMemory3(str, 100); // str 仍然为NULL
    strcpy(str, "hello"); // 运行错误
    cout < < str < < endl;//运行错误
    free(str);//运行错误
    }
    strcpy代码
    char* strcpy(char* strDest,const char* strSrc)
    {
    if(strDest==NULL||strSrc==NULL) return NULL;
    char* pStr=strDest;
    while((*strDest++=*strSrc++)!='\0)
    NULL;
    return pStr; 
    }
    复合表达式
    d = (a = b + c) + r ;
    该表达式既求a 值又求d 值.应该拆分为两个独立的语句:
    a = b + c;
    d = a + r;
    if (a < b < c) // a < b < c 是数学表达式而不是程序表达式
    并不表示
    if ((a <b) && (b <c))
    而是成了令人费解的
    if ( (a <b) <c )
    memcpy代码
    void* memcpy(char* strDest,const char* strSrc,size_t size)
    {
    if(strDest==NULL||strSrc==NULL) return NULL;
    if(size <=0) return NULL; 
    char* pStr=strDest;
    while(size-->0)
    *strDest++=*strSrc++;
    return pStr; 
    }
    sizeof:
    i.在32位操作系统中,基本数据类型
    类型  字节长度
    char  1
    short  2
    short  int  2
    signed short  2
    unsigned short  2
    int  4
    long  int  4
    signed  int  4
    unsigned int(unsigned)  4
    long  4
    unsigned long  4
    float  4
    double  8
    void*  4 (所有指针类型长度都一样)(char*,int*,float*,double*)
    enum  4
    ii.在32位操作系统中,定义或函数中的大小
    char a[]="hello";
    char b[100];
    char *p=a;
    类型  字节长度
    sizeof(a)  6
    sizeof(b)  100
    sizeof(p)  4
    void Func(char a[100])
    {
    sizeof(a);  //4
    }
    #pragma pack(1)
    struct A
    {
    int i;
    char j;
    };
    sizeof(A)  //5
    #pragma pack(1)
    struct A
    {
    int o;
    int j;
    union
    {
    int i[10],j,k;
    };
    };
    sizeof(A)  //48
    #pragma pack(1)
    struct A
    {
    enum  day{monring,  moon,  aftermoon}; 
    };
    sizeof(A)  //1
    sizeof(A::day)  //4

    4、函数参数传递
    C++语言中,函数的参数和返回值的传递方式有三种:值传递、指针传递和引用传递.
    "值传递"的示例程序.由于Func1 函数体内的x 是外部变量n 的一份拷贝,
    改变x 的值不会影响n, 所以n 的值仍然是0.
    void Func1(int x)
    {
    x = x + 10;
    }

    int n = 0;
    Func1(n);
    cout < < "n = " < < n < < endl; // n = 0
    "指针传递"的示例程序.由于Func2 函数体内的x 是指向外部变量n 的指
    针,改变该指针的内容将导致n 的值改变,所以n 的值成为10.
    void Func2(int *x)
    {
    (* x) = (* x) + 10;
    }

    int n = 0;
    Func2(&n);
    cout < < "n = " < < n < < endl; // n = 10
    "引用传递"的示例程序.由于Func3 函数体内的x 是外部变量n 的引用,x
    和n 是同一个东西,改变x 等于改变n,所以n 的值成为10.
    void Func3(int &x)
    {
    x = x + 10;
    }

    int n = 0;
    Func3(n);
    cout < < "n = " < < n < < endl; // n = 10
    内存分配方式
    分配方式  变量类型  分配特点
    静态存储区域分配  全局变量,static 变量  内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.
    栈分配  函数内局部变量  栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限.
    堆分配(亦称动态内存分配)  new ,malloc分配  用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存.
    内存错误 
    内存分配未成功,却使用了它. 
    内存分配虽然成功,但是尚未初始化就引用它. 
    内存分配成功并且已经初始化,但操作越过了内存的边界.  例如在使用数组时经常发生下标"多1"或者"少1"的操作.特别是在for 循环语句中,循环次数很容易搞错,导致数组操作越界.
    忘记了释放内存,造成内存泄露.
    放了内存却继续使用它.
    函数的return 语句写错了,注意不要返回指向"栈内存"的"指针"或者"引用",因为该内存在函数体结束时被自动销毁.
    程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面.
    使用free 或delete 释放了内存后,没有将指针设置为NULL.导致产生"野指针".
    malloc与new区别
    malloc 与free 是C++/C 语言的标准库函数,new/delete 是C++的运算符.它们都可用于申请动态内存和释放内存.
    对于非内部数据类型的对象而言,光用maloc/free 无法满足动态对象的要求.对象在创建的同时要自动执行构造函数, 对象在消亡之前要自动执行析构函数.由于malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free.因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete.注意new/delete 不是库函数.
    5、类重载、隐藏与覆盖区别
    成员函数被重载的特征:
    (1)相同的范围(在同一个类中);
    (2)函数名字相同;
    (3)参数不同;
    (4)virtual 关键字可有可无.
    覆盖是指派生类函数覆盖基类函数,特征是:
    (1)不同的范围(分别位于派生类与基类);
    (2)函数名字相同;
    (3)参数相同;
    (4)基类函数必须有virtual 关键字.
    #include <iostream.h>
    class Base
    {
    public:
    void f(int x)  { cout < < "Base::f(int) " < < x < < endl; }
    void f(float x) { cout < < "Base::f(float) " < < x < < endl; }
    virtual void g(void)  { cout < < "Base::g(void)" < < endl;} 
    void h(float x) { cout < < "Base::h(float) " < < x < < endl;}
    void k(float x) { cout < < "Base::k(float) " < < x < < endl;}
    };
    class Derived : public Base
    {
    public:
    virtual void g(void)  { cout < < "Derived::g(void)" < < endl;}
    void h(int x)  { cout < < "Derived::h(int) " < < x < < endl; }
    void k(float x) { cout < < "Derived::k(float) " < < x < < endl;}
    };
    void main(void)
    {
    Derived d;
    Base*pb = &d;
    Derived *pd = &d;
    pb->f(42);  // Base::f(int) 42  //重载
    pb->f(3.14f); // Base::f(float) 3.14  //重载
    pb->g();  // Derived::g(void)  //覆盖
    pd->g();  // Derived::g(void)  //覆盖
    pb->h(3.14f)  // Base::h(float) 3.14  //隐藏
    pd->h(3.14f)  // Derived::h(int) 3  //隐藏
    pb->k(3.14f)  // Base::k(float) 3.14  //隐藏
    pd->k(3.14f)  // Derived::k(float) 3.14  //隐藏 
    }
    extern问题
    如果C++程序要调用已经被编译后的C 函数,该怎么办?
    假设某个C 函数的声明如下:
    void foo(int x, int y);
    该函数被C 编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字用来支持函数重载和类型安全连接.由于编译后的名字不同,C++程序不能直接调用C 函数.C++提供了一个C 连接交换指定符号extern"C"来解决这个问题.例如:
    extern "C"
    {
    void foo(int x, int y);
    … // 其它函数
    }
    或者写成
    extern "C"
    {
    #include "myheader.h"
    … // 其它C 头文件
    }
    这就告诉C++编译译器,函数foo 是个C 连接,应该到库中找名字_foo 而不是找_foo_int_int.C++编译器开发商已经对C 标准库的头文件作了extern"C"处理,所以我们可以用#include 直接引用这些头文件.
    函数参数的缺省值问题
    正确方法:
    void Foo(int x=0, int y=0); // 正确,缺省值出现在函数的声明中
    void Foo(int x,int y)
    {
    ...
    }
    错误方法:
    void Foo(int x=0, int y=0)  // 错误,缺省值出现在函数的定义体中
    {
    ...
    }
    正确方法:
    void Foo(int x, int y=0, int z=0);
    错误方法:
    void Foo(int x=0, int y, int z=0);
    宏代码与内联函数区别
    语言支持关系:
    C  宏代码
    C++ 宏代码 内联函数
    宏代码本身不是函数,但使用起来象函数.预处理器用复制宏代码的方式代替函数调用,省去了参数压栈、生成汇编语言的CALL调用、返回参数、执行return 等过程,从而提高了速度.使用宏代码最大的缺点是容易出错,预处理器在复制宏代码时常常产生意想不到的边际效应.
    对于任何内联函数,编译器在符号表里放入函数的声明(包括名字、参数类型、返回值类型).如果编译器没有发现内联函数存在错误,那么该函数的代码也被放入符号表里.在调用一个内联函数时,编译器首先检查调用是否正确(进行类型安全检查,或者进行自动类型转换,当然对所有的函数都一样).如果正确,内联函数的代码就会直接替换函数调用,于是省去了函数调用的开销.这个过程与预处理有显著的不同,因为预处理器不能进行类型安全检查,或者进行自动类型转换.假如内联函数是成员函数,对象的地址(this)会被放在合适的地方,这也是预处理器办不到的.
    内联函数使用方法:
    关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用.
    正确使用方法:
    void Foo(int x, int y);
    inline void Foo(int x, int y) // inline 与函数定义体放在一起
    {

    }
    错误使用方法:
    inline void Foo(int x, int y); // inline 仅与函数声明放在一起
    void Foo(int x, int y)
    {

    }
    6、构造和析构的次序
    构造从类层次的最根处开始,在每一层中,首先调用基类的构造函数,然后调用成员对象的构造函数.析构则严格按照与构造相反的次序执行,该次序是唯一的,否则编译器将无法自动执行析构过程.
    String函数定义
    class String
    {
    public:
    String(const char *str = NULL); // 普通构造函数
    String(const String &other); // 拷贝构造函数
    ~ String(void); // 析构函数
    String & operate =(const String &other); // 赋值函数
    private:
    char *m_data; // 用于保存字符串
    };
    // String 的析构函数
    String::~String(void)
    {
    delete [] m_data;// 由于m_data 是内部数据类型,也可以写成delete m_data;
    }
    // String 的普通构造函数
    String::String(const char *str)
    {
    if(str==NULL)
    {
    m_data = new char[1]; // 若能加NULL 判断则更好
    *m_data = '\0';
    }
    else
    {
    int length = strlen(str);
    m_data = new char[length+1]; // 若能加NULL 判断则更好
    strcpy(m_data, str);
    }
    }
    // 拷贝构造函数
    String::String(const String &other)
    {
    int length = strlen(other.m_data);
    m_data = new char[length+1]; // 若能加NULL 判断则更好
    strcpy(m_data, other.m_data);
    }
    // 赋值函数
    String & String::operate =(const String &other)
    {
    // (1) 检查自赋值
    if(this == &other)
    return *this;
    // (2) 释放原有的内存资源
    delete [] m_data;
    // (3)分配新的内存资源,并复制内容
    int length = strlen(other.m_data);
    m_data = new char[length+1]; // 若能加NULL 判断则更好
    strcpy(m_data, other.m_data);
    // (4)返回本对象的引用
    return *this;
    }

  • 相关阅读:
    flume sink两种类型 file_rool 自定义sing com.mycomm.MySink even if there is only one event, the event has to be sent in an array
    为什么引入进程20年后,又引入线程?
    As of Flume 1.4.0, Avro is the default RPC protocol.
    Google Protocol Buffer 的使用和原理
    Log4j 2
    统一日志 统一订单
    网站行为跟踪 Website Activity Tracking Log Aggregation 日志聚合 In comparison to log-centric systems like Scribe or Flume
    Percolator
    友盟吴磊:移动大数据平台的架构、实践与数据增值
    Twitter的RPC框架Finagle简介
  • 原文地址:https://www.cnblogs.com/helife/p/1909961.html
Copyright © 2011-2022 走看看