c与c++常用函数

常用函数

  • max, min, fill, memset, sort, swap

字符串函数

  • 字符串比较函数strcmp因为原理是两个字符串一个个比较,所以可以比较字符是否相同!!!!!
  • 一般形式:strcmp(字符串1,字符串2)
    • 返回值:
      • 当s1<s2时,返回值<0
      • 当s1=s2时,返回值=0
      • 当s1>s2时,返回值>0
  • 如果把序号按字符串存储,则会可以通过strcmp比较序号是否相同。

    (有用)
  • Strlen函数如果没有遇到’\0’,会一直计算下去,字符串二维数组不可以用strlen,因为二维数组每一行相当于一个字符串一维数组,每一行都有’\0’!
  • c++标准库里字符串相关函数的声明,凡是不修改内容的地方一律声明为const char *, strlen(const char *),strcmp(const char *, const char *),strcpy(char *, const char *)第一个参数会被修改

strcpy函数

  • 原型声明:char *strcpy(char* dest, const char *src);
  • 功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间
  • 说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
  • 返回指向dest的指针。对于出现异常的情况ANSI-C99标准并未定义,故由实现者决定返回值,通常为NULL。

tolower函数

  • 定义函数:int tolower(int c);

函数说明:若参数 c 为大写字母则将该对应的小写字母返回。

返回值:返回转换后的小写字母,若不须转换则将参数c 值返回。
tolower(s[i]);

  • #include <cctype>

fill函数

  • 在头文件<algorithm>里面
  • 按照单元赋值,将一个区间的元素都赋同一个值
    fill(arr, arr + n, 要填入的内容);
    vector也可以:fill(v.begin(), v.end(), 要填入的内容);
  • fill 和fill_n函数是C++ Primer第十二章泛型算法部分内容,并把它们称为生成和变异算法,也就是说这两个函数只能对输入范围内已存在的元素进行操作。如果试图对空容器进行fill_n操作,会导致严重的运行错误,所以在对元素进行写入操作时要检查目标的大小是否足以存储要写入的元素。
  • fill的内部实现就是一个for循环
1
2
3
4
5
6
7
template< class ForwardIt, class T >
void fill(ForwardIt first, ForwardIt last, const T& value)
{
for (; first != last; ++first) {
*first = value;
}
}

对二维数组

  • 动态分配二维数组是指的new或者malloc申请内存

    memset函数

  • 1.memeset函数只能对连续的内存空间初始化。两次用malloc函数或new在堆上分的内存可能会不连续,因此错误。
  • 2.如果是直接声明的多维数组如int a[5][5],其内存肯定是连续的,此时统一memset没问题(动态声明的二维数组不一定内存连续)

    1
    2
    3
    int P[100][100];
    memset(P, 0, sizeof(P) ) ;
    //这种直接定义的,可以memeset初始化
  • memset函数的初始化只能对一维数组或者直接定义的而巍峨数组,对于动态分配的二维数组,对于每一行,是连续分配的; 然而对于各行之间,却不一定是连续分配的,容易出错

fill函数

  • 二维数组初始化(推荐)
    1
    2
    3
    4
    5
    6
    7
    8
    int mp[20][20];
    fill(mp[0], mp[0]+20*20, 5);
    //给二维数初始化
    for(int i = 0; i < 20; i++){
    for(int j = 0; j < 20; j++)
    cout << mp[i][j] << " ";
    cout << endl;
    }

与memset()函数的区别:

  • memset的初始化速度比循环要快很多
  • fill和for循环事件是一样的
    • fill的源码就是for循环实现的
  • 两者都可以用来对数组填充,memset是对按照字节来填充的,所以一般用来填充char型数组,也经常用于填充int型的全0或全-1操作。
  • fill是按照单元来填充的,所以可以填充一个区间的任意值。

fill_n函数

  • 在头文件<algorithm>里。
  • fill_n(vec.begin, cnt, val);从当前起始点开始,将之后的cnt个元素赋值为val。
      注意:不能在没有元素的空容器上调用fill_n()函数

memset函数

  • 在头文件<cstring>里面
  • memset的作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法
  • Memset函数:可以本身就是为字符数组设计的源代码:unsigned int 有一个特性就是如果将其赋值或者当作字节来使用的话,编译器将会截取低八位作为一个字节使用。

    1
    2
    3
    4
    5
    6
    7
     void *(memset)(void *s, int c, size_t n){
    const unsigned char uc = c;
    unsigned char *su;
    for (su = s; 0 < n; ++su, --n)
    *su = uc;
    return (s);
    }
  • 源码说明对于数组参数是按照字符数组的形式进行赋值的。
    也就是c的值每次赋值给一个字节,而不是4个字节,c的类型是int类型,4个字节,但只会赋值最低位的一个字节的内容。

  • 对于非单字节数据类型只能初始化为0,而不能初始化成别的初值,因为对所有字节按任意顺序赋值0的结果都是0,而如果初始化为其他的值,就会一个字节一个字节的进行赋值,从而出现奇怪的结果。

  • 对于变量:当结构体类型中包含指针时,在使用memset初始化时需要小心。
    struct sample_strcut stTest;用memset就非常方便:memset(&stTest,0,sizeof(struct sample_struct));
    原因是memset初始化的时候是按字节一个一个填充的,int有四个字节,于是填充成0000 0001 0000 0001 0000 00001 0000 0001,这样得出数组中的每个元素的值就是16843009了。赋值时0与\0效果一样。

  • 可以用于清空数组内元素与赋,memset函数一般用来填充char型数组,也经常用于填充int型的全0或全-1.不可用其它值,除非高低字节相同.
    -

    1
    2
    3
    #define INF 0x3f3f3f3f
    int num[N];
    memset(num, INF, sizeof(num));
  • 这样得到的数组里面的每一个元素数值都是INF
    看一下INF的二进制表示:
    00111111001111110011111100111111
    可以看出低8位是00111111,也就是实际赋值时是用
    00111111来填充一个int类型
    ,结果正好也是
    00111111001111110011111100111111
    于是就成功用memset进行了赋值。

