复杂数据类型,基础知识点1

2019-09-25 20:36栏目:网络编程
TAG:

原创博客,转载请注明出处!

1.字符串

一、数组

1.简介

字符串就是一个字符数组,结尾以''作为标志

一个字符占用一个字节(汉字占用两个字节),从左到右依次存放,在字符串的结尾自动加入一个字节的结束标志''

'a'与"a"的不同:'a'代表一个字符占用一个字节;"a"代表一个字符串占用两个字节.

字符串初始化:char str[10]="abc123!@#";//不能写成char str[10];str="dfh";(初始化声明的时候的=不代表赋值操作,只是初始化)

1> 数组的定义和初始化

# C++提供一些基本的数据类型(int,float,double,char等),但由于程序处理的问题通常较复杂,基本的数据类型不能满足程序需要,因此C++允许用户根据需要自定义数据类型。C/C++的结构体是包含相同/不同数据类型数据项的组合项,关键字struct标识结构体。

2.sizeof(类型名)

  1. 定义

    ① 数组定义了同种类型数据的集合② 定义数组时,数组必须有固定的长度
    
  2. 初始化

    ① 如果在定义数组时,初始化数组,数组元素的个数必须是常量② 如果不在定义数组时初始化,数组元素的个数可以是有确定值的变  量③ 大括号的初始化方式只能在定义时初始化的情况下使用
    

2.结构体类型的声明

sizeof返回的值是无符号的整数

可以用sizeof(a)/sizeof(a[0])计算数组长度

2> 数组的内存存储细节

# 如果在文件开头声明结构体类型,则所有的函数利用该结构体类型定义变量。

3.类型定义(typedef)

  • 为数组分配内存时是从内存的高地址到低地址,而数组元素的存储是从低地址到高地址
  • 数组名为该数组元素在内存中的首地址,是一个指针常量,类型与数组类型一致
  • 可以用&符号来取得每个数据元素的首地址
  • 数组在内存中所占内存的大小可以用sizeof/数组长度来计算

# 如果在函数中声明结构体类型,则只有本函数可以使用该结构体类型定义变量。

typedef int Bool;    //(后面变量名的首字母最好大写)

Bool flag;    //类似与使用了int flag

3> 使用注意

  1 struct 结构体类型名  2 {  3 成员名;  4 };

4.宏定义

  • 数组元素的下标是从0开始的
  • 若要访问数组中的多个元素,一般用for循环
  • 可以通过sizeof来计算数组的长度
  • 可以通过下标直接访问数组,也可以通过指针间接访问数组元素

【定义宏】#define BOOL int

4> 数组名作为函数参数

3.结构体类型变量的定义和初始化

#先声明结构体类型后定义结构体变量

  1 struct Student  2 {  3 int age;  4 char sex;  5 };  6 Student student1={11,‘女’};  

注意:Student是类型名,student1是变量名。声明结构体类型的时候,编译器不分配内存;定义结构体变量的时候,编译器分配内存。

4.引用结构体变量的成员

# 通过成员运算符引用结构体变量的成员

  1 // 定义结构体变量同时初始化  2 Student stu1={11,'女'};  3   4 // 引用结构体变量成员  5 cout<<stu1.age<<endl;

# 通过指向结构体变量的指针引用结构体变量的成员

  1 Student stu1={11,'女'};  2 Student *p = &stu1;  3 cout<<p->age<<endl;

5.用结构体变量和指向结构体变量的指针构建链表

图片 1图片 2

  1 #include <iostream>  2 using namespace std;  3   4 // 结构体类型声明  5 struct Student  6 {  7     int num;  8     int age;  9     Student *next; 10 }; 11  12 void LinkedList() 13 { 14     // 学生结点1 15     Student stu1; 16     stu1.num=101; 17     stu1.age=21; 18  19     // 学生结点2 20     Student stu2; 21     stu2.num=102; 22     stu2.age=22; 23  24     // 学生结点3 25     Student stu3; 26     stu3.num=103; 27     stu3.age=23; 28  29     // 链表头结点; 30     Student *head=&stu1; 31  32     // 学生结点建立链接 33     stu1.next = &stu2; 34     stu2.next = &stu3; 35     stu3.next = NULL; 36  37     // 打印链表 38     Student *p=&stu1; 39  40     while 41     { 42         cout<<p->num<<endl; 43         p = p->next; 44     } 45 } 46 int main() 47 { 48     LinkedList(); 49     return 0; 50 } 51 

