1.C与C++

C实现动态数组

存储学生信息,要求顺序存储可逐个添加信息,减少内存浪费。

#include
#include //字符串处理
#include //内存分配

struct Stu{ //单个学生结构体
    int id;  // 学号
    char name[20]; //姓名
};

struct Stu_arr{//学生组织结构体
    struct Stu *pstu; //指向结构体的指针
    int size; 
};

void init(struct Stu_arr *p_ss);
void destroy(struct Stu_arr *p_ss);
void push_back(struct Stu_arr *p_ss, struct Stu *p_stu);
void print(struct Stu_arr *p_ss);
int main(){
    struct Stu_arr ss;
    init(& ss); //初始化
    Struct  Stu stu1;
    stu1.id = 1;strcpy(stu1.name, "张三");
    push_back(&ss, &stu1);
    print(&ss);
    stu1.id = 5; strcpy(stu1.name, "mike");
    push_back(&ss, &stu1);
    print(&ss);
    destroy(&ss); //清理内存
    system("pause");
    return 0;
}
//初始化
void init(struct Stu_arr *p_ss) {
    p_ss->size = 0; 
    p_ss->pstu = NULL;
}

void destroy(struct Stu_arr *p_ss) {
    if (p_ss->pstu) // 
        free(p_ss->pstu);//释放内存
}
void push_back(struct Stu_arr *p_ss, struct Stu *p_stu) {
    struct Stu* p_new = (struct Stu*)malloc((p_ss->size + 1)
        * sizeof(struct Stu));
    memcpy(p_new, p_ss->pstu, p_ss->size * sizeof(struct Stu));
    memcpy(p_new + p_ss->size, p_stu, sizeof(struct Stu));
    free(p_ss->pstu);
    p_ss->pstu = p_new;
    p_ss->size++;
}
void print(struct Stu_arr *p_ss) {
    for (int i = 0; i < p_ss->size; i++) {
        printf("(%d,%s)\t", (p_ss->pstu)[i].id, (p_ss->pstu)[i].name);
    }
    printf("\n");
}

C++

使用c++中的标准库类型vector可以很轻松的完成任务。
不需要管理内存分配,对不同的类型都可以处理

使用c++中 string标准库类型string替代c中的字符数组类,编程更加自如

#include
#include
#include
using namespace std;
struct Stu{
    int id;
    string name;
};

