数据结构学习记录——c语言前置

学习资源来自b站逊哥带你学计算机

视频链接:https://www.bilibili.com/video/BV1tNpbekEht/?vd_source=21986a5c5d1c6c1a3a0e2e0f6e6cd097

1.学什么?

2.C语言前置内容

函数,数组,字符串,指针,内存解析,结构体

2.1函数

2.1.1函数的四种形式

无参数,无返回值案例:函数/test3.c

无参数,有返回值案例:函数/test4.c

有参数,无返回值案例:函数/test5.c

有参数,有返回值案例:函数test6.c

2.1.2`int fun` vs `void fun` 的区别

**`int fun`**: – 这种函数会返回一个整数值 – 在函数体中通常包含 `return` 语句来返回结果 – 调用该函数时,可以将返回值赋给一个变量或用于表达式中

**`void fun`**: – 这种函数不返回任何值 – 函数执行完后不会向调用者传递数据 – 通常用于执行某些操作、打印输出等任务

2.1.3日常写代码什么时候加参数?什么时候加返回值?

看需求!

实际应用:以计算1+2+……+100为例编写代码test3-6,代码如下

//test3
#include <stdio.h>
void fun()
{
    int sum=0;
    for(int i = 1;i<=100;i++)
    {
        sum+=i;
    }
    printf("sum=%d\n",sum);
}
int main()
{
    fun();
    return 0;
}
//test4
#include <stdio.h>
int fun()
{   int sum=0;
    for(int i=0;i<=100;i++)
    {
        sum+=i;
    }
    return sum;   
}
int main()
{
    
    int s=fun();
    printf("sum=%d\n",s);
}
//test5
#include <stdio.h>
void fun(int n)
{
    int sum =0;
    for(int i=1;i<=n;i++)
    {
        sum+=i;
    }
    printf("sum=%d\n",sum);
}
int main()
{
    fun(100);
    return 0;
}
//test6
#include <stdio.h>
int fun(int n)
{
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        sum+=i;
    }
    return sum;
}
int main()
{
    int n =fun(100);
    printf("%d\n",n);
}
运行结果
5050

2.2字符串

2.3虚拟内存地址

内存条、显卡、各种适配卡都有其各自的存储地址空间。
操作系统将这些设备的存储地址空间抽象成一个巨大的一维数组空间。
对于内存的每一个字节会分配一个32位或64位的编号,这个编号称为内存地址。

代码中变量地址是分配示例

int main 
{
int a =10;//int4个字节
int b =5;
return 1;
}

2.4数组

2.4.1数组的定义

int main()
{
int a[]={16,47,89,42,38};
for (int i=0;i<5;i++)
{
printf ("%d\n",a[i]);
}
}

2.4.2获取数组地址

获取数组地址,其实是取数组第一个元素的地址

补充:&取地址符,%p输出地址

#include <stdio.h>

int main()
{
    int a [] = {16,47,89,42,38};
    printf("%p\n",a);
    printf("%p\n",&a);//获取数组地址
    printf("%p\n",&a[0]);//获取数组第一个元素的地址
    printf("%p\n",&a[1]);//获取数组第二个元素的地址
    return 0;
}
结果输出
00000000005FFE30
00000000005FFE30
00000000005FFE30
00000000005FFE34

2.4.3数组与sizeof

sizeof 函数可以获取变量字节长度

#include <stdio.h>
int main()
{
    int a = 5;
    printf("%zu\n",sizeof(a));//int4字节
    printf("%zu\n",sizeof(int));
    printf("%zu\n",sizeof(3.14));//double8字节
    return 0;
}

结果
4
4
8

可利用sizeof函数获取数组元素个数

#include <stdio.h>
int main()
{
    int a[]={16, 17, 18, 19, 20};
    for(int i=0;i<sizeof(a)/sizeof(a[0]);i++)
    {
        printf("%d\n",a[i]);
    }

    printf("数组大小%zu\n",sizeof(a));//获取数组大小
    printf("数组元素大小%zu\n",sizeof(a[0]));//获取数组元素大小
    printf("数组个数%d\n",sizeof(a)/sizeof(a[0]));//获取数组元素个数
    return 0;
}