View Code

数组和指针不能用宏定义,宏定义中的替换列表为空也是合法的,也可以包含对另一个宏的调用,但宏不能调用它本身.

  • 数组名作为函数参数是传址参数,传递的是数组的首地址
  • 不同通过sizeof来计算数组长度,此时通过sizeof,计算的是该编译器中指针的长度
  • 数组的长度必须通过参数传递

一个数字常量,如果不是0和1,就最好定义成宏.

5> 示例

【带参数的宏】 #define  标示符(x1,x1,…,xn)  替换列表    //参数在替换列表中都要放在圆括号中

  • 步骤
    • 将整型数据10, 6, 23, 8, 15存放在一个数组中
    • 对数组中的元素进行从小到达排序
    • 输出排序后数组中的元素
  • 代码

    #include <stdio.h>//将数组按从小到大排序void sortTheArray(int array[], int count);//逐个输出数组中的元素void printTheArray(int array[], int count);int main(){    //定义一个数组并初始化    int array[]= {10, 6, 23, 8, 15};    //存储数组元素的个数    int count;    //计算数组的个数    count = sizeof / sizeof;    //逐个输出排序前数组中的元素    printTheArray(array, count);    //将数组按从小到大排序    sortTheArray(array, count);    //逐个输出排序后数组中的元素    printTheArray(array, count);    return 0;}//将数组按从小到大排序void sortTheArray(int array[], int count){    //用于循环遍历数组    int i,j,k;    //中间变量,用于交换数组的两个元素    int temp;    //选择排序    for (i = 0; i < count-1; i++)    {        k = i;        for (j = i + 1; j < count; j++)        {            if (array[j] < array[k])            {                temp = array[k];                array[k] = array[j];                array[j] = temp;            }        }    }}//逐个输出数组中的元素void printTheArray(int array[], int count){    for (int i = 0; i < count; i++)    {        printf("%dt", array[i]);    }    printf("n");}
    

5..数组

二、字符串

定义数组时,数组名不能和变量名相同,也不能和系统关键字一样

1> 基本使用

数组的地址就是数组元素的首地址,使用数组名a,代表的就是数组a[]的地址

  • C语言中用字符数组来表示字符串
  • 字符串用%s格式输出
  • string.h文件中声明了字符串相关的操作函数

多维数组:不常用,因为指针数组更加的灵活好用

2> 字符串的结束标志''

无论是一维数组还是多维数组,通过单词const作为数组声明的开始可以把数组变为“常量”;

  • 字符串末尾会有''结束标志,其ASCII码值为0
  • 字符串的操作函数是以''为结束符,若没有结束符,这些操作函数可能会操作其他危险的数据
  • 将字符串常量赋值给char类型的指针变量,则该变量存储的是字符串常量的首地址

(如:const int months[]={31,28,31,30,31,30,31,31,30,31,30,31};)

3> 字符串的输入

6..函数

  1. scanf函数

    ① scanf函数默认以空格、'n'和't'键作为字符串结束的标志② 可以用格式%[^c]来控制以指定字符c作为字符串结束的标志
    
  2. gets函数

    ① 可以输入包含空格和't'的字符串,以'n'作为字符串结束标志② gets函数不会判断上限,仅遇到'n'结束③ 用于接收字符串的缓冲区必须足够大,否则会发生溢出,引发bug
    
  3. getchar函数

    ① 可以通过循环使用getchar函数来输入任意的字符,来组成字符串② 要对末尾的'n'进行处理,将其转化为''
    

在调用函数前,都需要先声明函数,函数声明类似与函数定义的第一行,函数的声明必须与函数的定义一样。

