数据结构预备知识

数据结构预备知识

在进行数据结构讲解时,我们需要把一些基础知识进行复习和巩固,目的是为了方便数据结构的学习,主要涉及到的基础知识是指针、结构体、指针和数组的关系以及内存分配空间,接下来我们一起来简单的看看。

指针的重要性

  • 指针是C语言的灵魂
    • 定义:指针就是用来存储地址的,例如:int *p;p就是一个指针变量。
    • 地址:地址是内存单元的编号,从0开始的非负整数,范围:0-FFFFFFFFH

那么我们的CPU(中央处理器)和我们内存空间进行访问时的原理是什么?
原理:在CPU和内存中间存在地址线、控制线、数据线,地址线是CPU找到内存空间的地址,控制线主要用来控制数据的读和写的一个操作,比如0就是读,1就是写,数据线是CPU和内存空间进行数据的传递过程。

  • 指针是什么?
    • 指针就是地址,地址就是指针。
    • 指针变量是存放内存单元地址的变量。
    • 指针的本质是一个操作受限的非负整数。
  • 指针的分类分类:
    • 基本类型的指针
    • 指针和数组的关系
    • 构造数据类型指针

注意一点:变量并不一定连续分配,随机分配内存。

内存

  • 概念:内存是多字节组成的线性一维存储空间。
  • 单位:内存的基本划分单位是字节。每个字节含有8位,每一位存放1个0或1个1,内存和编号是一一对应的。
  • 软件在运行前需要向操作系统申请存储空间。在软件运行期间,该软件所占空间不再分配给其他软件。当软件运行完毕后,操作系统将回收该内存空间(操作系统并不清空该内存空间中遗留下来的数据)。

注意:

  • 指针变量也是变量,普通变量前不能加*,常亮和表达式前不能加&。
  • 局部变量只在本函数内部使用。

如何通过被调函数修改主调函数中普通变量的值

  • 实参为相关变量的地址;
  • 形参为以该变量的类型为类型的指针变量;
  • 在被调函数中通过 *形参变量名的形式 的形式就可以修改主函数。
#include<stdio.h>
int main(void)
{
    int *p; //p是个变量名字,int*表示该p变量只能存储int类型变量的地址
    int i=10;
    int j;

//  j=*p;
//  printf("%d\n",j);   //error,p未指定

//  char ch='A';
//  p=&ch;  //error,类型不一致   
    p=&i;   //p保存i的地址,p指向i;修改p的值不影响i的值,修改i的值不影响p的值;任何场合下,*p和i可以互换。*p等价于i。
    //p=10; //error
    j=*p;//等价于j=i;
    printf("i=%d,j=%d,*p=%d\n",i,j,*p);
    return 0;
}
例子二:
#include<stdio.h>
void fun(int * i)//不是定义了一个名字叫做*i的形参,而是定义了一个形参,该形参名字叫做i,它的类型是int*
{
    *i=100; 
}

int main(void)
{
    int i=9;
    fun(&i);    //局部变量只在本函数内部使用。
    printf("i=%d\n",i);
}

指针和数组之间的关系

数组名:一维数组名是个指针变量,它存放的是一维数组第一个元素的地址,它的值不能被改变,一维数组名指向的是数组的第一个元素。
结论:

  • a[3]等价于*(3+a); (a+3)等价于(3+a);

int a[5]={1,2,3,4,5};
Show_Aarry(a,5);//a等价于&a[0],&a[0]本身就是int*类型

void Show_Array(int * p,int len)
{
    int i;
    //P[2]=-1;//p[0]=*p ;  p[2]==*(p+2)==*(a+2)==a[2] ; p[i]就是主函数的a[i]
    for (i=0;i<lem;i++)
    printf(“%d\n”,p[i]);
}

注意:

  • 指针变量的运算

  • 指针变量不能相加,不能相乘,不能相除。

  • 如果两指针变量属于同一数组,则可以相减。

  • 指针变量可以加减一整数,前提是最终结果不能超过指针变量

  • p+i的值是p+i*(p所指向的变量所占的字节数)

  • p-i的值是p-i*(p所指向的变量所占的字节数)

  • p++等价于p+1 p--等价于P-1

  • 所有的指针变量只占4个子节 用第一个字节的地址表示整个变量的地址

double *p;
double x=66.6;  //一个double占8个字节
p=&x;//x占8个字节,1个字节是8位,1个字节一个地址,p内只存放了一个地址,通常是字节的首地址
double arr[3]={1.1,2.2,3.3};
double *q;
q=&arr[0];
printf(“%p\n”,q);   //%p实际就是以十六进制输出
q=&arr[1];
q=printf(“%p\n”,q); //p,q相差8

注意:无论指针指向的变量占多少个字节,指针变量统一都只占4个字节

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

  • 发送地址
  • 修改指针变量的值,只能修改地址
void fun(int **);
int main(void)
{
    int i=9;
    int *p=&i;//    *p;p=&i;
    printf(“%p\n”,p);
    f(&p);  
    printf(“%p\n”,p);
    return 0;
}
//void fun(int *q)
//{
//  q=(int *)0xffffffff;  //错误,不会改变p的值
//}
void fun(int ** q)
{
    *q=(int *)0xffffffff;//这里需要强转一下。 
}

结构体的使用概述

为什么会出现结构体:

  • 为了表示一些复杂的数据,而普通的基本类型变量无法满足要求
  • 结构体的定义:
    • 结构体是用户根据实际需要自己定义的复合数据类型
  • 如何使用结构体:
    struct Student st={1000,”zhagnsan”,20};
    struct Student*pst=&st;
    • 通过结构体变量名来实现
      st.sid
    • 通过指向结构体变量的指针来实现【重点】
      pst->sid
      pst所指向的结构体变量中的sid这个成员