结果
16
17
18
19
20
数组大小20
数组元素大小4
数组个数5

2.5指针

C程序员新手和老手的其中之一差别在于是否对指针有深刻的理解、高效的使用指针。
理解指针的关键在于理解C程序如何管理内存。

2.5.1指针的定义
指针是用来存放内存地址的变量

指针的使用

代码输出示例

#include <stdio.h>
int main()
{
    int a=5;
    int *p=&a;
    printf("a的地址为:%p,a的值为%d\n",&a,a);
    printf("p的地址为:%p,p的值为%p\n",&p,p);
    return 0;
}

结果
a的地址为:00000000005FFE4C,a的值为5
p的地址为:00000000005FFE40,p的值为00000000005FFE4C//p存放的是a的地址

2.5.2间接引用操作符

在指针定义外使用的*都为间接引用操作符

代码示例

#include <stdio.h>
int main()
{
    int a=5;
    int *p=&a;
    printf("a的地址为:%p,a的值为%d\n",&a,a);
    printf("p的地址为:%p,p的值为%p\n",&p,p);
    printf("*p的为%d\n",*p);
//修改a的值
    *p=10;
    printf("a的修改后的值为%d\n",a);
    return 0;
}
结果
a的地址为:00000000005FFE4C,a的值为5
p的地址为:00000000005FFE40,p的值为00000000005FFE4C
*p的为5
a的修改后的值为10

2.5.3指针与函数

示例1:设计一个函数,传入两个int参数,并交换这两个参数的值。

不使用指针

#include <stdio.h>
void swap(int a,int bn)
{
    int temp;
    temp = a;
    a=b;
    b=temp;
    printf("a=%d,b=%d\n",a,b);
}
int main()
    {
        int m=10,n=20;
        swap(m,n);
        printf("m=%d,n=%d\n",m,n);
        return 0;
    }
结果
a=20,b=10
m=10,n=20

使用指针
指针和地址可以简单理解为相互绑定的关系,提到指针就得想到地址,提到地址就得想到指针

#include <stdio.h>
void swap(int *a,int *b)//a和b为指针得传入地址
{
    int temp;
    temp = *a;
    *a=*b;
    *b=temp;
    printf("a=%d,b=%d\n",*a,*b);
}
int main()
    {
        int m=10,n=20;
        swap(&m,&n);
        printf("m=%d,n=%d\n",m,n);
        return 0;
    }
结果
a=20,b=10
m=20,n=10

2.5.4指针与数组

在C语言中,指针与数组的关系十分密切。
通过数组下标能完成的操作都可以通过指针完成。
一般来说,用指针编写的程序比用数组下标编写的程序执行速度快。

案例

#include <stdio.h>
int main()
{
    int a[] = {15, 20, 25, 30, 35};
    int *p;
    p =a;//数组可以直接赋给指针

    printf("%p\n",a);
    printf("%p\n",p);
    printf("%d\n",*p);
}
结果
00000000005FFE30
00000000005FFE30
15

给指针加上一个整数,实际上加的是这个整数和指针数据类型对应字节数的乘积

