C++数据结构基础

语法与数据结构基础


如何通过函数修改实参的值

1.改变正常变量的实参

#include<stdio.h>
int main(void){

   int i =10;
   f(&i);
   printf("%d\n",i);

}
void f(int *p){

     *p = 99  ;     //调用函数传递元素的地址,更改其实参值。
}
// 指针是唯一能够将调用函数中的局部变量传入到主函数中的方法
// 最终的输出结果为 99 通过指针将数据覆盖到实参的原位置,从而改变了实参值。

2.改变指针变量的实参

//改变指针变量的实参

#include<stdio.h>
//  unsafe !!!

int main(void){

   int i =10;
   int *p = &i;  //int *p ; p = &i;

   printf("%d\n",p);
   f(&p);    //直接传数值到函数f()只能作为形参,不能改变实参值,只能传递地址元素。

   printf("%d\n",p);
}


void f(int **q){   // 为了配合&p的数据类型,为指针的指针。

     *q =  (int *)0xFFFFFFFF;     //调用函数传递元素的地址,更改其实参值。
    // *q  理解为q的实参(q为指针的指针,因此q的实参其实也是指针(地址))
}
形参与实参


#include<stdio.h>
 
void A(int* p){//此处p为形参
	int x = 3;
	p = &x;
	printf("在函数中p中的地址为%d\n\n",p);
}
//形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用(形参没有确定的值,只有函数内部运行时才是存在的)
//更底层的讲,形参是使用栈保存的,函数调用时入栈。
//而实参一般直接分配内存空间,存储在堆空间之中。
 
