C++笔记 3

时间:2022-09-05 23:47:32

1、数组是自动分配空间,指针要手工分配空间(int *p = new int;)

2、在Unix上,程序出现段错误的时候,系统会生成core 文件,会把出现错误的那一刻的程序镜像保存在此文件中

3、结构的成员变量出现数组:
    struct Account{
       long id ;
       //char name[ 50 ] ;
       //char password[ 10 ] ;
       char * pname ;
       char * ppwd ;
       double balance ; 
    };
   数组长度100-200字节,最好用数组做,这样方便
   数组很大的时候,可以考虑用指针,赋值的时候要注意:
   a.pname = new char[50];
   strcpy(a.pname , "huxinzhe");
  
   在结构声明时,不能给成员变量赋值
   结构声明只是声明了一种数据类型,还没有为这个结构申请空间,赋值的数据没有空间保存
  
4、危险指针的用法
   使用NULL指针的内容 ---隐蔽性不高,容易发现
   使用没有初始化的指针 --- 会导致无意当中修改其它变量,破坏性很大,避免的办法  int *p = NULL;
   使用已经被delete的指针内容  ---  修改其它变量  避免的办法  delete p ;   p=NULL;
   返回一个局部变量的地址 
   由函数申请空间,由调用者释放
   #include <iostream>
   using namespace std;

char * readLine(){
     char * line = new char[ 100 ] ;  //在函数中申请了空间,但是没有地方释放
     strcpy( line , "hello world" ) ;
     cout<<"line = " << line << endl;
     return line ;                    //返回变量的指针,若是局部变量,在函数返回的时候,就消失了,若在堆中申请空间,没有释放空间的机会
   }
   int main(){
     char * p = readLine();
     cout<<"return from readLine "<<endl;
     cout<<"p = " << p << endl;
     delete p;                         //释放别人申请的空间,不安全
     return 0 ;
   }
  
   解决的办法 : 在函数外部申请一个指针并初始化,作为参数传给函数,这样可以保存数据并返回
                 在参数中传数组的起始地址,和数组长度
   只要是参数传指针,指针在传给函数之前要进行初始化
  
  
5、编译的时候不想看到警告信息  g++ -w
  
6、函数指针的声明:
   函数的名字就是这个函数的首地址
   函数指针之间的赋值,也要同类型的
   函数指针是不需要释放的。
  
   函数指针,设计通用算法
  
7、多层指针
   int i = 10;
   int * p = &i;
   int ** pp =&p;
   int**(*ppp) = & pp;
  
   *p = i ;
   *pp = p;
   **pp = i;
  
   多层指针的使用 :
   int ia[2][3] = {{11,12,13},
                   {21,22,23}};  //声明并定义一个二维数组
   cout << ia[0] << endl;  //打印的是ia的第一个数组的首地址
  
   int * p = ia[0]; //保存ia第一个数组的首地址
   cout << a[0][2] <<endl;
   cout << p[2] <<endl;  //与上面一行具有相同的效果 。
  
   ia[0]的类型就是int*类型的,指向ia的第一个数组
   ia也是个指针类型,指向那个二维数组 ,是 int**
  
   二维数组是一个二级指针
   二维数组的每个元素是一级指针
  
   int (*pp)[3] = ia;      //行指针,指向二维数组的一行,[]中的数字表示每一行的元素个数
   cout << pp[1][1] <<endl;  //通过二级指针去数组元素  pp[1][1] <=> *( *(pp+1) +1 )
  
   行指针可以描述指向数组的元素个数,以行为单位,加1就是指针指到下一行
   打印数组在内存中地址
  
   int (*p1)[3] --> p1的类型是int[3]  p1+1,走3个int,一个数组的长度
   int ** p2    --> p2的类型是int*    p2+1,走1个int
  
8、char* names[100]; 声明一个数组,每个元素类型是char*
   chat* names[3] = {"liucy","huxz","tangliang"};  //这样的声明更清晰的说明是char的二维数组
   for(int i = 0 ; i < 3 ; i++){
      cout << names[i] <<endl;             //打印每个元素
   }
  
