Day1-数据结构

文章通过示例代码展示了如何在C语言中动态分配堆区内存来存储字符串,定义了创建、输入、输出和释放堆区空间的函数。同时,详细阐述了C语言中的各种存储类型,如static、extern、const、auto、register和volatile的作用和特性。此外,还讨论了栈区和堆区的内存分配以及动态内存管理函数malloc和free的使用。最后,提到了宏定义的使用和typedef进行类型别名的定义。
摘要由CSDN通过智能技术生成

定义字符指针,分别指向堆区空间,计算字符串的长度

要求:

1.定义函数实现堆区空间申请

2.在主函数中实现输入字符串

3.定义函数实现字符串长度 size_t my_strlen(const char *s)

4.定义函数释放堆区空间

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *create( )
{
	char *p=(char *)malloc(sizeof(char)*100);
	if(p==NULL)
		return NULL;
	else
		return p;
}
char *Input(char *str)
{
	char *p=gets(str);
	return p;
}
size_t my_strlen(const char *str)
{
	const char *p=str;
	while(*str)
		str++;
	return str-p;
}
void Output(char *str)
{
	printf("%s\n",str);
}
char *free_space(char *p)
{
	if(p==NULL)
		return NULL;
	else
	{
		free(p);
		p=NULL;
	}
	return p;
}
int main()
{
	printf("请输入一段字符: ");
	char *p=create();
	p=Input(p);
	Output(p);
	printf("该字符串长度为:%ld\n",my_strlen(p));
	p=free_space(p);
	return 0;
}

结果为:

 

一、存储类型

a)static

1.static修饰未初始化全局变量,默认结果为0

2.static修饰局部变量,延长生命周期,生命周期不是作用域

依旧是局部变量

int a=0;//全局变量 生命周期和作用于都是从定义开始到整个文件结束
void fun()
{
int b=0;//局部变量
static int c=0;//局部变量 作用于:在fun函数使用
printf("&c=%p\n",&c);
a++;
b++;//1 1
c++;//1 2 3
    printf("a=%d\n",a);//1 2 3
    printf("b=%d\n",b);//1 1 1
    printf("c=%d\n",c);//1 2 3
}
int main(int argc, const char *argv[])
{
    fun();
    fun();
    fun();
    printf("c=%d\n",c);
    return 0;
}

3. static修饰函数只能在当前文件中调用,不可以跨文件调用

4.static修饰其他文件的全局变量,不可以使用extern引用

 

 

5.static修饰指针不可以指向auto类型的地址

原因:计算机先为静态变量分配空间,后再分配auto类型的变量

不可以使用指针指向不存在的变量地址。

 

b) extern

作用:引用外部变量

 

c)const 不是存储类型,修饰变量

作用:修饰的变量不发生改变

1.const修饰的全局变量,值不变,变量的空间在静态区的只读段

2.const修饰的局部变量,值不变,变量的空间在栈区

 

3.const和指针

const int *p *在const的右边,修饰的值,值不变,地址可以改变

int const *p *在const的右边,修饰的值,值不变,地址可以改变

int * const p *在const的左边,修饰的地址,地址不变,值可以改变

const int * const p 第一个const修饰的值,第二个const修饰的地址

地址和值都不可以改变

int const * const p 第一个const修饰的值,第二个const修饰的地址

地址和值都不可以改变

d) auto

自动类型

1.当默认不写存储类型时,默认就是auto类型

2.auto不可以直接修饰全局变量【auto int a】,定义全局变量时,默认是auto类型,但是不能是auto修饰,空间在静态区,从定义开始到整个文件结束

可以使用extern引用

3.auto修饰局部变量时,空间在栈区,从定义开始到本函数有效

不可以返回一个局部变量的地址

e) register 是存储类型之一

作用:表示这是一个寄存器变量

运行速度:寄存器> cache(高速缓存) > 内存

特点:不可以进行寻址操作

 

f) volatile 不是存储类型

作用:防止内存优化,保持内存的可见性

 二、虚拟内存空间

 

1.栈区:栈的思想,先进后出,后进先出,先定义变量后分配空间

导致栈的地址分配值从大地之到小地址

2.堆区:满足队列的思想,先进先出,后进后出,先定义变量先分配空间,导致堆区的地址分配从小地址到大地址。

3,栈区和堆区没有边界点,当栈区地址和堆区地址临界,那就是边界

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int a=10;//全局 已经初始化  在.data段
int b;//全局 未初始化  在.bss段

const int c=10;//sonst修饰的全局变量在.ro
char str[]="hello"//全局  初始化str在.data  
            //"hell0"  在.ro段,
            //字符串hello赋值一份给str
            //可以修改
