zoukankan      html  css  js  c++  java
  • C++笔记 2


    1、程序由函数组成,函数只完成自己特定的功能即可
       把函数声明写在头文件里(想使用函数时,可直接导入头文件,调用函数),把函数实现写在".cc"文件中
       把多个".cc"文件编译成可执行文件 ->分别编译成".o"文件,再连接到一起
      
    2、值传递
       函数中的参数传递是值传递,形参只是实参的一份拷贝数据,在函数中改变形参的值,对实参无影响
      
    3、作业分析:显示层(与用户的交互)
                 操作数据(完成业务逻辑) biz层
                 数据(id , password , balance )                       
      
      
    Bank实现代码 
    ================================================================
                biz.h
    ================================================================
    //operation

    /* p : Password of account .
     * b : balance of account .
     * return : id of account .
     */
    long create( int p , double b );
    void save( double sum ) ;

    /*
     * return : 0 success , otherwise -1 returned .
     */
    int withdraw( int p , double sum ) ;
    double query( int p ) ;
    long generateId();

    ================================================================
                biz.cc
    ================================================================

    #include <iostream>
    using namespace std;
    static long id ;
    static int passwd ;
    static double balance ;
    #include <iostream>
    using namespace std;
    long generateId(){
     static int id = 1 ;
     return id++ ;
    }
    long create( int p , double b ){
     id = generateId();
     passwd = p ;
     balance = b ;
     return id ;
    }
    void save( double sum ){
     balance += sum ;
    }
    int withdraw( int p , double sum ){
     if( p != passwd ){
      cout<<"invalid password ." << endl;
      return -1 ;
     }
     if( balance < (sum + 10) ){
      cout<<"no enough money ." << endl;
      return -1 ;
     }
     balance -= sum ;
     return 0 ;
    }
    double query( int p ){
     if( p != passwd ){
      cout<<"invalid password " << endl;
      return -1 ;
     }else{
      return balance ;
     }
    }
     

    ================================================================
                menu.h
    ================================================================
    int showMenu();

    void createMenu();
    void saveMenu();
    void withdrawMenu();
    void queryMenu();
    ================================================================
                menu.cc
    ================================================================
    #include "biz.h"
    #include <iostream>
    using namespace std;

    int showMenu(){
     cout<<"create ------> 1 " << endl;
     cout<<"save   ------> 2 " << endl;
     cout<<"withdraw ----> 3 " << endl;
     cout<<"query -------> 4 " << endl;
     cout<<"exit --------> 0 " << endl;
     cout<<"enter your choice >";
     int c ;
     cin>>c ;
     if( !cin ){
      return -1 ;
     }else{
      return c ;
     }
    }

    void createMenu(){
     int passwd ; 
     double balance ;

     cout<<" enter password >";
     cin>>passwd ;
     cout<<" enter balance >";
     cin>>balance ;

     long id = create( passwd , balance );
     cout<<"======================"<<endl;
     cout<<"create account ok , id = " << id <<endl;
     cout<<"======================"<<endl;
    }
    void saveMenu(){
     double sum ;
     cout<<" enter sum >";
     cin>>sum ;
     
     save( sum ) ;

     cout<<"======================"<<endl;
     cout<<"save money ok "<<endl;
     cout<<"======================"<<endl;
    }
    void withdrawMenu(){
     int passwd ;
     double sum ;
     cout<<" enter password >";
     cin>>passwd ;
     cout<<" enter sum >";
     cin>>sum ;

     int ret = withdraw( passwd , sum ) ;

     if( ret == 0 ){
      cout<<"========================"<<endl;
      cout<<"withdraw successful . "<<endl;
      cout<<"========================"<<endl;
     } 
    }
    void queryMenu(){
     int passwd ;
     cout<<" enter password >";
     cin>>passwd ;

     double ret = query( passwd ) ;
     if( ret != -1 ){
        cout<<"============================"<<endl;
        cout<<"BLANCE : $ " << ret << endl;
        cout<<"============================"<<endl;
     }else{
        cout<<"============================"<<endl;
        cout<<"invalid password "<<endl;
        cout<<"============================"<<endl;
     }
    }
    ================================================================
                main.cc
    ================================================================
    #include <iostream>
    #include "menu.h"
    using namespace std;
    int main(){
     int c = 0 ;
     do{
      c = showMenu();
      if( c == -1 ) { break ; }

      switch( c ){
        case 1 :
       createMenu();
       break;
        case 2 :
       saveMenu();
       break;
        case 3 :
       withdrawMenu();
       break;
        case 4 :
       queryMenu();
       break;
        case 0 :
       cout<<"===================="<<endl;
       cout<<"Good Bye "<<endl;
       cout<<"===================="<<endl;
       break;
        default :
       cout<<"===================="<<endl;
       cout<<"invalid option, try again.";
       cout<<endl;
       cout<<"===================="<<endl;
       break;
      } 
     }while( c != 0 );
     return 0 ;
    }
    ================================================================


                
    4、数组
       (1)声明数组    <元素类型> 数组名[元素个数]   int intArray[100]; -->intArray 是个集合,有100个元素,每个元素都是int类型的
       (2)初始化数组 
       (3)使用        通过数组的下标来访问数组中的元素,下标从0开始  intArray[0]=100; -->intArray数组中的第一个元素赋值为100
      
       数组声明时,元素个数必须是常量表达式
       数组声明带有初始化,则可直接为数组赋值
       在数组声明时,必须指明数组长度,若在声明时候初始化,数组长度可省
       int a1[2]={100,200}; 长度2
       int a2[] = {5,6,7}; 长度3
      
       对于数组中的元素个数,比声明时的多,则会报错,这样的越界访问,对整个程序来说会有很严重的后果!!!
                             比声明少,系统会把余下的没有定义数据的元素初始化为0
                         
       不初始化的数组,其中的元素数据为随机数
      
       下标工作的原理:
               表示编号,还表示当前元素相对于数组起始位置的偏移量
               计算机通过偏移量找到元素在内存中的位置
              
    5、数组的排序
       选择排序:找出最小的放在第一个位置
                 数组元素有n个,需要找n-1次,需要比较n-i次(i为开始元素的位置)
                
    6、多维数组
        二维数组;一个数组中的每个元素是个数组
                声明: int iA[5][10];  -->“5”代表数组有5行,“10”代表数组有10列
                       声明时,第一维可以省略!
                确定一个元素需要2个下标
               
    7、结构
       用户自己定义的一组数据类型
       声明结构时,编译器不会分配空间,在声明一个结构的变量的时候才会为其分配空间
       结构中的成员是多个简单类型组成的
       用 “结构名.成员名”来操作其中的成员变量
       strcpy(p.name,"huxz");为char数组赋值
       结构类型的变量间也可以相互赋值
      
       结构的大小就是所有成员的大小之和(每个成员的大小必须是int类型的整倍数,当不够时,会自动补齐)
       Unix上还要求,结构的大小是结构的最大的成员的整倍数
       size(of)  计算结构大小  

    作业:把银行系统用结构改写,要求可以开多个账户(定义一个account类型的数组保存)
          struct account{
               long id;
               int password;
               double balance;
          }
         
          create(int password,double balance);
          void save(int id , double sum);
          int withdraw(int id,int password,double sun);
          double query(int id,int password);

    1、变量的存储
       (1)内存是一块空间,把其中的每个字节做了编号,为了以后计算机能通过编号找到数据
       (2)编址方式:绝对编址(在整个程序中使用),相对编址(字节相对于逻辑0偏移量,在进程中使用)

    2、取变量地址
       (1)"&"  &i 表示取内存中i的地址
            地址的编址用十六进制表示
       (2)逻辑0在代码区
            全局变量在数据区,地址的编址是大于0的
            局部变量在栈区,地址的编址是小于0的
       
    3、数组、结构的地址
       (1)数组中的数据在内存中是连续存储的。 数组中每个元素的地址相差的值应为数组元素类型的大小。
       (2)结构的地址:
            结构的空间是连续的。
            结构的起始地址与第一个成员变量的地址是一样的。

    4、存储地址—
       指针:存储变量的地址
       指针的类型由将要保存的地址的变量类型决定
       int*只能保存int变量的地址
       指针赋值一定要是同类型的指针才能相互赋值!
      
    5、指针的运算
       (1)指针和指针之间的运算
          “+”,“*”,“/” 指针与指针间是不能做这些运算,没有意义!
          “-” 可以做减法运算,以“sizeof(指针类型)”作为计算单位的!    注意:要同类型的指针才能做此运算,不同的话,会对运算单位产生歧义。
      (2)指针和数字之间的运算(加、减都可以)
          int i = 100;
          int * p = &i;
          打印 p+1  -> 相当于在地址上加4,因为存储的变量是int类型的
               p+2  -> 相当于在地址上加8
      
    6、通过指针访问所指向的变量
       *p 代表指针p所指向的变量  *p <=> i
      
       指针在声明的时候,即初始化
       int * p = NULL;  表示没有明确指向,不能 *p ,会出现 “段错误”的异常  -->空指针
      
       段错误原因 (1)空指针
                  (2)数组越界
                  (3)递归的条件不正确
                 
    7、课堂练习
        用指针打印出数组中个元素的值
        #include <iostream>
        using namespace std;

        int main(){
           int ai[6]={34,4,12,67,34,2};
           int *p = &ai[0];
           for(int i = 0 ; i < 6 ; i++){
               cout <<"a[" << i << "]=" <<*(p+i) << endl;
           }
           return 0;
        }
       
        int *p = ai ; 数组的本质就是用指针实现的,数组的名字就代表数组的首地址(起始地址)
                     数组的名字是指向数组首地址(a[0])的指针
                    
        ai 数组名,就是指向数组首地址的指针,可以用下标取元素,也可以把数组名当指针来访问元素   *(ai+n)
        p  指针名,也是指向首地址的指针,也可以通过下标(像数组名一样)访问数组元素   
        p[n] <=>  *(p+n)
       
    8、结构指针
       struct person{
            int id;
            int age;
       }
      
       int main(){
            person per = {1,20};
            person* p = &per;
            cout << "per.id ="<<per.id<<endl;  //通过结构名取成员变量
            cout << "per.age=" << per.age <<endl;
            cout <<"======================"<<endl;
            cout << "(*P).id=" << (*P).id <<endl;   //通过指针访问结构的成员变量 
            cout << "(*P).age=" << (*P).age <<endl;  //   (*p).id  <=>  p->id   只有结构指针可以这样使用 
            cout <<"======================"<<endl;
            cout << "p->id=" << p->id <<endl;  
            cout << "p->age=" << p->age <<endl;
          
            return 0;
       }
      
    9、指针的地址
       指针变量在内存中占4个字节(与类型无关,因为保存地址的指针只保存地址)
       保存int型指针(int* p = &i)的地址用int**保存(int** pp = &p)
      
       #include <iostream>
       using namespace std;

       int main(){
         int i = 0 ;
         int * p = &i ;
         int ** pp = & p ;

         cout<<"&i = " << &i << endl;
         cout<<"p = " << p << endl;
         cout<<"&p = " << &p << endl;
         cout<<"pp = " << pp << endl;
         cout<<"&pp = " << &pp << endl;

         cout<<"i = " <<i << endl;
         cout<<"*p = " << *p << endl;
         cout<<"*pp = " << *pp << endl;
         cout<<"**pp  = " << **pp << endl;
     
         return 0 ; 
        }
       
    执行结果:
    &i = 0xffbffbec
    p = 0xffbffbec
    &p = 0xffbfbe8
    pp = 0xffbfbe8
    &pp = 0xffbffbe4
    i = 0
    *p = 0
    *pp = 0xffbffbec
    **pp = 0
      
         pp  ->  p  ->  i   指向关系
          pp=&p     p=&i
          *pp=p     *p=i       **pp=*p=i

    1、数组指针声明的时候不用初始化,声明以后就指向数组的首地址了,以后不允许改变,所以,数组指针可以认为是一个常量,一旦赋值就不能改变

    2、char数组
       (1)打印char数组的名字即打印数组的内容
       (2)对于字符数组,''是结束标志 
            字符 '' = 数组0  可以认为字符''的ASCII码就是0
            要保存5个字符,就要把字符数组长度声明为6
      
       (3)strcpy()和memset()
            给一个字符串数组赋值 strcpy(),自动为字符串补 ''
            在使用strcpy之前,要调用memset(str,0,sizeof(str));初始化一片内存
                                       str  ->   初始化内存的起始位置
                                       0    ->   初始化的值 (初始化为0,清除垃圾数字)
                               sizeof(str)  ->   初始化空间的大小
        (4)strlen(str)
           计算实际存储的字符个数,不包括''
       
        (5)strcmp(str1,str2)
           比较2个字符串是否相等
           实际比较的两个字符串的ASCII码的大小,返回0则内容一样
          
        (6)字符串的拆分  strtok(a,b);
           a、被拆分的字符串名字,当此处是NULL时,表示要拆分的不是新串
           b、分隔符号
           此函数调用一次,拆分一次
           当此函数返回NULL时,则表明拆分完毕
          
           "Hello World"叫字符串常量,存储在data数据区里,类型就是char*
               其值是一个地址,指向数据区里的一块空间
               数据区里的空间保存的内容就是"Hello World"
          
           char line[50];
           strcpy(line,"1:liucy:20:male");
          
           char *p = strtok(line , ":");  //p指针指向的变量
           cout << p << endl;
           while(p != NULL){
               p = strtok ( NULL , ":" );
               cout << p << endl;
           }
          
          
        (7)  strcpy(name,"1234"); //name是个变量,可以改变
               strcpy(p,"1234"); //p是个指针,指向一个字符串,是常量,不能改变 
               p = "1234"; //这样是正确的
               指针指向的是常量,不能通过指针改其值,若指向变量,则可以通过指针改变变量的值
              
        (8)字符串连接 strcat(sub,"world");
             连接条件:sub字符串数组的剩余长度要大于连接的字符串长度
            
             char *p = "Hello";
             strcat(p,""World); //error 指针指向一个常量,不能改变,所以指针后面不能添加东西
            
    3、通过指针传递参数
       通过传递地址。改变变量的值
           
            #include <iostream>
            using namespace std;

            void fn (int *pa){
               *pa = 2 * (*pa);  //*pa是指针pa指向的变量的值,在此做的操作,会对变量造成永久的改变
            }

            int main(){
               int a = 100;
               fn(&a);          //把a的地址传个fn函数
               cout << a << endl;
               return 0;
            }
           
    4、课堂练习
       字符串  “1:huxinzhe:20:male”
       要求:声明一个结构
               Person{
                 int id;
                 char name[50];
                 int age;
                 char gender[10];
               }
       拆分赋值 提示:atoi可以把字符串转换成int型
      
       #include <iostream>
       #include <string.h>
       #include <stdlib.h>
       using namespace std;

       struct Person{
          int id;
          char name[20];
          int age;
          char gender[10];
       };

       int main(){
           Person per;

           char line[50];
          
           while(true){
                cout << "enter a string>";
                cin>>line;

                if(strcmp(line,"exit")==0)
                    break;
                char *p = strtok(line , ":");
                per.id = atoi(p);
               
                p = strtok(NULL , ":");
                strcpy(per.name,p);
               
                p = strtok(NULL , ":");
                per.age = atoi(p);
               
                p = strtok(NULL , ":");
                strcpy(per.gender,p);

                cout <<"per.id     = " <<per.id << endl;
                cout <<"per.name   = " <<per.name << endl;
                cout <<"per.age    = " <<per.age << endl;
                cout <<"per.gender = " <<per.gender << endl;

           }
           return 0;
       }
      
    5、内存管理
       堆(heap):动态的内存申请与释放
       堆空间不能通过像( 数据区,栈)变量访问空间,要使用指针保存地址
      
       (1)堆空间的管理  new / delete
            new int
            new Person
           
            new 操作符返回值是地址,用指针保存
            int *p = new int;  //在堆空间中申请4个字节
            *p = 100;          //赋值
            delete p;          //释放空间
           
        (2)动态申请空间,对内存的使用变的方便,能更好的控制对内存的占用
             动态内存的指针不能重复赋值,这样会造成内存丢失
             释放空间后,还可以通过指针访问原来的数据。
             释放空间后,还可以再次通过指针赋值,释放的意思就是表示曾经申请的内存的标记位更改,别人可以使用
             这样会造成过期的指针更改重要数据,建议在释放指针以后 ,把指针赋值为NULL ,确保数据安全
             delete p ;
             p = NULL :
            
         (3)在申请空间的同时初始化
            int *p = new int(123);  申请4个字节大小,保存数字“123” 
           
        (4)int *p = new int[10];  一次在堆里申请10个int,并且申请的内存是连续的。
            *(p+1) , p[1]  都能取到下一个数据
            此时的*p就是第一个元素的值
            在释放的时候 delete[] p;  p = NULL; 确保释放的是多个指针 
           
         (5)在堆空间里申请结构
            Person *p = new Person;
            p->id = 1;
            // (*p).id = 1;
           
    6、  传递参数
         最好传地址,节省内存(因为不用进行入栈,出栈操作,直接用指针访问数据)
         在参数前加const,可避免在函数内部对数据进行非法修改
        
         当一个数组做参数时,编译器会自动把数组的首地址传个函数
         所以在函数内部对数组的更改,就是通过指针对数组中元素的永久性更改
        
    7、数组,存数据个数不限,通过一个函数insert()存数据,disp()打印数组
      

  • 相关阅读:
    Silverlight 4 新特性之NotificationWindow
    如何理解JavaScript原型
    惹恼程序员的十件事
    浅谈HTTP中Get与Post的区别
    asp中Access与Sql Server数据库区别总结
    SQL208语句
    jQuery源码分析
    3. 在 as 和 强制类型转换之间,优先使用 as 操作符。
    揭秘10项必学的.NET技术
    如何设置远程访问SQL Server2005
  • 原文地址:https://www.cnblogs.com/fickleness/p/3154462.html
Copyright © 2011-2022 走看看