【函数声明】 返回类型  函数名(形式参数);    【编译器只预处理函数,但是不分配内存】

【函数定义】 返回类型  函数名(形式参数)    【开辟内存空间,分配内存给函数,函数入口地址为函数名所在地址】

三、指针

2)从返回值的角度:

1> 基本使用

有返回值:return,(函数有且只能返回一个返回值),可以是基本数据类型和指针等。

无返回值:void,在C89标准中可以忽略返回值类型,UNIX中默认为int,Window VC中为void;在C99标准中不可以忽略返回值类型。

  • 指针变量的内容为内存地址,内存地址是一个机器相关量
  • 指向指针的指针,其内容为所指向指针的地址
  • 通过符号*来访问指针变量所指向地址存储的内容,并可进行修改
  • 指针所指向的内存空间存储变量的类型,与定义指针的类型一致
  • 指针作为函数参数,是一个传址参数
  • 指针可以作为函数参数用于返回函数的执行结果
  • 可以使用指针数组来代替多维数组

3)从参数的角度:

2> 使用注意

带参数:需要告诉编译器参数的类型和数量

int main(int argc,char *argv[]);

int main(int argc,char **argv);

不带参数:参数列表为空,void,可以省略,即int main()或int main(void);就是不需要参数来参与运算。

  • 定义指针变量时的符号*只是一个符号,没有任何实际的意义
  • 定义指针变量时用常量将其初始化,此指针变量的内容将不能被修改
  • 不能间接访问没有初始化的指针变量
  • 若使用一阶指针,不要将地址存储到指针变量所指向的内容
  • 若指针指向的变量类型与定义的类型不一致,可能会影响间接访问的内容
  • sizeof函数的返回值为unsigned long类型,输出格式为%zd
  • 若返回值类型为指针类型,返回值是一个地址

.返回语句

3> 指向函数的指针

return:【return 表达式】如果return中表达式的类型和函数返回的类型不一致,系统会把表达式的类型转换成返回类型

  • 定义格式 void ,这是定义一个无返回值,有一个整型参数的指向函数的指针变量
  • 通常用函数名为指向函数的指针变量赋值,函数名表示函数在内存中存储的首地址
  • 通过指针变量调用函数的两种方式

     ① p; ② ;
    

exit:任何函数中都可以使用,【exit(表达式)】;包含在#include 头文件中。

四、指针与数组

main函数的返回值是状态码,0表示正常结束,非0为异常结束。

1> 基本使用

7..递归

  1. 通常定义一个与数组同类型的指针变量来指向数组的首地址
  2. 通过指针的自增自减运算来间接访问数组元素
  3. 可以用指针变量加上下表来访问数组元素

递归是函数嵌套调用的一种特殊形式,就是当一个函数调用另外一个函数的过程时,另一个函数恰好是它本身。

递归产生的条件:直接或间接的调用它本身,有一个出口(即结束递归的条件),要有一个明显的公理或公式,有规律可循。

1)直接递归调用

2)间接递归调用

注意:

1)递归调用在发生时,消耗了大量的系统资源,反复读写栈内存,CPU资源,会降低系统性能,不可控或深层递归都会造成系统不稳定

2)我们在开发过程中使用的都是浅层递归,如Windows搜索,使用了多线程,浅层递归(一般不超过3层)

3)递归调用也被用于分治算法

4)能不用就不用递归,如:.(){ .|. };.  (.本身是一个函数,()为.函数的参数列表,;前为.函数的定义,最后一个.是调用这个函数)

2> 使用注意

8..迭代

  1. 指针运算是以定义指针类型在内存中所占存储空间的字节数为单位的
  2. 下标绝不会比指针更有效率,但指针有时可能比下标更有效率
  3. 数组名和指针不能等同

迭代法又叫做递推,凡是能用递归来实现的迭代或递推都能实现。

四、结构体

9..指针

1> 基本使用

简单的说,指针就是地址。

内存中的最小存储单元是字节,一个字节有8位,每一位都有自己的地址,指针就是他们的首地址。

