• 指针和结构体


    结构体的认识

    • 结构体的定义
      将不同数据类型的数据对象组织在一起。
    • 结构体在c中和C++不同
      在C中的结构体只能自定义数据类型,结构体中不允许有函数,而C++中的结构体可以加入成员函数。C中的结构体只涉及到数据结构,而不涉及到算法,也就是说在C中数据结构和算法是分离的,而到C++中一类或者一个结构体可以包含函数(这个函数在C++我们通常中称为成员函数),C++中的结构体和类体现了数据结构和算法的结合。

    结构体的定义、初始化

    • 一般结构体
    struct test//定义一个名为test的结构体 
    { 
     int a;//定义结构体成员a 
     int b;//定义结构体成员b 
    }; 
    test pn1;//定义结构体变量pn1 
    test pn2;//定义结构体变量pn2 
    
    pn2.a=10;//通过成员操作符.给结构体变量pn2中的成员a赋值 
    pn2.b=3;//通过成员操作符.给结构体变量pn2中的成员b赋值 
    test* point;//定义结构指针 
    point=&pn2;//指针指向结构体变量pn2的内存地址
    
    point->a=99;//通过结构指针修改结构体变量pn2成员a的值 
    • 含有指针
    struct Student{   
            char *name;   
            int score;   
            struct Student* next;   
        };  
    //重点记住,在结构体中含有指针需要为指针指定指向的内存地址
    Student stu,*pStu;
    //结构体成员需要初始化
    stu.name = new char;//stu.name = (char*)malloc(sizeof(char));
    strcpy(stu.name,"ddd");
    stu.score = 99;
    //结构体成员需要初始化
    Pstu = new Student;//Pstu = malloc(sizeof(Student));
    Pstu->name = new char//在用结构体指针的=时候先为整个结构体分配内存,然后再为结构体内部的指针申请内存。
    
    //最后在根据那个地方new,然后进行delete
    delete stu.name;
    stu.name = null;
    delete Pstu.name;
    Pstu->name = null;
    delete Pstu;
    Pstu = null;
    //记住最后一定将指针赋值为null,防止指针乱指,成为野指针。
    View Code
    • 结构体嵌套
    struct Data
    { 
    int year;
    int month;
    int day;
    }
    struct stu /*定义结构体* / 
    { 
        char name[20]; 
        long num; 
        struct data birthday; /嵌*套的结构体类型成员*/ 
    } ;
    
    //结构体初始化
    struct stu a;
    a.name = "gaoqinag";//在声明的时候自动在栈为数组进行内存分配
    a.birthday.year = 2013;//对于嵌套的结构体同样适用,自动 申请内存。
    a.birthday.month = 12;
    View Code

    这样的结构体,成员指针或者分配内存,或者指向常量区,不然它们就都是野指针;分配内存的话,就要释放,分配内存的时候,是从外向里,即先分配结构体的指针,再分配成员指针,释放的时候,是从里向外,先释放成员指针,再释放结构体指针,顺序不能错的。总之每个malloc都要对应一个free,每一个new要对应一个delete!

    结构体数组

    structdata/*定义结构体类型*/ 
    { 
         intday,month,year; 
    };
    structstu/*定义结构体类型*/ 
    { 
         char name[20]; 
         long num; 
         struct data birthday; 
    };
    
    main() 
    {
         inti; 
         structstu*p,student[4]=
         {
             {"liying",1,1978,5,23},
             {"wangping",2,1979,3,14}, 
             {"libo",3,1980,5,6},
             {"xuyan",4,1980,4,21}
         }; 
    /*定义结构体数组并初始化*/ 
         p=student;/*将数组的首地址赋值给指针p,p指向了一维数组student*/ 
         printf("
    1----Outputname,number,year,month,day
    "); 
         for(i=0;i<4;i++)/*采用指针法输出数组元素的各成员*/ 
         printf("%20s%10ld%10d//%d//%d
    ",(p+i)->name,(p+i)->num, 
         (p+i)->birthday.year,(p+i)->birthday.month, 
         (p+i)->birthday.day); 
    }
    View Code

    结构体作为函数参数

    • #include<iostream>
      #include<string>
      using namespace std;
      //结构体定义
      struct Student{
       string name;
       int score; 
      };
      int main(){
       Student one;
       one.name="千手";
       one.score=99;
       // 值传递演示
       PrintByValue(one);//100
       cout<<one.name<<endl;
       cout<<one.score<<endl;//验证 score的值是否加一了 //99
      //参数为指针演示
      Student *p=&one; 
       PrintByHand(p);//100
       cout<<one.name<<endl;
       cout<<one.score<<endl;//验证 score的值是否加一了 //100
      //参数为引用演示
      PrintByQuote(one);//101
       cout<<one.name<<endl;
       cout<<one.score<<endl;//验证 score的值是否加一了 //101
       return 0;
      }
      void PrintByValue(Student one){
       cout<<one.name<<endl;
       cout<<++one.score<<endl;//在Print函数中,对score进行加一 
      }
      void PrintByHand(Student *p){
       cout<<p->name<<endl;
       cout<<++p->score<<endl;//在Print函数中,对score进行加一 
      }
      
      void PrintByQuote(Student &one){
       cout<<one.name<<endl;
       cout<<++one.score<<endl;//在Print函数中,对score进行加一 
      }
      View Code
      参数为结构体值

    这种方式值采取的“值传递”的方式,将结构体变量所占的内存单元的内存全部顺序传递给形参。实际上在被调用函数,重新在栈中分配内存,将实参的值,进行赋值,在被调用函数操作时新申请内存的形参,和实参半点关系没有。采用值传递的方式,如果在函数被执行期间改变了形参的值,该值不能反映到主调函数中的对应的实参,这往往不能满足使用要求。因此一般较少使用这种方法。

    • 参数为指针

    这种方式虽然也是值传递的方式,但是这次传递的值却是指针。通过改变指针指向的结构体变量的值,可以间接改变实参的值。并且,在调用函数期间,仅仅建立了一个指针变量,大大的减小了系统的开销。

    • 参数为引用

    形参是对应的结构体类型的引用,虚实结合时传递的是地址,因而执行效率比较高。而且,与指针作为函数参数相比较,它看起来更加直观易懂。因而,引用变量作为函数参数,它可以提高效率,而且保持程序良好的可读性。

    • 引用传递

    上面讲解的是按值传递,按值传递就是将值传递进去,在函数中进行一些列操作,被调用函数中申请分配的内存不会传出来。
    引用传递最重要的目的就是将被调用函数申请的内存进行获取,更准确将是内存的地址。
    在这里讲解一个重点就是在被调用函数申请内存的时候,怎样从被调用函数这个传出这个结构体,这里要从内存分析。
    在被调用函数进行内存分配后需要将内存的地址获取,而内存的地址往往是通过指针获取,另一方面形参中创建一个指针后,要与实参的指针建立联系。单纯进行 stu* p = stu *ptr;这样形参中对p进行操作和实参的*ptr半点关系没有,所以传入的二级指针。

    void GetStu(Student** stu)
    {
    //这里做实验,如果先申请内存,然后在赋值给stu,其实改变stu指向,不再指向实参了,内存还是没有传出去
        //Student *student = new Student;
    //  student->name = "hahh";
    //  student->score = 80;
    //  stu = &student;
    //这里直接获取形参中指向,也就是实参地址,为实参地址分配内存
        *stu = new Student;
        (**stu).name = "ahha";//为实参中地址指向的内存赋值。
        (**stu).score = 80; 
    
    }
    Student *temp;//声明一个结构体指针
    *temp->name = "hah"//程序会报错,没有给结构体指针变量赋值呢。
    GetStu(&temp);
    cout<<(*temp).score<<endl;
    cout<<(*temp).name<<endl;
    cout<<temp->name<<endl;
    delete temp;//记得释放内存
    View Code

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    基于Proxy的小程序状态管理
    还不会正则表达式?看这篇!
    Fundebug前端JavaScript插件更新至1.8.2,修复2个小BUG
    JavaScript深入浅出第1课:箭头函数中的this究竟是什么鬼?
    5种处理Vue异常的方法
    重构:一项常常被忽略的基本功
    SQL Server中使用SQL语句关闭数据库连接和删除数据库文件
    SQL Server使用加密连接SSL/TLS (转载)
    SQL Server使用sp_executesql在存储过程中执行多个批处理
    How to call a stored procedure in EF Core 3.0 via FromSqlRaw(转载)
  • 原文地址:https://www.cnblogs.com/polly333/p/4705668.html
Copyright © 2020-2023  润新知