char *p="hello"//全局  p在.data段
            //hello在.ro段a
            //p指向只读段的hello常亮的首地址
int *p=(int *)malloc(100);//报错 全局不可以调用函数
static int d;//静态区 未初始化 .bss段
static int e=10;//静态去  初始化 .data段

int main(int argc, const char *argv[])
{
static int d;  //静态局部变量 静态区 未初始化 .bss段
static int e=10; //静态局部  初始化 .data段
int a=10; //栈区
int b; //栈区
const int c=10;//const修饰的局部变量在栈区
char str[]="hello"//str:栈区  hello只读段

char *p="hello"//p在栈区  
int *p=(int *)malloc(100);//p在栈区  100在堆区

    return 0;
}
动态申请:
    头文件:#include <stdlib.h>
    格式:void *malloc(size_t size);
     参数:size_t size  表示堆区申请空间字节大小
     返回值:void *,如果申请成功则返回堆区空间首地址
         如果申请失败返回NULL,记得保存堆首地址
         0x10--0x20
            0x16--0x20
    使用格式:
        申请单个空间
        int *p=(int *)malloc(sizeof(int))
        申请连续空间
        int *p=(int *)malloc(sizeof(int)*n)
 动态释放:
     头文件:#include <stdlib.h>       
     格式: void free(void *ptr);
     参数:void *ptr 表示释放的指针
     返回:无返回
     使用格式:
         int *p=(int *)malloc(sizeof(int)*n)
         //0x10--0x50  p=0x10
         free(p); //p=0x10
         p=NULL;//防止野指针
         
          野指针
1,未初始化的指针直接使用,称为野指针    
    int *p;//p指向随机地址
    printf("*p=%d\n",*p);      
2.返回一个局部变量的地址,称为野指针
    int *fun()
    {
        int a;//0x20-0x23 局部变量,当调用函数分配空间,
        //函数调用结束空间释放
        return &a;    
    }  
3.通过指针越界访问数组  
     int arr[3];
     int *p=arr;
     *(p+3)=100;
4.指针指向堆区空间,释放指针,此时指针为野指针
     int *p=(int *)malloc(sizeof(int)*n)
     //0x10--0x50  p=0x10
     free(p); //p=0x10

四、宏

i)宏定义

格式: #define 宏名 宏体

不可以修改,常量,只做替换不做计算,不做正确性检查

1.宏定义
#define N 10
#define M 'A'
#define K 1.1
#define STR "hello"
2.宏函数
格式: #define  宏函数名(参数列表) 宏体
宏函数名:大写
参数列表: 宏函数的参数列表,不需要加数据类型
宏体不需要加{}
#define MAX(a,b) a>b?a:b
#define SUM(a,b) a+b
#define SUM(a,b) (a+b)

ii)宏函数

#if 宏条件
    c语句1
#else
    c语句2
#endif
如果宏条件成立则执行C语句1,否则执行C语句2
多用于注释

#ifndef 宏名
    c语句1
#endif
如果宏名未定义,则执行C语句1

#ifdef 宏名
    C语句;
#endif
如果宏名已经定义,则执行C语句1

iii)多文件编译

头文件:预处理命令,函数声明,全局变量

主函数:存储主函数

自定义函数

执行过程:gcc main.c test.c

 

 

五、typedef

作用:类型重定义,起别名

格式: typedef 数据类型 别名

1.别名:满足命名规范

2.typedef是关键字,是C语句,加分号

typedef int size_4;//把int起别名size_4

int==》size_4

int a;

size_4 a;

 

int a;
int arr[3];
int arr[3][4];
char str[];
char str[][];
int *p
int **p
int *p[];
int (*p)[]
int *p(void)
int (*p)(void)
int (*p[])(void)
数据类型
int ;
int [3];
int [3][4];
char [];
char [][];
int *
int **
int *[];
int (*)[]
int *(void)
int (*)(void)
int (*[])(void)
typedef 数据类型结合
typedef int size_4;//size_4是类型名int
typedef int arr_t[3] ;//arr_t是int [3]的类型名
typedef int arr[3][4];//arr是int [3][4]的类型别名
typedef char str[];
typedef char str[][];
typedef int *p
typedef int **p
typedef int *p[];
typedef int (*p)[]
typedef int *p(void)
typedef int (*p)(void)//p函数指针类型名
typedef int (*p[])(void)

5.1 typedef和#define之间的区别

#define size_4 int ----》 typedef int size_4

1,typedef属于C语句,宏不属于C语句

2,typedef在编译阶段,宏在预处理阶段

3,typedef是类型重定义,宏属于宏替换

4,typedef可以适用于任何复杂的数据类型,但是宏只能适用于基本类型的替换

typedef int arr[3] 正确

宏实现不了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ck钉钉钉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值