基本数据类型的指针,就是他们在内存中的首地址。

构造类型的指针,数组,他的位置就是,数组名称所在内存的首地址,即a[0]的地址或者是数组名。

函数类型的指针,就是函数的入口地址,即函数名所在内存的首地址。

指针变量:和其他基本数据类型的变量类似,特殊的是他是能保存地址的变量。

1.定义指针的时候没有初始化

2.指针指向一个局部变量,当局部变量执行完毕释放后,仍然指向该局部变量的时候(用完置NULL即可)

3.当指针指向一块动态的内存空间时malloc(new)使用完毕被free(delete)释放后,仍然指向该空间,(用完置NULL即可)

  • 结构体定义了多个不同类型数据的集合,是构造类型的一种
  • 结构体可以将某个对象的一组属性组合在一起
  • 结构体的成员可以是基本数据类型,也可以是其他构造类型,如结构体
  • 可以在定义结构体时用大括号为其初始化,用点语法可以实现机构提成员的乱序赋值
  • 结构体数组用于定义具有多个属性的多个同种类型的对象

10.指针和常量的关系

2> 使用注意

常量指针:指针指向了一个常量的指针变量,常量的内容不可以修改,但是地址可以修改。

int const *p;    const在*号后,是p的值不能修改;const在*号前,是*p的内容不能修改

指针常量:是个常量,是指指针变量P的值不能被修改,p是个常量,而指针指向的对象的值是可以改变的。

  • 定义结构体不会分配内存空间,只有定义结构体变量时才会为变量分配内存空间
  • 结构体变量所占内存空间的大小为所有成员变量中占内存空间最大的变量所占内存空间的整数倍
  • 结构体变量之间可以赋值,实际上是全部成员变量之间的赋值
  • 结构体变量的名字是该结构体在内存中的首地址
  • 不能定义同名结构体
  • 尽量不要再代码块内定义结构体,避免造成作用域问题

11.指针和数组的关系

3> 定义结构体变量的三种方式

数组指针:指向一维数组的指针,即数组的首元素

int a[10];int *p=NULL;p=a;

是一个指向二维数组一行的指针变量,即二维数组的首行的地址

int (*p)[表达式];

指针数组:数组元素是指针变量

int *p[表达式];

  • 在定义结构体的同时定义结构体变量,重用性差
  • 先定义结构体,在用这种类型定义结构体变量
  • 用typedef为结构体定义一个新的类型名,用这个新类型名定义这种类型的结构体变量

12.结构体(struct)

4> 指向结构体的指针

能够保存不同数据类型的一种构造数据类型

  • 可以定义一个结构体类型的指针来指向该种类型的结构体变量
  • 通过指针间接访问结构体指针变量的两种方式

     ① .name,(p为指向结构体变量的指针,name为结构体变量的成 员变量的名字) ② p->name
    

【关键字】struct

五、枚举

【定义结构体】    struct 结构体名{

成员变量1;

成员变量2;

成员变量n;

};  

1> 基本使用

【结构体和指针】

  • 用于定义一个具有固定取值的变量
  • 枚举类型变量的定义与结构体类型变量的定义相似

1)指向结构体的指针

struct struct_name *p;    //p是指针变量名

p=&object_name;        //&取地址符不能忘

2> 使用注意

【结构体的嵌套】

  • 枚举类型的成员变量实际上存储的是整型常量,默认从0开始编号
  • 可以指定枚举类型的成员变量的编号规则

一个结构体中嵌套了另一个结构体

struct struct_name{

成员变量1;

成员变量2;

struct struct_name_a{

成员变量a;

成员变量b;

}object_name_a;

}object_name;

六、综合示例