int main(){
    vector ss;
    Stu stu1;
    stu1.id = 1; stu1.name = "张三";
    ss.push_back(stu1);
    stu1.id =5; stu1.name = "mike";
    ss.push_back(stu1);
    for(int i = 0; i < ss.size(); i++){
        cout<<"("<

C++对C的扩展(命名空间:作用域)

在相同作用域,同名变量只可以定义一次
不同作用域中,同名变量课重复定义
只有新定义的起作用

实际上,不同作用域的同名变量所占有的空间是不同的。

#include
int x = 10;
void fun(){
    int x  = 20;
    printf(" fun()" x = %d\n,x);
}
int main(){
    int x = 30;
    {
        int x = 40;
        printf("main(){}: x =%d\n",x);
     }
     fun();
      printf("main():x = %d\n",x);
      return 0 ;
}

C++对C的扩展(命名空间:引入原因)

在大型项目过程中,经常会用到多家公司提供的类库,或者协作开发的多个小组之间,可能会使用同名的函数或者全局变量,从而造成冲突。

基本语法:

namespace 空间名字{
    变量;
    函数;
}(注意此处没有分号)

基本用法:

空间名字::变量名/函数名

命名空间分割了全局命名空间(::)
每个命名空间都是一个作用域

#include 
namespace A {
    int x = 10;
    void print() { printf("A::x=%d\n", x); }
}
namespace B {
    int x = 20;
    void print() { printf("B::x=%d\n", x); }
}

int x = 30;
void print() { printf("x=%d\n", x); }
int main() {
    int x = 40;
    printf("main:x=%d\n", x); //局部变量x 40
    printf("全局:x=%d\n", ::x); //全局的x 30
    printf("命名空间A::x=%d\n", A::x);//A中的x 10
    printf("命名空间B::x=%d\n", B::x);//B中的x 20
    A::print(); //10
    B::print(); //20
    print();    //30
    return 0;
}

命名空间:使用方法

  1. 空间名字::变量名/函数名
  2. using 空间名字::变量名/函数名
  3. using namespace 空间名字

第一种方法推介,肯定不会有错
第2中种用法每次只能引入一个成员
第3种用法会打开该空间中所有的成员(变量/函数等),谨慎使用

#include 

namespace A {
    int x = 10, y = 20;
}
int x = 30;
int main() {
    //打开了A, A中的名字被“添加”到全局作用域
    {
        using namespace A;
        y++; //此处y是 A::y (ok)
        //x++; //此处的x可能是::x也可能是A::x (错误)
        ::x++; //指明了是全局作用域的x (ok)
        A::x++; //指明了是 A::x (ok)
        int x = 31; //当前的局部变量x (ok)
        x++;  //此处的x 是上面的局部变量 31 (ok)
    }

    {
        using A::x;
        x++; //此处的x是 A::x (ok)
    }

    return 0;
}

#include 

namespace A {
    int x = 10, y = 20;
}
namespace B {
    int x = 30;
}
int main() {
    {
        using namespace A;
        using namespace B;
        y++; // ok
    }

    {
        using namespace A;
        using namespace B;
        //x++; //A B 中都有x, 二义性 (错误)
    }
    {
        using namespace A;
        int x; //定义局部变量 (ok)
    }

    {
        using A::x;
        //int x; //错误
    }

    return 0;
}

在实际使用中,要避免二义性错误,直接使用
空间名字::变量函数的写法是最保险的

命名空间:嵌套连续
#include
using namespace std;
namespace A{
    int a1 = 1;
    inr a2= 2;
    namespace A1{
        int x1 = 3;
        int y1 = 4;
    }
}
int main(){
    //方法1:  A::A1::作用域符
    cout <
#include 
using namespace std;
namespace A{
    int a1=1;
    int a2 = 2;
}
namespace A{// 同名空间自动合并
    int b1 = 3;
    int b2 = 3;
}
int main(){
    return 0 ;
}
C++对C的扩展(输入输出:格式化)
#include 

int main() {
    int a = 12345;
    double f = 123.4567;
    //默认输出整数
    printf("a=%d===\n", a);
    //占8格,右对齐
    printf("a=%8d===\n", a);
    //占8格,左对齐
    printf("a=%-8d===\n", a);
    //默认输出浮点数,小数显示6位
    printf("f=%f===\n", f);
    //占10格,小数显示2位,右对齐
    printf("f=%10.2f===\n", f);
    //占10格,小数显示2位,左对齐
    printf("f=%-10.2f===\n", f);

    return 0;
}
#include 
#include 
using namespace std;
int main() {
    int a = 12345;
    double f = 123.4567;
    //默认输出整数
    cout << "a=" << a << "===" << endl;
    //占8格,右对齐
    cout << "a=" << setw(8) << a << "===" << endl;
    //占8格,左对齐
    cout << "a=" << setw(8) << setiosflags(ios::left)
        << a << "===" << endl;
    //默认输出浮点数,有效位数显示6位
    cout << "f=" << f << "===" << endl;
    //占10格,小数显示2位,右对齐
    cout << "f=" << setw(10) << setprecision(2)
        << setiosflags(ios::fixed) << setiosflags(ios::right)
        << f << "===" << endl;
    
    return 0;
}
字符串

C代码:输入输出字符串

# include
int main(){
    char str[10] = {0};
    scanf("%s",str);
    printf("%s\n", str);
    return 0;
}

问题1:输入字符串有空格,无法处理
问题2:输入长度超过字符数组长度,不安全

以下代码解决问题:

#include 
#include 
int main() {
    char str[10] = { 0 };
    fgets(str, sizeof(str), stdin); // stdin 标准输入文件
    if (str[strlen(str) - 1] == '\n')
        str[strlen(str) - 1] = '\0';
    printf("%s\n", str);
    return 0;
}
#include 
using namespace std;
int main() {
    char str[10] = { 0 };
    cin.getline(str, sizeof(str));
    cout << str << endl;
    return 0;
}

C++代码

#include 
using namespace std;
int main(){
    char str[10] = {0};
    cin>>str;
    cout<

问题1、2都存在
using namespace std;
int main(){
char str[10] = {0};
cin.getline(str,sizeof(str));
cout < return 0 ;
}

C++基本内置类型

新增bool类型,取值是真(true),false(假)

基本类型转换

#include
using namespace std;
int main(){
    // int 和 bool 转换(1,0)
    int i = 3;
    bool b = true;
    i = b ; // bool 转 int 
    cout << " i = " << i <

其中,1 - 2 运算转换成1 + (-2)
1的原码和补码都为0.......1;
-2 的原码为1.....10,原码转换成补码:先转换成反码然后在加1:为111111...01 +1 = 11111...10

所以:1+(-2)= 0......1 + 111...10 = 111...111

变量的声明

变量可以多次声明,但只能定义一次

int i1 ; //定义
int i2 =20;//定义
extern int i3 = 30 // 定义

extern int i4; //声明
列表初始化
#include 
using namspace std;
int main(){
    int i1 = 0;
    int i2 = {0};
    int i3(0);  // c++
    int i4{0}   // c++
    return 0;
}

列表初始化: 由一组花括号括起来的初始值进行初始化,使用该方式对内置类型变量初始化时,假如存在丢失信息的风险,编译器直接报错。

#include
using namespace std;
int main(){
    double fd = 3.14
    int i1(fd), i2 = fd; //    ok
    int i3{fd},  i4 = {fd}; //error
    return 0;

}
指针和引用

//空指针
// NULL 在C中定义是((void*) 0 )
// NULL 在C++中定义是0
//nullptr 在 c++中用来表示空指针

int *p = nullptr;
if(p)
    cout<< "p is false"<

指针实际上是地址,指针变量用来存放指针(指针)。
指针变量也是一种变量,同样要占用一定的存储空间,指针的存储空间存放的是一个地址。

#include
using namespace std;
int main(){
    int i = 100;
    int  &ref_i  = i; // 引用
    cout<< i << "  " <

引用是给变量或对象起一个别名,定义时必须初始化,一旦绑定,终身不变,引用并不占有内存空间。

#include
using namespace std;
int main(){
    int a = 10;
    int &ra = a;
    cout<<&a<<&ra<
# include
using namespace std;
void swap1(int *pa, int *pb){
    int tmp = *pa;
    *pa = *pb;
    *pb = tmp;
}
void swap2(int &a, int &n){
    int tmp = a;
    a = b ;
    b = tmp;
}
void swap3(int a1, int b1) {
    int tmp = a;
    a = b;
    b = tmp;
int main(){
    int a = 10,b = 20;
    swap1(&a,&b);
    cout<
数组的引用
#include
using namespace std;
int main(){
    int a = 1,b =2 , c =3;
    // ok,指针数组
    int *ptr[] = {&a,&b,&c}
    // 错误 在数组中存放引用是不行的
    // int &r_arr[] = {&a ,&b , &c};
    int arr[3] = {a,b,c};
    int (*p1)[3] = &arr; //ok,数组指针,指向数组的指针
    int(&r1)[3] = arr; // ok,数组的引用
    return 0;
}

引用的本质,从下面的代码,可以猜测,引用好像就是一个指针,通过汇编代码的分析,可以推测引用实际上通过指针实现的,引用是指针的一种的包装:类似int * const p 这样的格式的一种包装。

#include
using namespace std;
struct Stu{
    int age;
    char sexl;
    char name[20];    
};
struct A{int &data;};
struct B{char &data;};
struct C{stu &data;};
int main(){
    cout<
const 限定符

C代码
可以通过将const 常量的地址赋值给指针变量改变const常量的值,这通常是不被希望看见的

#include 
int main() {
    const int i = 10;
    //const int i;  //错误,const变量必须在定义时初始化
    //i=100;        //错误,const类型不能修改
    int *p = &i;    //将i的地址赋值给指针p( 在C中ok)
    *p = 20;        //通过指针修改const int i的值
    printf("i=%d,*p=%d\n", i, *p); // 20 20
    return 0;
}

在C++中增强了对const的限制,不允许以上类似C的操作

#include 
using namespace std;
int main() {
    const int i = 10;
    //int *pi = &i; 编译错误(C++中不行)
    const int *pi = &i; //ok
    //*pi = 20; 编译错误(指向常量的指针无法修改常量)

    //下面尝试,强转转换来修改常量:
    int *pi2 = (int*)&i; //将常量i的地址强转为int *
    *pi2 = 20;   //将pi2指针指向的地址内容修改为20
    //观察 *pi2 和 i 对应的内存地址是否一样:
    cout << "pi2=" << pi2 << " &i=" << &i << endl;
    //观察 *pi2 和 i 的值
    cout << "*pi2=" << *pi2 << " i=" << i << endl;
    //输出 *pi2=20 i=10
    //思考:为什么会出现这样的结果??

    //一定要这么做,怎么做?
    volatile const int ii = 10; //使用volatile关键字
    int *pii = (int*)ⅈ
    *pii = 20;
    cout << "*pii=" << *pii << " ii=" << ii << endl;
    //输出 *pii=20 ii=20

    return 0;
}

默认情况下,const对象仅在文件内有效,假如要在多个文件中生效,则const变量不管是声明还是定义,都加上extern关键字。

const与引用
#include 
using namespace std;
int main() {
    const int i = 10;
    //int &ri = i; 错误,非常量引用指向常量
    int ii = 20;
    const int &rii = ii; //OK
    //rii = 30; 错误,常量引用无法修改值

    double fd = 1.23;
    //int &r = fd; 错误
    const int &r = fd; //OK
     //观察 fd 和 r 的值
    cout << fd << " " << r << endl;
    //观察 fd 和 r 的地址
    cout << &fd << endl;
    cout << &r << endl;

    return 0;
}

以上代码中 r 绑定了一个临时量

const int temp = fd;
const int &r = temp;
指针与const
#include 
using namespace std;
int main() {
    int i = 10, j = 30;
    int *p1 = &i; //无const限定
    *p1 = 20; //可以改变指向变量的值(i-->20)
    p1 = &j;  //可以改变指向的变量(p1指向了j)

    //指向常量的指针
    const int *p2; //const在*前面(也可写int const *p2)
    p2 = &i;    //p2 的指向 可以改变 (意味着p2不是常量)
    p2 = &j;
    //*p2 = 100; 错误,*p2改不了值(意味着*p2是常量)

    //常量指针(指针本身是常量)
    int * const p3 = &i; //const在*后面
    //p3 = &j; 错误,p3的指向不能改变(p3是常量)
    *p3 = 100; //OK, *p3可以修改

    //指向常量的常量指针
    const int * const p4 = &i; //两个const
    //p4 = &j; 错误
    //*p4 = 100; 错误
    return 0;
}

指向常量的指针
const int *p2 //const在* 前面,也可以写成 int const *p2
其中,p2的指向可以改变,意味着p2不是常量,但是 *p2不能改变,意味着*p2是常量
所以 上面 const 限定的是 *p2

常量指针

int * const p3 = &i; // const在*之后
// p3 = &j ; // 错误 p3的指向不能改变(p3是常量)
* p3 = 100; // OK,*p3 可以修改

指向常量的常量指针

const int * const p4 = &i ;//两个const
// p4 = &j; 错误
// * p4 = 100; 错误
return 0 ;

顶层const :指针本身是常量(常量指针int *const p1
底层const :指正指向的对象是常量(指向常量的指针 const int *p2)

数据类型 struct 和 class
#include 
using namespace std;
class player {
public:
    player(int level = 0, int hp = 0)
        :level(level), hp(hp) {}
    void train(int nums) {
        int killnums = hp > nums ? nums : hp;
        level += killnums;  hp -= killnums;
        cout << "练级:长了 " << killnums << " 级。";
        cout << "当前:level=" << level << ",hp=" << hp << endl;
    }
    void pk(player &another) {
        int power1 = level * 100 + hp;
        int power2 = another.level * 100 + another.hp;
        if (power1 >= power2)
            printf("You win!\n");
        else
            printf("You loss!\n");
    }
private:
    int level;  //等级
    int hp;     //hp值
};

int main() {
    player p1(1, 100); player p2(2, 50);
    p1.train(6);
    p2.train(10);
    p1.pk(p2);
    system("pause");
    return 0;
}
字符串

C语言

#include 
#include 
int main() {
    //字符数组
    char str1[20] = "abcde";        //初始化
    char str2[20] = { 'a','b','c' };//初始化
    //str2 = "abc"; 错误
    char str3[20];
    str3[0] = 'a'; str3[1] = 'b'; str3[2] = '\0';
    //字符指针
    char *pstr = "bcd"; //将常量字符串的地址赋给pstr
    pstr = "def";
    pstr = str1;
    pstr[0] = 'x';      //通过指针修改
    *(pstr + 1) = 'y';  //通过指针修改
    printf("str1=%s\n", str1); // 输出xycde
    //字符串长度
    printf("str1长度= %d\n", strlen(str1));  //5
    //字符串拷贝
    printf("str1=%s\n", strcpy(str1, "ddd"));//ddd
    //字符串连接
    printf("str1=%s\n", strcat(str1, str2)); //dddabc
    //字符串比较
    if (strcmp(str2, str3) > 0)
        printf("%s > %s\n", str2, str3);
    else if(strcmp(str2, str3) == 0)
        printf("%s == %s\n", str2, str3);
    else
        printf("%s < %s\n", str2, str3);
    //字符串查找
    strcpy(str2, "--ab=="); //str3: "ab"
    printf("%s\n", strstr(str2, str3)); //ab==
    return 0;
}

C++

#include 
#include 
using namespace std;
int main() {
    //std::string
    std::string str1("abc"); //初始化
    string str2 = "bcd";     //初始化
    str2 = "defg";           //可以直接赋值
    str2 = str1;             //可以直接赋值
    
    const char *pstr = str2.c_str(); //转c风格字符串
    str2[0] = 'X';      //可以直接下标访问操作
    str2.at(1) = 'Y';   //可以 at 访问操作
    cout <<"str2=" << str2 << endl; //XYc
    
    //求字符串长度
    cout << str2.size() << endl;
    cout << str2.length() << endl;
    //strlen(str1); 错误
    cout << strlen(str2.c_str()) << endl; //正确
    //字符串连接
    str2 = str2 + str1 + "!!";
    cout << "str2=" << str2 << endl; //XYcabc!!
    //字符串比较 (str1: abc)
    cout << str2.compare(str1) << endl; //-1
    cout << (str2 < str1) << endl;      //1
    //字符串查找
    cout << str2.find(str1) << endl;    //3
    //字符串提取
    string str3 = str2.substr(3, 3);
    cout << str3 << endl;               //abc

    return 0;
}
vector
#include 
#include 
#include 
using namespace std;
int main() {
    //std::vector的结构
    std::vector vec11; // [ 1, 3, 9 ...]
    vector vec22;   // [ "abc", "play", "C++" ]
    vector> vec33; // [ [1,3,9..],[2,3,4..], ... ]
    vector> vec44; // [ ["hello","C",..],["C++","abc",..],... ]

    //vector的初始化
    vector vec1 = { 1,2,3 };
    vector vec2{ 1,2,3 };  //列表初始化
    vector vec3 = vec1;    //vec1拷贝给 vec3
    vector vec4(10);       //初始化10个元素,每个元素都是0
    vector vec5(10, -1);   //初始化10个元素,每个元素都是-1
    vector vec6(10, "hi"); //初始化10个元素,每个元素都是 "hi"

    //判断是否为空
    cout << vec1.empty() << endl; //0
    //元素个数
    cout << vec1.size() << endl;  //3
    //添加元素在最后面
    vec1.push_back(100);
    cout << vec1[vec1.size() - 1] << endl; //100
    //弹出元素在最后面
    vec1.pop_back();
    cout << vec1[vec1.size() - 1] << endl; //3
    //直接下标访问元素
    cout << vec1[1] << endl; //2
    vec1[1] = 10;
    cout << vec1[1] << endl; //10
    // vector vec6(10, "hi")
    vec6[0][1] = 'X';
    cout << vec6[0] << endl; //hX

    //遍历(类似遍历数组)
    for (int i = 0; i < vec1.size(); i++) 
        cout << vec1[i] << " "; // 1 10 3
    cout << endl;

    return 0;
}

标准库类型vector表示对象的集合,其中所有的对象类型必须相同,因为vector 容纳着其他对象,所以被称为容器,vector是一个类模板。

auto 类型说明符
#include 
using namespace std;

int main() {
    //1.auto 变量必须在定义时初始化,类似于const
    auto i1 = 0; auto i2 = i1;
    //auto i3; //错误,必须初始化
    //2.如果初始化表达式是引用,则去除引用语义
    int a1 = 10;
    int &a2 = a1; // a2是引用
    auto a3 = a2; // a3是int类型,而不是引用
    auto &a4 = a1; // a4是 引用
    //3.去除顶层const
    const int b1 = 100;
    auto b2 = b1; // b2 是 int
    const auto b3 = b1; // b3是 const int
    //4.带上底层const
    auto &b4 = b1; // b4 是 const int 的引用
    //5.初始化表达式为数组时,推导类型为指针
    int arr[3] = { 1,2,3 };
    auto parr = arr; //parr 是 int * 类型
    cout << typeid(parr).name() << endl;
    //6.表达式为数组且auto带上&,推导类型为数组
    auto &rarr = arr; //rarr 是 int [3]
    cout << typeid(rarr).name() << endl;
    //7.函数参数类型不能是 auto
    //func(auto arg); //错误
    //8.auto并不是一个真正的类型,编译时确定
    //sizeof(auto); 错误
    return 0;
} 

迭代器:返回指针

#include 
#include 
#include 
using namespace std;

int main() {
    vector vs =
        { "all","people","like","c++" };

    for (vector::iterator i = 
                 vs.begin(); i != vs.end(); i++)
        cout << *i << " ";
    cout << endl;

    for (auto i = vs.begin(); i != vs.end(); i++) 
        cout << *i << " ";
    cout << endl;

    for (auto &s : vs)
        cout << s << " ";
    cout << endl;

    return 0;
}

你可能感兴趣的:(1.C与C++)