int main(){
	
	int e = 9;
	int* p = &e; //此处p为实参
	printf("main:p中的地址为: %d\n\n",p);
	
	A(p);//此时传入的是地址值,只能作为形参;当传入地址时才能做实参。
	
	printf("main:p中的地址为: %d\n\n",p);
	return 0;
    
    
//main:p中的地址为: 1030875172

//在函数中p中的地址为1030875148

//main:p中的地址为: 1030875172  
    

//假如在main方法中有一个指针变量p,它指向的内存地址为20000。现在将它传递到一个函数中,在这个函数里让它指向内存地址为20048。当函数执行完返回到main函数时,p所指向的地址还是20000,而不是20048。

在这里插入图片描述

读入未知数目输入

// 读入未知数目的输入
#include<iostream>
using namespace std;
int main(){
    int sum =0,value;
    while(std::cin >> value)
        sum += value;
    std::cout << "sum is "<<sum<<std::endl;
    return 0;
}
类与结构体

结构体:为了表示一些复杂的数据,而普通的基本类型变量无法满足要求;因此产生了结构体 ,结构体即用户根据实际需要自己定义的复合数据类型。

struct Student st = {1000, "zhangsan", 20} 

struct Student * pst = &st; 

\1. st.sid 

\2. pst->sid 

pst 所指向的结构体变量中的 sid 这个成员 
#include<stdio.h>
#include <cstring>
struct Student
{
     int sid;
     char name[200];
     int age;
};//创建类

int main(void){

  struct Student st;//创建一个名为st的对象
  f(&st);
  g(st);
  g2(&st);
 // printf("%d %s %d\n",st.sid,st.name,st.age);
  return 0;

}

//  结构体变量可以相互赋值,但实参一共占208个字节,浪费空间且耗时间。
//   传指针省空间 省时间。
void g(struct Student st)

{
     printf("%d %s %d\n",st.sid,st.name,st.age);
}
void g2(struct Student *st)
{
     printf("%d %s %d\n",st->sid,st->name,st->age);
}

void f (struct Student *pst)   //想要传入实参改变实值必须传入地址
{

(*pst).sid = 99;
//  *p.sid = p->sid    (普通变量).sid  ==  (指针变量)->sid
    strcpy(pst->name,"zhangsan");
    pst->age = 22;

}

类:


使用类的时候必须知道:1.类的名称2.类在哪里定义3.类支持什么操作。

成员函数:成员函数是类定义的方法,有时称作类方法。

#include <iostream>
#include <cstring>
using namespace std;

class C{
public:
    C(const char *s ="",int i=0,double d=1){
        strcpy(dataMember1,s);
        dataMember2 = i;
        dataMember3 = d;
    }
    void memberFunction1(){
        cout << dataMember1 <<"\n" << dataMember2 <<"\n" <<  dataMember3 <<endl;
        
    }
       void memberFunction2(int i,const char *s = "unkonwn"){
           
        dataMember2 = i;
           
        cout << i << "received from"<< s <<endl;// ''一个词;“” 一句
        
    }
protected://protected:只允许本类及子类的成员函数访问
    char dataMember1[20];
    int dataMember2;
    double dataMember3;
    
};



int main()
{
	
C object1("object1",100,2000);//, object2("object2"), object3;
 


//在创建的对象中调用函数。
object1.memberFunction1();
object1.memberFunction2(123,"object2");
   return 0;
}


在这里插入图片描述

class intClass{
    int storage[50];

};
class floatClass{
    float storage[50];

};

//使用模板声明一个通用类,在定义对象时确定对象引用什么类型的数据。
template<class genType>
class gneClass{
    genType storage[50];
};

genClass<int> intObject;
genClass<float> floatObject;

//将数组大小定义也推迟到创建对象的时候
template<class genType,int size =50>  //class可用typename替换
    class GneClass{
        genyType storge[size];
        
};
genClass<int> intObject1;//use the default size;
genClass<int,100> intObject2;
genClass<float,123> floatObject;


// 使用模板定义一个交换函数
template<class genType>  //class可用typename替换
   void swap(genType & e11,genType &e12){
    genType tmp = e11; e11 = e12; e12 = tmp;
}
        
swap(n,m);
// template 模板的用法
template<int N, int LO = 1, int HI = N>
struct Sqrt {
    static constexpr auto mid = (LO + HI + 1) / 2;
    static constexpr auto value =
        (N < mid * mid) ?
        Sqrt<N, LO, mid - 1>::value
        :
        Sqrt<N, mid, HI>::value;
};

template<int N, int M>
struct Sqrt<N, M, M> { // 终止条件为LO和HI相等
    static constexpr auto value = M;
};




//类模板
template<typename T> //在模板定义语法中关键字 class 与 typename 的作用完全一样;这里 class 关键字表明T是一个类型,后来为了避免 class 在这两个地方的使用可能给人带来混淆,所以引入了 typename 这个关键字,它的作用同 class 一样表明后面的符号为一个类型。
class A {
public:
    A(T y) : x(y) {}
private:
    T x;
};

A<int> a(10);
继承

#include <iostream>

using namespace std;

class BaseClass {
public:
    BaseClass() { }    //成员变量空置
    void f(const char *s = "unknown") {    //定义成员函数
        cout << "Function f() in BaseClass called from " << s << endl;
        h();
    }
protected:   //基类的受保护乘员只能在派生类中调用,因此f()在Derived1Level1、Derived2Level1中调用都是合法的,但在main()中调用是非法的
    void g(const char *s = "unknown") {
        cout << "Function g() in BaseClass called from " << s << endl;
    }
private:   // 私有类中定义的函数只能在BaseClass内部定义的函数调用;使用main()或者BaseClass的派生类调用都是非法的。
    void h() {
        cout << "Function h() in BaseClass\n";
    }
};
class Derived1Level1 : public virtual BaseClass {    // :后面加public,将继承指定为公有继承;(公有继续共有,受保护继续受保护)
public:
    void f(const char *s = "unknown") {
        cout << "Function f() in Derived1Level1 called from " << s << endl;
        g("Derived1Level1");
        h("Derived1Level1");   //g来自于base类;h来自于该派生类自己定义的函数
    }
    void h(const char *s = "unknown") {
        cout << "Function h() in Derived1Level1 called from " << s << endl;
    }
};
class Derived2Level1 : public virtual BaseClass {   //virtual 用于继承防止冗余;确保DerivedLevel2 仅包含BaseClass成员函数的一个副本
public:
    void f(const char *s = "unknown") {
        cout << "Function f() in Derived2Level1 called from " << s << endl;
        g("Derived2Level1");
//      h();  // error: BaseClass::h() is not accessible
    }
};
class DerivedLevel2 : public Derived1Level1, public Derived2Level1 {
public:
void f(const char *s = "unknown") {
	cout << "Function f() in DerivedLevel2 called from " << s << endl;
	g("DerivedLevel2"); 
	Derived1Level1::h("DerivedLevel2");
	BaseClass::f("DerivedLevel2");
    }
};

int main() {
    BaseClass bc;
    Derived1Level1 d1l1;
    Derived2Level1 d2l1;
    DerivedLevel2 dl2;
    bc.f("main(1)");
//  bc.g(); // error: BaseClass::g() is not accessible
//  bc.h(); // error: BaseClass::h() is not accessible
    d1l1.f("main(2)");
//  d1l1.g(); // error: BaseClass::g() is not accessible 注: Derived1Level1 继承自BaseClass的g()仍然是protected,不能在main中直接调用
    d1l1.h("main(3)");
    d2l1.f("main(4)");
//  d2l1.g(); // error: BaseClass::g() is not accessible 注: Derived2Level1 继承自BaseClass的g()仍然是protected,不能在main中直接调用
//  d2l1.h(); // error: BaseClass::h() is not accessible 注: Derived2Level1 继承自BaseClass的h()仍然是private,不能在main中直接调用
    dl2.f("main(5)");
//  dl2.g();  // error: BaseClass::h() is not accessible
    dl2.h();  //h是继承自Derived1Level1的public函数h();
    return 0;
}
指针&动态分配内存

*p =  20  //这里的(*)是一个间接寻址运算符
    
// malloc动态分配内存
#include<stdio.h>
#include<malloc.h>
int main(void ){

int a[5] = {4,10,2,8,6};
 int len;
 printf("请输入你需要分配的数组长度:");
 scanf("%d",&len);
 int *pArr = (int *)malloc(sizeof(int)*len);

 //*pArr = 4;   //动态分配的数组和普通数组有一样的用法即*pArr = pArr[0]
 //pArr[1] = 10;
 //printf("%d %d",*pArr,pArr[1]);
 //我们可以当做一个普通数组来使用
 for(int i = 0;i <len;i++)
     scanf("%d",&pArr[i]);

  for(int i = 0;i <len;i++)
      printf("%d\n",*(pArr+i));



 free(*pArr);       //动态数组可以随时释放节省内存,释放(4字节)*len 大小的内存。
 return 0;
}
//  C++中想要动态的分配合回收动态空间,主要使用new和delete两个函数
p = new int;
//指示程序向内存管理器请求足够的空间来存储一个整数,这部分内存的地址存放在p中;现在可以间接地通过指针对p指向的内存块赋值,也可以使用q = p将存储在p中的地址赋值给另一个指针。
// int *p = (int *)malloc(sizeof(int));
delete p;  //回收内存;为了防止内存泄露,使用完内存后应当即时释放内存空间。
    

指针和数组

int n =10, *p = &n;
delete p;
int a[10],*q = a; // a性质和一致
delete [] q;

//动态分配数组空间
//int n = 10;
p = new int[n]
delete [] p
    

指针与复制构造函数

#include <iostream>
#include <cstring>
using namespace std;

struct Node{
    char *name;
    int age;
    Node(const char *n = "",int a=0){
	
        name = strdup(n);
        age  = a;
	}
};

int main()
{
    Node node1("Roger",20),node2(node1);
	strcpy(node2.name,"Wendy");
    node2.age = 30;
    cout << node1.name << ' '<<node1.age << ' '<<node2.name<<' '<<node2.age;
	
   return 0;
}

// 运行结果:Wendy 20 Wendy 30

在这里插入图片描述

// 使用新的构造函数,声明node2(node1)生成了"Roger"的·一个副本(图c),node.name指向该副本,给一个数值成员赋值并不会影响到另一个成员。
struct Node{
    char *name;
    int age;
    Node(const char *n = "",int a=0){
	
        name = strdup(n);
        age  = a;
	}
    //Node(const Node * n)// 只传地址; n的数据结构:Node *n
    Node(const Node &n){  // 只传地址; n的数据结构:Node n   // &n = x  
        name = strdup(n.name);//*n.name or n->name
        age = n.age;
        
    }
        
};
//入果用户没有提供赋值运算符的定义,以下操作
node1 = node2;
// 就会对逐个成员进行复制,引起图(a)图(b)所示的问题
//为了避免这一问题,用户必须重载运算符,以下代码可以帮node完成这一任务。
   Node & operator = (const Node &n){
    if(this != 0){
        if(name != 0)
            free(name);
        name = strdup(n.name);
        age = n.age;
    }
    return *this;
} // 每个对象都可以通过指针this访问自己的地址;所以*this就是对象本身。

在这里插入图片描述

函数指针

// 考虑一个简单的函数
double f(double x){
    return 2*x;

}
// 对于这个定义 f是指向函数f()的指针; *f()是函数本身

// double *f(double)  返回一个指向double值得指针

double sum(double (*f)(double),int n,int m ){//传的都是形参
    double result =0;
    for(int i = n;i<=m;i++){
        result += i;
    }
    return result;
}
//调用函数sum()时,需要提供一个具有double参数并返回double值的函数,这个函数既可以是自定义的也可以是内置的。
// cout  << sum(f,1,5) << endl;
// cout  << sum(sin,3,7)  << endl;
    
    
//在函数sum()的定义中,第一个形参的声明
// double (*f)(double)  
 // 意味着  f是一个指向函数的指针,该函数带有一个double参数

//示例: 在某个区间寻找连续函数的根  、
// 使用二分法求根

double root(double (*f)(double),double a,double b,double epsilon){  //第一个声明将函数 f 作为形参传入
    double middle = (a+b)/2;
    while( middle != 0 && fabs(b-a) > epsilon){
        if(f(a)*f(middle)<0)
            b = middle;
        else
            a = middle;
        middle = (a+b)/2;
    }
    return middle;
    
}
跨函数使用内存

只有在使用动态内存,且动态内存没有free的前提下,函数调用时所占用的内存会保留。

#include<stdio.h>
struct Student{
int sid ;
int age;
};

struct Student *CreateStudent(void);  //创建
void ShowStudent(struct Student *);

int main (void){

 struct Student *ps;   //创建一个动态数据类型的结构体
 ps = CreateStudent();   //ps == p
 ShowStudent(ps);
 return 0;
 }
  void ShowStudent(struct Student *pst)
  {
       printf("%d %d",pst->sid,pst->age);
  }
  struct Student *CreateStudent(void){
       struct Student *p = (struct Student *)malloc(sizeof(struct Student));   //创建了一个Student 结构体动态分配变量
       p->sid = 99;
       p->age = 20;
       return p;

  }
多态性

#include <iostream>

using namespace std;

class Class1 {
public:
    virtual void f() {
	  cout << "Function f() in Class1\n";
    }
    void g() {
	  cout << "Function g() in Class1\n";
    }
};

class Class2 {
public:
    virtual void f() { 
	  cout << "Function f() in Class2\n";
    }
    void g() {
	  cout << "Function g() in Class2\n";
    }
};

class Class3 {
public:
    void h() {
	   cout << "Function h() in Class3\n";
    }
};

int main() {
    Class1 object1, *p;
    Class2 object2;
    Class3 object3;
    p = &object1;
    p->f();     //Function f() in Class1
    p->g();     //Function g() in Class1
    p = (Class1*) &object2;
    p->f();     // Function f() in Class2
    p->g();     // Function g() in Class1
    p = (Class1*) &object3;
//  p->f(); // Abnormal program termination;
    p->g();      //Function g() in Class1
//  p->h(); // h() is not a member of Class1;
    return 0;
}



在这里插入图片描述

标准模板库

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

函数对象

在这里插入图片描述

// 定义一个重载函数调用运算符的类实现同样的任务

在这里插入图片描述

标准模板库中的向量

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional> // greater<>

using namespace std;

template<class T>
void printVector(char *s, const vector<T>& v) {
    cout << s << " = (";
    if (v.size() == 0) {
        cout << ")\n";
        return;
    }
    typename vector<T>::const_iterator i = v.begin();
    for ( ; i != v.end()-1; i++)
        cout << *i << ' ';
    cout << *i << ")\n";
}

bool f1(int n) {
    return n < 4;
}

int main() {
    int a[] = {1,2,3,4,5};
    vector<int> v1;      
    printVector("v1",v1);  // v1 is empty, size = 0, capacity = 0
    cout << "size = " << v1.size() << ", capacity = " << v1.capacity() << endl;
    for (int j = 1; j <= 5; j++)
        v1.push_back(j);   // v1 = (1 2 3 4 5), size = 5, capacity = 8
    printVector("v1",v1);
    cout << "size = " << v1.size() << ", capacity = " << v1.capacity() << endl;
    vector<int> v2(3,7); 
    printVector("v2",v2);  // v2 = (7 7 7)
    vector<int>::iterator i1 = v1.begin()+1;
    vector<int> v3(i1,i1+2); 
    printVector("v3",v3);  // v3 = (2 3), size = 2, capacity = 2
    cout << "size = " << v3.size() << ", capacity = " << v3.capacity() << endl;
    vector<int> v4(v1);  
    printVector("v4",v4);  // v4 = (1 2 3 4 5), size = 5, capacity = 5
    cout << "size = " << v4.size() << ", capacity = " << v4.capacity() << endl;
    vector<int> v5(5);   
    printVector("v5",v5);  // v5 = (0 0 0 0 0)
    v5[1] = v5[3] = 9;
    printVector("v5",v5);  // v5 = (0 9 0 9 0)
    v3.reserve(6);       
    printVector("v3",v3);  // v3 = (2 3), size = 2, capacity = 6
    cout << "size = " << v3.size() << ", capacity = " << v3.capacity() << endl;
    v4.resize(7);        
    printVector("v4",v4);  // v4 = (1 2 3 4 5 0 0), size = 7, capacity = 10
    cout << "size = " << v4.size() << ", capacity = " << v4.capacity() << endl;
    v4.resize(3);        
    printVector("v4",v4);  // v4 = (1 2 3), size = 3, capacity = 10
    cout << "size = " << v4.size() << ", capacity = " << v4.capacity() << endl;
    v4.clear();          
    printVector("v4",v4);  // v4 is empty, size = 0, capacity = 10 (!)
    cout << "size = " << v4.size() << ", capacity = " << v4.capacity() << endl;
    v4.insert(v4.end(),v3[1]);
    printVector("v4",v4);         // v4 = (3)
    v4.insert(v4.end(),v3[1]);
    printVector("v4",v4);         // v4 = (3 3)
    v4.insert(v4.end(),2,4);
    printVector("v4",v4);         // v4 = (3 3 4 4)
    v4.insert(v4.end(),v1.begin()+1,v1.end()-1); 
    printVector("v4",v4);         // v4 = (3 3 4 4 2 3 4)
    v4.erase(v4.end()-2);
    printVector("v4",v4);         // v4 = (3 3 4 4 2 4)
    v4.erase(v4.begin(), v4.begin()+4);
    printVector("v4",v4);         // v4 = (2 4)
    v4.assign(3,8);             
    printVector("v4",v4);         // v4 = (8 8 8)
    v4.assign(a,a+3);  
    printVector("v4",v4);         // v4 = (1 2 3)
    vector<int>::reverse_iterator i3 = v4.rbegin();
    for ( ; i3 != v4.rend(); i3++)
        cout << *i3 << ' ';       // print: 3 2 1
    cout << endl;

//  algorithms

    v5[0] = 3;           
    printVector("v5",v5);         // v5 = (3 9 0 9 0)
    replace_if(v5.begin(),v5.end(),f1,7);
    printVector("v5",v5);         // v5 = (7 9 7 9 7)
    v5[0] = 3; v5[2] = v5[4] = 0;
    printVector("v5",v5);         // v5 = (3 9 0 9 0)
    replace(v5.begin(),v5.end(),0,7);
    printVector("v5",v5);         // v5 = (3 9 7 9 7)
    sort(v5.begin(),v5.end()); 
    printVector("v5",v5);         // v5 = (3 7 7 9 9)
    sort(v5.begin(),v5.end(),greater<int>()); 
    printVector("v5",v5);         // v5 = (9 9 7 7 3)
    v5.front() = 2;         
    printVector("v5",v5);         // v5 = (2 9 7 7 3)
}


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值