【结构体数组】

  • 步骤
    • 定义一个Person结构体,属性包含:名字、性别
    • 名字用字符串表示
    • 性别用枚举表示
    • 定义一个函数输出结构体变量的信息
  • 代码

    #include <stdio.h>#include <string.h>//定义一个枚举类型,用于存储性别typedef enum{    sexMan, sexWoman, sexUnknown} Sex;//定义一个结构体类型,用于存储某个人的姓名和性别属性typedef struct{    char name[20]; //姓名    Sex sex; //性别} Person;//声明一个函数,用于打印某个人的信息void printThePerson(Person *p);int main(){    //定义一个结构体变量p    Person p;    //输入姓名,存放到结构体的name属性中    printf("请输入一个人的姓名n");    //使用%[^n]控制一'n'字符作为字符串的结束字符    scanf("%[^n]", p.name);    //输入性别,存放到结构体的sex属性中    printf("请输入一个人得性别(0:Man,1:Woman,2:Unknown)n");    scanf("%d", &p.sex);    //打印结构体变量p的相关信息    printThePerson;    return 0;}void printThePerson(Person *p){    char *str = NULL;    //将枚举值sex转换成相应的字符串    switch (p->sex)    {        case 0:            str = "Man";            break;        case 1:            str = "Woman";            break;        case 2:            str = "Unknown";            break;        default:            break;    }    printf("这个人的姓名为:%st性别为:%sn", p->name, str);   }
    

数组中的每个元素都是一个结构体变量

struct struct_name{

成员变量1;

成员变量2;

}数组名[表达式];        //表达式可以为空,为空的时候是不定长度的数组

13.枚举(enum)

枚举的成员中只能用一种类型,成员内不指定序号的时候都以0开始,C语言把枚举变量和常量作为整数来处理

enum color{red, black, blue}a,b;    //中间以逗号隔开

14.链表

链表是线性表的一种,是线性表的链式存储;是一种使用动态内存分配的,能保存不同数据类型的一种数据结构.构成链表的最小单位称为节点.

C语言执行过程中,在内存中的情况:

1)代码段(静态区域)

代码段由程序中的机器码组成,C语言中源代码编译后就形成了机器码,执行的时候,CPU的程序计数器指向了代码段的每一条代码,并由CPU依次执行

2)数据段(静态区域)

只读数据段,是程序使用一些不会被修改的数据,使用这些数的方式类似与查表式的操作,放置在只读存储器中;

已初始化读写数据段,是在程序中声明,有初值的变量,需占用寄存器空间,在程序执行时,位于可读写的内存区域内,供程序运行时读写

4)堆空间(动态区域)

只在程序运行时出现,一般由程序员分配和释放,在具有操作系统的情况下,若程序员忘记释放,在程序结束后,系统会自动回收内存

5)栈内存(动态区域)

只在程序运行时出现,在函数内部使用的变量,函数参数及返回值,函数调用(递归)都将使用栈空间.栈空间是由编译器自动分配和释放的内存.

C语言提供的两种内存分配的方式:

1).静态内存分配(栈内存)

由编译器自动为我们分配的内存空间,一般栈内存的大小为10M~30M

内存的对齐:是指整型占4个字节,大于4个字节的数据类型,也按照4个字节来计算,而且是4的整数倍

内存的补齐:只在结构体中有,如果所占字节数不足4个数据类型,比如char,需将不足的字节数补空,补够4个字节

2).动态分配内存(malloc向堆申请内存)

malloc函数(分配后不初始化)

void *malloc(size_t size);    //返回值是万能指针,在Mac下占8个字节,在Win下占4个字节

用于动态的向堆内存申请内存空间,使用完后,要使用free()函数释放该内存

一旦指针p指向动态分配的内存块,就可以忽略p是指针的事实,并且把它用作数组的名字,p[i].

静态库(.a): 是指在编译链接时, 把库文件中的代码全部加入到可执行文件中, 因此生成的文件比较大, 但在运行时就不再需要库文件了.

动态库(.so): 在编译链接时, 并没有把库文件的代码加入到可执行文件中, 而是在程序执行时由运行时链接文件加载库, 节省了系统开销.

原文链接:http://wquanfeng.blog.51cto.com/6316183/1228113

版权声明:本文由澳门新葡亰平台游戏发布于网络编程,转载请注明出处:复杂数据类型,基础知识点1