初始化与赋值

  • memset()的深刻内涵:用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化
    • 例如:memset(a,'\0',sizeof(a) );
  • 对字符串数组

    1
    2
    3
    char a[5];
    memset(a, '1', 5);
    // 数组a 是字符型的,字符型占据内存大小是1Byte,而 memset 函数也是以字节为单位进行赋值的
  • 对bool型数组赋值:

    1
    2
    3
    4
    const int N = 11;
    bool arr[N];
    memset(&arr, 1, sizeof(bool) * N);
    //bool类型就是1或0.
  • 对结构体

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    //有一个结构体Some x,可以这样清零:
    memset(&x, 0, sizeof(Some));
    //如果是一个结构体的数组Some x[10],可以这样:
    memset(x, 0, sizeof(Some)*10);

    //memset可以方便的清空一个结构类型的变量或数组。如:
    struct sample_struct
    {
    char csName[16];
    int iSeq;
    int iType;
    };

    //对于变量
    struct sample_strcut stTest;

    //一般情况下,清空stTest的方法:
    stTest.csName[0]={'\0'};
    stTest.iSeq=0;
    stTest.iType=0;
    //如果用memset的话非常方便:
    memset(&stTest, 0, sizeof(struct sample_struct));

    //如果是数组:
    struct sample_struct TEST[10];

    memset(TEST, 0, sizeof(struct sample_struct)*10);
    //另外:如果结构体中有数组的话还是需要对数组单独进行初始化处理的

INF小知识

  • 0x3f3f3f3f的十进制是1061109567,也就是10^9级别的(和0x7fffffff一个数量级),而一般场合下的数据都是小于10^9的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。
  • 另一方面,由于一般的数据都不会大于10^9,所以当我们把无穷大加上一个数据时,它并不会溢出(这就满足了“无穷大加一个有穷的数依然是无穷大”),事实上0x3f3f3f3f+0x3f3f3f3f=2122219134,这非常大但却没有超过32-bit int的表示范围,所以0x3f3f3f3f还满足了我们“无穷大加无穷大还是无穷大”的需求。

  • 最后,0x3f3f3f3f还能给我们带来一个意想不到的额外好处:如果我们想要将某个数组清零,我们通常会使用memset(a,0,sizeof(a))这样的代码来实现(方便而高效),但是当我们想将某个数组全部赋值为无穷大时(例如解决图论问题时邻接矩阵的初始化),就不能使用memset函数而得自己写循环了(写这些不重要的代码真的很痛苦),我们知道这是因为memset是按字节操作的,它能够对数组清零是因为0的每个字节都是0,现在好了,如果我们将无穷大设为0x3f3f3f3f,那么奇迹就发生了,0x3f3f3f3f的每个字节都是0x3f!所以要把一段内存全部置为无穷大,我们只需要memset(a,0x3f,sizeof(a))
    所以在通常的场合下,const int INF = 0x3f3f3f3f;真的是一个非常棒的选择。

  • 因为在某些编译器分配空间时,内存中默认值并不为0,所以先用memset函数赋初值0.

转换函数

atoi()函数

  • 用来将字符串转换成整数(int):int atoi (const char * str);
  • 【返回值】返回转换后的整型数;如果 str 不能转换成 int 或者 str 为空字符串,那么将返回 0。
  • atoi() 函数会扫描参数 str 字符串,跳过前面的空白字符(例如空格,tab缩进等,可以通过isspace() 函数来检测),直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回。
  • Enter a number: 233cyuyan
  • The value entered is 233.

atol函数

  • 定义函数:long atol(const char *nptr);
  • 函数说明: atol()会扫描参数nptr字符串,跳过前面的空格字符(就是忽略掉字符串左空格的意思),直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时(‘\0’)才结束转换,并将结果返回。
  • 返回值:返回转换后的长整型数。如果传入的字符串为空,或者字符串包含的内容非阿拉伯数字序列,则函数返回默认值0。

    与stoi区别

  • stoi用于string类
  • stoi()会做范围检查,默认范围是在int的范围内的,如果超出范围的话则会runtime error!而atoi()不会做范围检查,如果超出范围的话,超出上界,则输出上界,超出下界,则输出下界;

atof函数

  • 定义函数 double atof(const char *nptr);
  • 函数说明 atof()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回。参数nptr字符串可包含正负号、小数点或E(e)来表示指数部分,如123.456或123e-2。
  • 返回值:函数返回转换后的双精度浮点数,如果没有执行有效的转换,则返回零(0.0)。
  • 范例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include<stdlib.h>
    int main()
    {
    char*a="-100.23";
    char*b="200e-2";
    double c;
    c=atof(a)+atof(b);
    printf(“c=%.2lf\n”,c);
    return 0;
    }

memcpy

  • void *memcpy(void*dest, const void *src, size_t n);
  • 用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度:

    1
    2
    3
    char a[100], b[50];
    memcpy(b, a, sizeof(b) );
    //注意如用sizeof(a),会造成b的内存地址溢出
  • 说明

    • source和destin所指内存区域不能重叠,函数返回指向destin的指针。
    • 与strcpy相比,memcpy并不是遇到’\0’就结束,而是一定会拷贝完n个字节。
------ The Happy Ending ------