#include<stdio.h>
#include <string.h>
//全局结构体定义
struct Student
{
    int sid;
    char name[200];
    int age;
};  //分号不能省
int main(void)
{
    struct Student st={1000,”zhagnsan”,20};
    printf(“%d,%s%d\n,”,st.sid,st.name,st.age);
    printf(“%d,%s%d\n,”,st);        //error
    st.sid=99;      //第一种
    //st.name=”lisi”;       //error 
    strcpy(st.name,”lisi”);
    st.age=22;  
    struct Student*pst;
    pst=&st;        //第二种
    pst->sid=99;    //pst->等价于(*pst).sid,而(*pst).sid等价于st.sid,所以pst->sid等价于st.sid
    return 0;
}

注意:

  • 结构体变量不能加减乘除,但可以相互赋值
  • 普通结构体变量和结构体指针变量作为函数传参的问题
#include<stdio.h>
struct Student
{
    int sid;
    char name[200];
    int age;
};  
void f(struct Student *pst);
void g(struct Student st);
void g2(struct Student *pst);
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;
}
void g(struct Student st)   //整体变量赋值//输出方法二,速度慢,耗空间,耗内存,不推荐
{
    printf(“%d %s %d\n”,st.sid,st.name,st.age); 
}
void g2(struct Student *pst)
{
printf(“%d %s %d\n”,pst->sid,pst->name,pst->age);   
}
void f(struct Student *pst)
{
(*pst).sid=99;
strcpy(pst->name,”zhagnsan”);
pst->age=22;
}

malloc()动态分配内存概述

  • 动态内存的分配和释放
#icclude<stdio.h>
#include<malloc.h>
int main(void)
{
    int a[5]={1,2,3,4,5};   //静态数组

    int len;
    printf(“请输入你需要分配的数组长度:len=”);
    scanf(“%d”,&len);
    int *pArr=(int *)malloc(sizeof(int)*len);   //(int *)为强制转换,强制使pArr指向前四个字节。可以将pArr当做数组名来操作
    //*pArr=4;//类似于a[0]=4;
//  pArr[1]=10;//类似于a[1]=10;
//  printf(“%d %d\n”,*pArr,pArr[1]);
//我们可以把pArr当做一个普通数组来使用
    for (int i=0;i<len;++i)
        scanf(“%d”,&pArr);
    for (i=0;i<len;++i)
        printf(“%d\n”,*(pArr+i));

    free(pArr); //把pArr所代表的的动态分配的20个字节的内存释放
    return 0;
}
  • 跨函数使用内存讲解及其示例
#include <stdio.h>
int f();
int main(void)
{
    int i=10;
    i=f();
    printf(“i=%d\n”,i);
    for(i=0;i<2000;++i)
        f();
    return 0;
}
int f()
{
    int j=20;
    return j;
}
#include <stdio.h>
 int main ()
{
    int *p;
fun(&p);
...
}
int fun (int **q)
{
    int s;  //s为局部变量。调用完毕后s就没有了,最终p没有指向一个合法的整型单元
    *q=&s;
}
#include <stdio.h>
int main()
{
    int *p;
    fun(&p);
    ...
}
int fun(int **q)
{
    *q=(int *)malloc(4);    //返回4个字节,只取第1个字节地址赋给*q,*q==p。执行完后,因为没有free(),内存没有释放。如果没有free(),整个程序彻底终止时才能释放
}

Java程序内部类定义方法
A aa=new A();
A pa=(A)malloc(sizeof(A));

#include<stdio.h>
#include<malloc.h>
struct Student
{
    int sid;
    int age;
}
struct Student *  CreatStudent(void);
void ShowStudent(struct Student *);
int main(void)
{
    struct Student *ps;
    ps=CreatStudent();
    ShowStudent(ps);
    return 0;
}
struct Student *  CreatStudent(void)
{
    struct Student *P=(struct Student *)malloc(sizeof(struct Student));
    p->sid=99;
    p->age=88;
return p;
}
void ShowStudent(struct Student *pst)
{
    printf(“%d %d\n”,pst->sid,pst->age);
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 144,100评论 1 305
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 61,765评论 1 257
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 95,393评论 0 213
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 41,312评论 0 183
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 49,108评论 1 260
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 38,923评论 1 178
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 30,527评论 2 274
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,280评论 0 168
  • 想象着我的养父在大火中拼命挣扎,窒息,最后皮肤化为焦炭。我心中就已经是抑制不住地欢快,这就叫做以其人之道,还治其人...
    爱写小说的胖达阅读 29,155评论 6 235
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 32,640评论 0 214
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,391评论 2 216
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 30,744评论 1 231
  • 白月光回国,霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前, 不然我有一百种方法让你生不如死。]我...
    爱写小说的胖达阅读 24,292评论 0 32
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,198评论 2 213
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 31,654评论 3 211
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,655评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,070评论 0 169
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 33,654评论 2 233
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 33,800评论 2 237

推荐阅读更多精彩内容

  • 一、数据结构概述 1.什么是数据结构? 我们如何把现实中大量而复杂的问题以特定的数据类型和特定的存储结构保存到主存...
    卖报的女孩阅读 271评论 0 0
  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,378评论 3 44
  • 一、框架 1、Mac系统及常用工具、进制;C数据类型、常量变量、运算符、表达式、格式化输入输出 2、关系运算符、逻...
    师景福阅读 607评论 0 1
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,016评论 1 32
  • 前段时间有同学评论说,指针方面的问题不太懂,今天小编就给大家带来非常详细的c语言之指针学习资料。 前言:复杂类型说...
    诸葛青云999阅读 29,988评论 0 16