9、void*
   任何类型的变量的地址都可以把地址存进来
   通用指针的存储,不能做任何运算,是纯粹的存储地址而用
  
10、const与指针
   const int *p  常量指针 不能通过指针改变变量的值  const离int近,值不能改
   int* const p  指针常量 指针不能改,指向的对象是固定的,但可以通过指针改变变量的值
  
11、指针的要求
   指针的声明和基本运算
   数组与指针的关系,结构和指针的关系,字符指针的用法
   堆空间及危险用法
  
12、引用
    引用就是一个变量的别名  int &iR= i;  //给i起的别名iR
    引用声明的时候必须初始化(与一个变量保持关联关系),一旦赋值,就不能把别名再给别的变量了
   
    int iL = 100;
    iR = iL; // 相当于把i的值改变了,iR还是i的别名
   
13、引用的使用
    以引用的形式传参数 fn(int &a)
    在函数内部的操作就是对此实参进行操作
   
    一般情况下  (1)在真的想改变实参的值的时候
                (2)在实参的大小比较大的时候,传引用,这样系统不生成临时变量,减小耗费内存
    的时候传引用。
   
    fn(const int &a) 这样传引用,不会创建临时变量,也不会改变实参的值
   
14、周末项目
   (1)完善项目 把密码用char数组保存
   (2)写一个函数,对所有类型的数组进行排序
        提示:通过函数指针实现对struct传参数
              void* 指针,存储所有类型指针
             
              void sort (int perlen , int *p , int len , void (*order)(int * ,int *)){
                   char *p1 = (char*)p;        //char是基本类型里最小的,可以模拟步长
                   for(int i = 0 ; i < len ; i ++{
                       for(int j = 0 ; i < len ; i++){
                            order(p+i*prolen,p+j*prolen);
                       }   
                   }
              )

1、排序函数
   void order(int* p1, int* p2){
       if(*p1 > *p2){
           int temp = *p1;
           *p1 = *p2;
           *p2 = temp;
       }
   }

void sort (int *p , int len , int perLen , void (*pOrder)(void* , void*)){
       char* pt = (char*)p;
       for(int i = 0 ; i < len ; i++){
            for(int j = i ; j < len ; i ++){
                  pOrder(pt+i*perLen , pt+j*perLen);
            }
       }
   }                       
  
   (1)将输入参数int* -> void*  (void* 可以存储任何类型的地址,可以通用 )
   (2)表示数组的第i个元素,事先要知道数组每个元素的大小(参数传入)
         i*perLen => 当不知道指针类型时,表示走一步,应越过的字节数
         p+i*perLen => 表示第i个元素的地址
   (3)具体的数组要有具体的排序方法
        调用函数,当不知道函数名时,可以通过函数指针调用
       
    ==================================================
                     sort.h
    ==================================================                    
    void sort( void * p , int len , int perLen ,
           void (*pOrder)(void * , void * ) );
    ==================================================
                     sort.cc
    ==================================================
    void sort( void * p , int len , int perLen ,
               void (*pOrder)(void * , void * ) ){

char* pt = (char*)p ;
        for( int i = 0 ; i < len ; i++ ){
           for( int j = i ; j < len ; j++ ){
             pOrder(pt+i*perLen,pt+j*perLen ) ;
           }

}
    }                    
    ==================================================
                     main.cc
    ==================================================
    #include <iostream>
    #include "sort.h"
    using namespace std;

void orderInt( void * p1 , void * p2 ){
      int * t1 = (int*)p1 ;
      int * t2 = (int*)p2 ;
      if( *t1 > *t2 ){
        int temp = *t1 ;
        *t1 = *t2 ;
        *t2 = temp ;
      }
    }

struct Person{
      char name[ 40 ] ;
      int age ;
      int id ;
    } ;

void orderByAge( void * p1 , void* p2 ){
      Person * t1 = (Person*)p1 ;
      Person * t2 = (Person*)p2 ;
      if( t1->age > t2->age ){
         Person t = *t1 ;
         *t1 = *t2 ;
         *t2 = t ;
      } 
    }

void orderById( void *p1 , void* p2 ){
      Person* t1 = (Person*)p1 ;
      Person* t2 = (Person*)p2 ;
      if( t1->id > t2->id ){
         Person t = *t1 ;
         *t1 = *t2 ;
         *t2 = t ;
      }
    }

void orderByName( void * p1 , void* p2 ){
       Person* t1 = (Person*)p1 ;
       Person* t2 = (Person*)p2 ;

if( strcmp( t1->name , t2->name ) > 0 ){
          Person t = *t1 ;
          *t1 = *t2 ;
          *t2 = t ; 
       }
    }
    int main(){
       int ia[] = { 3,1,6,3,6,8,3,468,89 };
       sort( ia , 9, sizeof(int), orderInt );

for( int i = 0 ; i < 9 ; i++ ){
          cout<<ia[i] <<" " ;
       }
       cout<<endl;

Person pers[ 3 ] ;
       pers[0].id = 1 ;
       pers[0].age = 29 ;
       strcpy( pers[0].name , "liucy" ) ;

pers[1].id = 2 ;
       pers[1].age = 28 ;
       strcpy( pers[1].name , "huxinzhe" ) ;

pers[2].id = 3 ;
       pers[2].age = 26 ;
       strcpy( pers[2].name , "xuehailu" ) ; 
 
       sort( pers , 3 , sizeof(Person), orderByAge );
       for( int i = 0 ; i < 3 ; i++ ){
          cout<<pers[i].name <<","<<pers[i].age<<",";
          cout<<pers[i].id<<endl ;
       }

sort( pers, 3, sizeof( Person) , orderById ) ;
       for( int i = 0 ; i < 3 ; i++ ){
          cout<<pers[i].name <<","<<pers[i].age<<",";
          cout<<pers[i].id<<endl ;
       }

sort( pers , 3 , sizeof( Person ) , orderByName );
       for( int i = 0 ; i < 3 ; i++ ){
          cout<<pers[i].name <<","<<pers[i].age<<",";
          cout<<pers[i].id <<endl;
        }
  
 
        return 0 ;
      }
                    
   
   
2、面向对象
   封装:对象表示
   继承:更好的代码重用
   多态
  
   对象的组成 : 属性   成员变量
                 行为   函数
                
   面向过程的表示方法:
       数据与函数分离,关系松散
       封装的作用,把数据和函数封装到一起,保证数据专用
      
  全局函数:在类外面的函数,要使用成员变量,要通过参数传进来
  成员函数:在类内,可直接使用自己类的成员变量
 
  对于类的变量的初始化:
       Person p ;
       strcpy(p.name , "liucy");
       p.age = 23;
       p.speak();
  对成员变量和成员函数的使用都要通过类的对象
 
  public 关键字,表示在其他地方可以使用
  默认是私有的,在main函数中不能使用
 
  成员变量和成员函数依赖于类的对象(实例)
 
  类型是对对象的描述
  对象是类型的实例
 
  对象自己的成员函数访问自己的成员变量 
 
  什么是类?类由什么组成?
  怎么使用类?及类和对象的关系?
  成员变量和成员函数归谁所有?
 
  面向对象的方法写程序
  (1)首先写一个类,描述对象
       用变量表示属性,函数表示行为
  (2)调用函数
       创建一个类的对象,通过对象调用函数

1、类型封装
   类 --> 对象
   描述 : (1)属性
           (2)行为    ---属性和行为是属于类的
   创建对象。
  
2、构造函数 --- 初始化对象
   (1)构造函数名字必须与类名一样
   (2)构造函数不能写返回类型
  
   构造函数在创建对象时,系统自动调用
  
   构造函数允许重载,按用户要求,适应多种情况
   当类中一个构造函数都没有的时候,系统提供默认无参的构造函数
   但如果在类中定义了一个构造函数,系统就不提供默认的了,所以,建议,在写构造函数时,都要写一个无参的构造函数
  
3、对类的安全的定义
   变量 -> 私有 -> private  保护变量,防止外界随意修改,只能在类的内部使用(只能被自己的成员函数使用)
   函数 -> 公有 -> public
  
   为保证私有变量也能为外界访问,在类内部提供set,get方法
   set方法没有返回值,但要求有参数
   get方法肯定有返回值,没有参数
  
4、定义类的步骤
   (1)写属性的行为
          成员变量   函数
   (2)成员变量--> private
         成员函数 --> public
    (3)特殊函数
       构造函数,建议写2个。一个有参数的,一个无参的
       get,set函数,一个成员变量对应一对get,set函数,是外界访问此变量的唯一途径
            对于setXXX函数,没有返回值,有参数,参数的类型与被赋值的属性类型一致。
            对于getXXX函数,没有参数,有返回值,返回值的类型与输出的属性类型一致。
       类的行为
      
5、封装
   定义类的过程就是封装
  
练习:封装一个account类型
                属性:id , password ,name ,balance
                行为:save , withdraw , query
               
6、把account类拆成多文件结构
   (1)方便快速浏览整个类定义
   (2)使用方便,包含头文件即可
  
   long Account::getId(){...........}
   在函数实现时,函数前把类名加上,确定函数的所有权,避免2个类中有同名的函数,编译出错。
   " :: "称为域访问控制符。
  
7、Person per ;  创建了一个对象,系统调用构造函数。
   Person *p = NULL ; 声明一个类的指针,系统是不会调用构造函数的
  
   Person * p = NULL;
   p = new Person ; 在堆中申请一个类空间
   delete p;
   在堆中的数据没有名字,只能通过指针访问类对象,访问类的成员变量:
   (*p).sayHello();
   p->sayHello();
  
   Person ps[5];声明一个Person类型的数组,会调用5次构造函数
                数组在声明的时候,系统会为其分配空间
                并且在声明数组的时候,没有机会指定构造函数,只会调用无参的构造函数
               
   当一个类定义中没有无参的构造函数,但要声明一个类的数组时,可以声明一个指针数组
   Person *ps[5];  ---声明指针的时候,类对象没有创建,数组中每个元素都是Person类型的指针,达到:
   (1)不用构造函数
   (2)实现使用对象
  
   for(int i = 0 ; i <5 ; i++){
        ps[i] = new Person(i , 20+i);   //用循环初始化每个指针
   }
   for(int i = 0 ; i < 5 ; i++){
        delete ps[i];                   //释放指针指向的空间
        ps[i] = NULL ;
   }
  
8、课堂练习:
   要求:main()函数中不能写代码,在运行程序时,打印“Hello World”
   答案:全局变量的初始化操作在main函数执行之前就已经初始化了。因此,可以写一个全局变量的类,其无参构造函数写输出语句。
         然后声明一个类的全局对象。
        
9、在构造函数中,当成员变量名称和形参名称相同,避免冲突的方法:
   在每个对象内部都有一个名为this的指针,指向自己,使用自己的成员变量 this->name
  
10、析构函数
    当对象的生命周期结束,系统要回收空间,会自动被调用
    申请的所有资源(new char[20]),在析构函数中释放  
    若对象是在main函数中的变量,在main函数结束之后,才会调用析构函数
    若对象是一个函数中的局部变量,在函数返回时,调用析构函数
   
    析构函数调用 : 对象生命周期结束,系统自动调用析构函数
                    可以把释放资源的代码写在析构函数中
                   
    析构函数的写法:构造函数前加 “~”
                    不能重载,不能有参数
                   
    若不写析构函数,系统会提供默认的析构函数
   
    当类中用到了系统空间:new内存,打开文件
    就需要写析构函数,释放资源

11、作业:(1)利用面向对象的思想实现栈结构,并自己写main函数测试。

(2)把原来的银行系统改成面向对象的形式。

C++笔记 3的更多相关文章

  1. git-简单流程(学习笔记)

    这是阅读廖雪峰的官方网站的笔记,用于自己以后回看 1.进入项目文件夹 初始化一个Git仓库,使用git init命令. 添加文件到Git仓库,分两步: 第一步,使用命令git add <file ...

  2. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  3. SQL Server技术内幕笔记合集

    SQL Server技术内幕笔记合集 发这一篇文章主要是方便大家找到我的笔记入口,方便大家o(∩_∩)o Microsoft SQL Server 6.5 技术内幕 笔记http://www.cnbl ...

  4. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  5. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  6. NET Core-学习笔记(三)

    这里将要和大家分享的是学习总结第三篇:首先感慨一下这周跟随netcore官网学习是遇到的一些问题: a.官网的英文版教程使用的部分nuget包和我当时安装的最新包版本不一致,所以没法按照教材上给出的列 ...

  7. springMVC学习笔记--知识点总结1

    以下是学习springmvc框架时的笔记整理: 结果跳转方式 1.设置ModelAndView,根据view的名称,和视图渲染器跳转到指定的页面. 比如jsp的视图渲染器是如下配置的: <!-- ...

  8. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  9. 2014年暑假c&num;学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  10. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

随机推荐

  1. javacomm64位用不了,可以使用RXTXcomm for x64

    安装完后把导入包名改一下就行了! 附上读串口代码: /* * @(#)SimpleRead.java 1.12 98/06/25 SMI * * Copyright (c) 1998 Sun Micr ...

  2. 【BZOJ 2730】 &lbrack;HNOI2012&rsqb;矿场搭建

    Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一 ...

  3. Visual Studio 2012中编写C程序

    换了win7系统后,突然发现VC++6.0不兼容了,我听说有的同学的行,反正我是不行. 那就用VS2012呗.... 我们来看看怎么用: 打开文件->新建->项目,新建一个项目 选择win ...

  4. WM&lowbar;CLOSE、WM&lowbar;DESTROY、WM&lowbar;QUIT学习总结(点击关闭按钮会触发WM&lowbar;CLOSE消息,DestroyWindow API会触发WM&lowbar;DESTROY和WM&lowbar;NCDESTROY消息,MSDN上写的很清楚)

    WM_CLOSE:关闭应用程序窗口 WM_DESTROY:关闭应用程序 WM_QUIT:关闭消息循环 只有关闭了消息循环,应用程序的进程才真正退出(在任务管理器里消失). win32应用程序的完整退出 ...

  5. Android ListView在增加HeaderView之后使用getLocationInWindow和getLocationOnScreen获得值不正确的解决方法

    近日遇到一个很恶心的问题,把解决方法放到空间里来分享给大家: 问题发生的条件: 1)ListView 控件中使用addHeaderView,为其添加了一个header view.(基本常识:heade ...

  6. 【Ubuntu】Ubuntu设置和查看环境变量

    [Ubuntu]Ubuntu设置和查看环境变量    转载 https://blog.csdn.net/White_Idiot/article/details/78253004 1. 查看环境变量 查 ...

  7. mono部分源码解析

    一.源码结构 这里仅列举几个重要的目录:mcs:    mcs: Mono实现的基于Ecma标准的C#编译器.    class: CLI的C#级的实现.类似于Android中的Java层,应用程序看 ...

  8. C&num; 使用Vici WinService组件来创建Windows服务

    Vici WinService 是 Windows平台下使用C#开发的轻量级用于创建,删除服务的类库,您只需简单的几行代码即可实现多线程异步服务的创建,删除,运行 废话不多说,直接上代码 /***** ...

  9. Spring cloud config-client 爬坑

    配置文件 找不到属性 Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'from' in st ...

  10. Oracle数据库基本操作(四) —— PLSQL编程

    Procedure Language 实际上是Oracle对SQL语言的能力扩展,让SQL语言拥有了if条件判断,for循环等处理. 一.PLSQL基本语法 DECLARE -- 声明部分 变量名 变 ...