//案例遍历输出数组
#include <stdio.h>
int main()
{
    int a[] = {15, 20, 25, 30, 35};
    int *p;
    p =a;//数组可以直接赋给指针
    for(int i =0;i<sizeof(a)/sizeof(a[0]);i++)
    {
        printf("%d\n",a[i]);
    }
    for(int i =0;i<sizeof(a)/sizeof(a[0]);i++)
    {
        printf("%d\n",*(p+i));//指针p+1=p+1*4 
    }
结果
15
20
25
30
35
15
20
25
30
35

2.6结构体

2.6.1结构体的声明

2.6.2结构体的初始化和调用

示例代码
#include <stdio.h>
struct point
{
    int x,y;
};
int main()
{
    struct point p;
    p.x=5;
    p.y=10;
    printf("x = %d, y = %d",p.x,p.y);
}

结果
x = 5, y = 10

2.6.4结构体构造函数

#include <stdio.h>
struct point//point是取的标签名可修改
{
    int x;
    int y;
};

struct point createPoint(int x,int y)
{
    struct point temp;
    temp.x=x;
    temp.y=y;
    return temp;
}
int main()
{
    struct point p;
    p=createPoint(10,20);
    printf("(%d,%d)",p.x,p.y);
    return 0;
}


结果
(10,20)

2.6.5结构体与指针

#include <stdio.h>
struct test3
{
    int x;
    int y;
};
int main()
{
    struct test3 t;
    t.x = 10;
    t.y = 20;

    struct test3 *pp;
    pp = &t;
/*
第二种写法
pp->x = 30;   // 等价于 (*pp).x,是简写形式
pp->y = 40;   // 专业代码都用这种写法
*/
    (*pp).x = 30;
    (*pp).y = 40;
    printf("x = %d, y = %d\n", t.x, t.y);
    printf("x = %d, y = %d\n", pp->x, pp->y);
    return 0;
}
结果
x = 30, y = 40
x = 30, y = 40

2.7类型定义tepydef

2.7.1如何使用

#include <stdio.h>

typedef int myType;
typedef char myChar;

int main()
{
    myType a = 10;
    myChar b = 'a';
    printf("a = %d\n", a);
    printf("b = %c\n", b);
    return 0;
}

结果
a = 10
b = a

2.7.2定义结构体

#include <stdio.h>

typedef struct {
    int a;
    int b;
}s1;
int main()
{
    s1 s;
    s.a = 1;
    s.b = 2;
    printf("%d %d\n", s.a, s.b);
    return 0;
}
结果
1 2

2.8动态内存分配

内存分类

C程序编译后,会以三种形式使用内存:
静态/全局内存
静态声明的变量和全局变量使用这部分内存,这些变量在程序开始运行时
分配,直到程序终才消失。
自动内存(栈内存)
函数内部声明的变量使用这部分内存,在函数被调用时才创建。
动态内存(堆内存)
根据需求编写代码动态分配内存,可以编写代码释放,内存中的内容直到
释放才消失。

特性int a;int arr[10];malloc
分配位置栈区栈区堆区
大小编译时固定编译时固定运行时确定
生命周期随代码块结束随代码块结束手动控制
最大限制栈空间小(几MB)栈空间小堆空间大(几GB)
灵活性
风险内存泄漏/悬空指针

动态内存分配

在C语言中,动态分配内存的基本步聚:
1.使用malloc(memory allocate)
函数分配内存
void*malloc(size_t)
如果成功,会返回从堆内存上分配的内存指针
如果失败,会返回空指针
2.使用分配的内存
3.使用free函数释放内存

malloc函数

#include <stdlib.h>   // 必须包含!

void* malloc(size_t size);
部分含义
返回值 void*返回申请到的内存起始地址,失败返回 NULL
参数 size_t size需要申请的字节数
void*通用指针,需要强制转换成具体类型

示例1
基本数据类型

#include <stdio.h>
#include <stdlib.h>
int main ()
{
    int *p;
    p = (int *) malloc (sizeof(int));
    *p = 10;
    printf ("%d\n", *p);
    free (p);
    return 0;
}
运行结果
10

示例2:maloc/test1
字符串


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
   char *str;
   str = (char *)malloc(12 * sizeof(char));  // 分配12个字符的内存空间,足够容纳"Hello World"字符串和结束符'\0'
   strcpy(str, "Hello World");
   printf("%s\n", str);
   free(str);
   return 0;
}
运行结果
Hello World

示例3:数组/test2.c


#include <stdio.h>
#include <stdlib.h>
int main()
{
    int *arr = (int *)malloc(sizeof(int) * 10);
    for (int i = 0; i < 10; i++)
    {
        arr[i] = i;
    }
    for (int i = 0; i < 10; i++)
    {
        printf("%d\n", arr[i]);
    }

    }
运行结果
1
2
3
4
5
6
7
8
9

示例4:结构体 /test3.c

#include <stdio.h>
#include <stdlib.h>
typedef struct 

{
    int x;
    int y;
}po;

int main()
{
    po *p;
    p=(po*)malloc(sizeof(po));
    p->x=1;
    p->y=2;
    printf("%d %d",p->x,p->y);
    return 0;
}
运行结果
1 2

总结

初步了解的数据结构学什么内容,初步简略复习了c语言前置内容,可另外寻找资源详细学习