C/C++ - 基础篇

  1. qsort 使用:
    // int cmp(const void *a, const void *b):返回正数就是说 cmp 传入参数第一个要放在第二个后面, 负数就是传入参数第一个要放第二个前面, 如果是 0, 那就无所谓谁前谁后。
    
    #include
    
    int cmp(const void *a, const void *b)
    {
         return(*(ElementType *)a>*(ElementType *)b)?1:-1;
    }
    
    ElementType Max( ElementType S[], int N )
    {
        qsort(S,N,sizeof(ElementType),cmp);
        return S[N-1];
    }
  2. (int)a;  int(a);  // 后者只能在C++编译器运行,前者C/C++都支持。
  3. C/C++ 基本数据类型 点击打开链接
  4. C/C++ 语言中,long 固定 32bit,而 int 32 or 16。
  5. unsigned == unsigned int
  6. 正是double它不同于long long的存储方法,使得它虽然只有64位但是可以比同样是64位的long long 类型取值范围大很多。
  7. 一个 long long 占两个 %d,(b/a 结果是 long long):
    ll a=6;
    int b=120;
    printf("%d/%d/%d\n",b/a,1); // 20/0/1
    printf("%lld/%d/%d\n",b/a,1); // 20/1/随机数
  8. string:
    /* string 字符串从 n 开始输出(包括第 n 个) */
    printf("%s\n",s.c_str()+n);
    cout<>s;
    // transform(first, last, result, op);
    transform(s.begin(), s.end(), s.begin(), ::tolower); // 转化小写
    transform(s.begin(), s.end(), s.begin(), ::toupper); // 转化大写
    
    
    /* string 用 scanf 读取 */
    string s;
    s.resize(20); // 需要预先分配空间
    scanf("%s", &s[0]); // 1
    scanf("%s", s.begin()); // 2
    
    
    /* string.find() */
    s.find("."); // 返回 "." 在 s 中的位置,从 0 开始
    
    
    /* string.erase() */
    s.erase(pos, n);      // 删除从pos开始的n个字符,比如erase(0,1)就是删除第一个字符
    s.erase(position);    // 删除position处的一个字符(position是个string类型的迭代器)
    s.erase(first, last); // 删除从first到last之间的字符(first和last都是迭代器)
    
    
    /* string.insert() */
    s.insert(1,".") // 在s[1]处插入一个"."
    
    
    /* 用 string 方式替代 char* + sprintf 妙用 */
    string s(100,0); // 等价于 string s(100,'\0');
    sprintf(const_cast(s.c_str()),"%s%d%s","test ",1,"all");
    // 等价于
    char a[100];
    sprintf(a,"%s%d%s","test ",1,"all");
    
    
    /* string.append(int,char):连续添加 int 个 char */
    s.append(1,'a');
    
    
    /* string.append(string) */
    s.append("ab");
    
    
    /* assign 方法:可以理解为先将原字符串清空,然后赋予新的值作替换 */
    
    // 将字符串或者字符数组作为新内容替换原字串
    s.assign("Go home"); //Go home
    char ch[20] = "go back to shanghai";
    s.assign(ch); //go back to shanghai
    
    // 将 s 的内容从位置 pos 起的 n 个字符作为原字串的新内容赋给原字串
    s.assign("Come on!", 5, 2); //on
    
    // 将字符数组或者字符串的首 n 个字符替换原字符串内容
    s.assign("go back to China", 7); //go back
    
    // 将原字串替换为 n 个字符 c
    char ch = '?';
    s.assign(5, ch); //?????
    
    // 控制台输入:"abcd efg",不包括引号,最后按 Ctrl + Z 结束,会自动去掉空格拼接起来
    s.assign(istream_iterator(cin), istream_iterator()); //abcdefg
  9. char[ ]:
    /*
        crr1==crr2 return 0;
        crr1>crr2  return +;
        crr1

     

  10. heap:
    /* C++中堆的应用:make_heap, pop_heap, push_heap, sort_heap
    
    函数说明: 
    std::make_heap将[start, end)范围进行堆排序,默认使用less, 即最大元素放在第一个。
    
    std::pop_heap将front(即第一个最大元素)移动到end的前部,同时将剩下的元素重新构造成(堆排序)一个新的heap。
    
    std::push_heap对刚插入的(尾部)元素做堆排序。
    
    std::sort_heap将一个堆做排序,最终成为一个有序的系列,可以看到sort_heap时,必须先是一个堆(两个特性:1、最大元素在第一个 2、添加或者删除元素以对数时间),因此必须先做一次make_heap。
    
    make_heap, pop_heap, push_heap, sort_heap 都是标准算法库里的模板函数,用于将存储在 vector/deque 中的元素进行堆操作,对不愿自己写数据结构堆的C++选手来说,这几个算法函数很有用,下面是这几个函数操作 vector 中元素的例子。
    
    */

     

  11. auto: 
    a、使用auto关键字的变量必须有初始值,编译器才能推导出变量类型。 
    b、在传递const变量的时候,使用auto必须自己加const 
    const int a =10; 
    auto b = a;       // b的类型是int 
    const auto c = a; // c 的类型是const int 
    c、关于很奇葩的函数返回值:
    auto add(int a, int b)->int 
    {
         return a + b;
    }
    auto关键字只能在函数的返回值使用auto关键字,并且在函数尾还需要标注返回类型。这样看起来很奇葩,莫不如不用auto关键字,但我认为委员会的人没这么闲,上google查了下,有下面两条原因: 
        i、他们认为把返回值放在函数后面更好看(特别是返回值很长的时候) 。
       ii、C++14将会把讨人烦得返回值去掉,编译器直接支持自推导。
    d、for (auto it : mp) { // it.second 而不是 it->second }
    e、for (auto it : st) { // it 输出元素 而不是 *it }
  12. hypot 函数:
    功能:计算直角三角形的斜边长。
    头文件:
    用法:double hypot(double x, double y);
  13. 两种方式iterator遍历的次数是相同的,但在STL中效率不同,前++--返回引用,后++--返回一个临时对象,因为iterator是类模板,使用it++这种形式要返回一个无用的临时对象,而it++是函数重载,所以编译器无法对其进行优化,所以每遍历一个元素,你就创建并销毁了一个无用的临时对象。
  14. struct:如果在构造一个新的构造函数中参数里带有 string 类型,一定要补上默认的0参数构造函数;如果用 char* 替代 string,那么不需要补默认构造函数。
  15. 多组数据时输入时,while(~scanf("%c>%c",&c1,&c2)) ,没办法 Ctrl+Z;可以用 while(cin>>s)。
  16. 四舍五入保留小数点后 bits 位:
    double round(double num,unsigned int bits)
    {
        stringstream ss;
        ss<>num;
        return num;
    }
  17. 输出小技巧:(较 if...else... 要好)
        printf("%d",a[0]);
        for(i=1;i
  18. if(1){} ~ if(1);
  19. 结构体赋值:
    nds[0]=tnds[0]; // 结构体直接赋值的话,nds[0] 地址不变,数据变
  20. DFS 中临时数组写法,保证每次回溯时,值也跟着恢复上一层的值:
    void dfs(int sum)
    {
        if(sum==all) return;
    
        for(int i=0;i0)
            {
                int vis[len]; mem(vis,0);
                vis[i]=1;
                dfs(sum+1);
                if(vis[i]==1)
                {
                    // do something...
                }
            }
        }
    }
  21. 虽然 if(1) //T,if(2) //T,以及ture==1,false==0 已定死规则了,但是 true!=2,其他类似。
  22. set.rbegin() 与 set.end() 不相等,前者 == 后者 - 1,可以用来判断是否到达最后一个。
  23. int fun(){...}  // 如果最后没有 return 的话,默认返回一个随机值。
  24. 使用 stringstream:可以吞下不同的类型,然后吐出不同的类型。
    int a = 30;
    stringstream ss;
    ss<>s3; 也可以转换 char[] 类型
    ss>>s2;
    cout<
  25. %f 和 %lf 区别:
        printf("%f\n",1L/2);        // 0.000000
        printf("%f\n",1.0/2);       // 0.500000
        printf("%f\n",1.0L/2);      // -0.000000
        printf("%f\n",1.0F/2);      // 0.500000
        printf("%f\n",1F/2);        // 编译错误
        printf("%lf\n",1.0L/2);     // 0.500000
        printf("%lf\n",1L/2);       // 0.500000
        printf("%lf\n",1.0F/2);     // 0.000000
    Ps:printf的%f说明符的确既可以输出float型又可以输出double型。根据“默认参数提升”规则float型会被提升为double型。因此printf()只会看到双精度数。对于scanf,情况就完全不同了,它接受指针,这里没有类似的类型提升。向float存储和向double存储大不一样,因此,scanf区别%f和%lf。      
    也就是说输出的时候不管输出的是双精度还是单精度都用%f就没错了,但是输入的时候,输入单精度要用%f而输入双精度要用%lf。
  26. stringstream ss; 清空:用 “ss.str("")” 配合 “ss.clear()”:(前后顺序无关)
        string s1="10",s2="12";
        int a,b;
        stringstream ss;
    
        ss<>a;
        cout<>b;
        cout<>b;
        cout<
  27. vector:
    /* vec.clear() 与 vector().swap(vec) 区别 */
    vector vec;
    vec.push_back(12);
    vec.clear();
    cout<().swap(vec);
    cout< 比较:元素是否相同,或者按字典序比较 */
    puts(v1 == v2 ? "Yes" : "No");
    
    
    /* vector.resize(n) 申请空间大小,直接可以使用 v[i] */
    vector v;
    v.resize(100);
    v[3]=15;
    
    
    /* find(v.begin(),v.end(),泛型)-v.begin() */
    // 找到则返回第一次出现的下标,若找不到,则返回 v.size()
    
    
    push_back() 时预留空间不够用:要重新分配内存,并且拷贝当前已有的所有元素到新的内存区域。如果已有元素很多,这个操作将变的非常昂贵。
    Ps:ector的内存管理策略是:一旦空间不足,则增长一倍,对于大数据量,这也许是一块不容小朝的资源。
  28. 循环(外 / 内)反复声明变量的优缺点:
    1、对于使用 int 等基本数据类型作为循环变量,只要你用的优化方面足够给力的主流的编译器,完全不需要关心在循环外还是循环内定义循环变量。
    2、如果循环变量本身是复杂的对象,建议在循环外定义好,并且在 for 循环的赋值语句、判断语句中,都要避免重复创建对象。
  29. pair<...> 用法(伪代码):
    typedef pair pii;
    queue q;
    q.push(make_pair(i,j));
    x=q.front().first, y=q.front().second; q.pop();
  30. char[ ] 大小写转换:

    for(int i=0;i='a' && s[i]<='z') s[i]=toupper(s[i]);      // 转大写
        else if(s[i]>='A' && s[i]<='Z') s[i]=tolower(s[i]); // 转小写
    }

     

  31. '\0' (char)-> 0(int)

  32. '空格'(char)-> 32(int)

  33. char 转 string:

    string s;
    cout<<(s+'a')<

     

  34. 优先队列自定义优先级排序:

    // 第 1 种方法
    struct pq_cmp // 根据先到达的人先处理业务
    {
        bool operator()(P p1,P p2)
        {
    	// 它与正常的 sort_cmp 的思想反着来的
            return p1.ssum>p2.ssum; // 进入的时间:从小到大
        }
    
    };
    
    priority_queue,pq_cmp> pq;
    
    
    // 第 2 种方法
    struct node
    {
        char a[20];
        int rk;
        friend bool operator<(node p1,node p2) // 注意写死:friend、< 
        {
            return p1.rk>p2.rk; // 从小到大
        }
    };
    
    priority_queue pq;
  35. scanf 中 %*s 妙用:

    //Robert is a child of John
    
    char a[20],with[20],b[20];
    scanf("%s%*s%*s%s%*s%s",a,with,b);
    
    /*
    a==Robert
    with==child
    b==John
    */

     

  36. unordered_map / map:

  37. /* unordered_map / map 自定义排序 */
    typedef pair psi;
    
    unordered_map ump;
    
    int cmp(psi p1,psi p2)
    {
        if(p1.second==p2.second) return p1.firstp2.second;
    }
    
    vector vec(ump.begin(),ump.end());
    sort(vec.begin(),vec.end(),cmp);
    // Ps:map:红黑树;unordered_map:hash 散列表。
    
    
    /* 泛型里面用 char* 替代 string 以及 map 插入时排序自定义 */
    struct cmp
    {
        bool operator()(const char* s1,const char* s2) const
        {
            return strcmp(s1,s2)<0; // default:map 根据 key 排序(字典序)
        }
    };
    
    map mp;
    
    mp.clear();
    char rr[100],rr1[100];
    rr1[0]=rr[0]='a';
    rr[1]='b';
    rr1[2]=rr[2]='c';
    mp[rr]=10;
    rr1[1]='a';
    mp[rr1]=12;
    
    for(map::iterator it=mp.begin();it!=mp.end();it++)
        cout<first< > mp; // default ~ map mp;
    map > mp;
    
    // 自定义
    struct cmp
    {
        bool operator()(const string& k1, const string& k2)
        {
            return k1.length() < k2.length();
        }
    };
    map mp;
    
    
    /* C++ STL 中 Map 的按 Value 排序 */
    // 待更新...
    
    
    /* erase(it) or erase(key) or erase(mp.begin(),mp.end()) */

    判断字符是否为:字母、大小写英文字母、数字、数字或字母:

  38. cout<

    连续赋值情况:

  39. int a[200],b[200],len=0;
    a[len]=b[len++]=1; // a[1]==b[0]==1
    a[len++]=b[len]=1; // a[0]==b[1]==1

    unordered_set / multiset / hash_set / set:

  40. 1、说到这那到底hash_set与unordered_set哪个更好呢?实际上unordered_set在C++11的时候被引入标准库了,而hash_set并没有,所以建议还是使用unordered_set比较好,这就好比一个是官方认证的,一个是民间流传的。
    
    
    2、set.count():O(logn); unordered_set.count() 比 set.count() 再快 4 倍左右。
    
    
    3、multiset 可插入重复的值,其他用法与 set 类似。
    
    
    /* set - count、insert().second */
    set st;
    int ans=st.count(1); // st 中 1 出现的次数
    bool f=st.insert(1).second; // 先插入试试,最后返回是否插入成功
    
    
    /* set 自定义排序 */
    struct node
    {
        int val,cnt;
        node(int val,int cnt):val(val),cnt(cnt){}
        bool operator<(const node &nd)const
        {
            //return false 数据插入失败,而不是(插入成功,只是位置不一样)。
            return cnt!=nd.cnt ? cnt>nd.cnt : val st;

    在scanf中 “\n” 不是表示接受一个回车符,而是表示忽略所有的空白字符(包括回车、空格、Tab)。所以想要结束输入,输入任意一个非空白字符即可,但是该字符仍然会留在缓冲区中。一般不建议在 scanf 中使用 “\n”。

  41. 双重 for_i 循环的变量情况:

    for(int i=0;i<4;i++)
    {
        for(int i=1;i<3;i++)
            printf("%d\n",i);
    }
    
    /*
    1
    2
    1
    2
    1
    2
    1
    2
    */

     

  42. #define 的妙用:

    #define add(x,y) x+y // 不是计算好后返回,而是先返回好表达式再计算
    
    printf("%d\n",add(1,2*add(3,4))); // 11
    
    
    #define P 3
    #define f(a) P*a*a
    
    printf("%d\n",f(3+5)); // 3*3+5*3+5==29
    
    
    #define ABC(x) x*x
    int a, k=3;
    a = ++ABC(k+1); //9
    // 由于带参宏不会对参数自行添加括号运算,因此a 的计算展开式可写为 ++k+1*k+1 这样就很明显了,由于运算优先级的关系,先执行++k,即k先进行自加,k的值变成了4,然后a=4+1*4+1,结果就为9啦~

     

  43. 输出自动填充:

    cout<

     

  44. 结构体:

    node nd;
    // 等价于
    node nd();

     

  45. 变量计算时的自动转换规则:(例如:int型除以double型,结果是double型)
    自动转换遵循以下规则:
    1) 若参与运算量的类型不同,则先转换成同一类型,然后进行运算。
    2) 转换按数据长度增加的方向进行,以保证精度不降低。如int型和long型运算时,先把int量转成long型后再进行运算。
         a.若两种类型的字节数不同,转换成字节数高的类型
         b.若两种类型的字节数相同,且一种有符号,一种无符号,则转换成无符号类型
    3) 所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算。
    4) char型和short型参与运算时,必须先转换成int型。
    5) 在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换为左边量的类型。如果右边量的数据类型长度左边长时,将丢失一部分数据,这样会降低精度,丢失的部分按四舍五入向前舍入。

  46. 见名知意:

    1、foo(function object oriented):面向对象编程的函数,有时候也不知道取什么名字,就代表“张三、李四”的味道。

     

  47. 指针声明定义语法:

    node *left,*right; // T
    node* left, right; // F

     

  48. int */ double,无需 *1.0,只要有一个是小数即可(在末尾添加“.0”):

    int a=2;
    printf("%f\n",a*1.0/3); // 不推荐
    printf("%f\n",a/3.0);   // 推荐

     

  49. 补空格,%2d:

    printf("%2d\n",1); //空1

     

  50. 容器:

    /* 遍历倒序 */
    for(set::reverse_iterator it=st.rbegin(); it!=st.rend(); it++)
    {
        cout<<*it<

     

  51. C语言优先级
     

    优先级

    运算符

    名称或含义

    使用形式

    结合方向

    说明

    1

    []

    数组下标

    数组名[整型表达式]

    左到右

     

    ()

    圆括号

    (表达式)/函数名(形参表)

     

    .

    成员选择(对象)

    对象.成员名

     

    ->

    成员选择(指针)

    对象指针->成员名

     

    2

    -

    负号运算符

    -算术类型表达式

    右到左

    单目运算符

    (type)

    强制类型转换

    (纯量数据类型)纯量表达式

     

    ++

    自增运算符

    ++纯量类型可修改左值表达式

    单目运算符

    --

    自减运算符

    --纯量类型可修改左值表达式

    单目运算符

    *

    取值运算符

    *指针类型表达式

    单目运算符

    &

    取地址运算符

    &表达式

    单目运算符

    !

    逻辑非运算符

    !纯量类型表达式

    单目运算符

    ~

    按位取反运算符

    ~整型表达式

    单目运算符

    sizeof

    长度运算符

    sizeof 表达式

    sizeof(类型)

     
    3

    /

    表达式/表达式

    左到右

    双目运算符

    *

    表达式*表达式

    双目运算符

    %

    余数(取模)

    整型表达式%整型表达式

    双目运算符

    4

    +

    表达式+表达式

    左到右

    双目运算符

    -

    表达式-表达式

    双目运算符

    5

    <<

    左移

    整型表达式<<整型表达式

    左到右

    双目运算符

    >>

    右移

    整型表达式>>整型表达式

    双目运算符

    6

    >

    大于

    表达式>表达式

    左到右

    双目运算符

    >=

    大于等于

    表达式>=表达式

    双目运算符

    <

    小于

    表达式<表达式

    双目运算符

    <=

    小于等于

    表达式<=表达式

    双目运算符

    7

    ==

    等于

    表达式==表达式

    左到右

    双目运算符

    !=

    不等于

    表达式!= 表达式

    双目运算符

    8

    &

    按位与

    整型表达式&整型表达式

    左到右

    双目运算符

    9

    ^

    按位异或

    整型表达式^整型表达式

    左到右

    双目运算符

    10

    |

    按位或

    整型表达式|整型表达式

    左到右

    双目运算符

    11

    &&

    逻辑与

    表达式&&表达式

    左到右

    双目运算符

    12

    ||

    逻辑或

    表达式||表达式

    左到右

    双目运算符

    13

    ?:

    条件运算符

    表达式1? 表达式2: 表达式3

    右到左

    三目运算符

    14

    =

    赋值运算符

    可修改左值表达式=表达式

    右到左

     

    /=

    除后赋值

    可修改左值表达式/=表达式

     

    *=

    乘后赋值

    可修改左值表达式*=表达式

     

    %=

    取模后赋值

    可修改左值表达式%=表达式

     

    +=

    加后赋值

    可修改左值表达式+=表达式

     

    -=

    减后赋值

    可修改左值表达式-=表达式

     

    <<=

    左移后赋值

    可修改左值表达式<<=表达式

     

    >>=

    右移后赋值

    可修改左值表达式>>=表达式

     

    &=

    按位与后赋值

    可修改左值表达式&=表达式

     

    ^=

    按位异或后赋值

    可修改左值表达式^=表达式

     

    |=

    按位或后赋值

    可修改左值表达式|=表达式

     

    15

    ,

    逗号运算符

    表达式,表达式,…

    左到右

    从左向右顺序结合

  52. printf(i,i++), fun(j,++j); // 在C中,一律都是从右到左;在Java中,一律都是从左到右。

  53. vector.push:如果是对象的push,则属于拷贝,与原先的对象的地址是不一样的。

  54. static 写在函数里作用域等同于写在main函数外面。

    static int a=0;
    
    int main()
    {
        return 0;
    }
    
    等价于
    
    void fun()
    {
        static int a=0;
    }
    
    int main()
    {
        return 0;
    }

     

  55. C++中int类型默认值:
    1. 在全局域中声明的变量会自动初始化为0。
    2. 如果变量是在局部域中定义的,则系统不会向它提供初始值0,这些对象被认为是未初始化,其值随机(有的编译器可能会为你初始化为0,但千万别依赖于这种可能行为,因为它会给你的程序带来未定义的行为)。

  56. 在C语言中,int a = -028; 这里的 0 默认当作 8 进制来看,而不是十进制。

  57. 结构体类似于基本类型,所以传参时,也只是传值

  58. sizeof & strlen 区别:

  59. 默认加“\0”
    C/C++ - 基础篇_第1张图片

  60. 待更新...

你可能感兴趣的:(#,C/C++,#,STL)