精华内容
下载资源
问答
  • @[TOC]在数据结构中,字符要单独用一种存储结构来存储,称为串存储结构。这里的指的就是字符。无论学习哪编程语言,操作最多的总是...下面将依次介绍三种存储方式。定长顺序存储字符的定长顺序存储结构,...

    @[TOC]

    在数据结构中,字符串要单独用一种存储结构来存储,称为串存储结构。这里的串指的就是字符串。无论学习哪种编程语言,操作最多的总是字符串。我们平常使用最多的存储结构无疑是利用定长数组存储。但是这种存储结构需要提前分配空间,当我们不知道字符串长度的时候,过大的分配内存无疑是一种浪费。因此,合理的选择字符串的存储方式显得格外重要。下面将依次介绍三种存储方式。

    定长顺序存储

    字符串的定长顺序存储结构,可以理解为采用 "固定长度的顺序存储结构" 来存储字符串,因此限定了其底层实现只能使用静态数组。

    使用定长顺序存储结构存储字符串时,需结合目标字符串的长度,预先申请足够大的内存空间。

    例如,采用定长顺序存储结构存储 "feizhufeifei",通过目测得知此字符串长度为12(不包含结束符 '\0'),因此我们申请的数组空间长度至少为 12,用 C 语言表示为:char str[18] = "feizhufeifei";

    下面是具体的C语言实现#include

    int main()

    {

    char str[15]="feizhufeifei";

    printf("%s\r\n",str);

    return 0;

    }

    这种存储方式基本是初学者都应该掌握的。下面介绍第二种存储方式。

    动态数组存储

    首先我们应该明确两个概念:堆和栈。

    堆是由我们程序员自己管理的,当进程调用malloc等函数分配内存时,新分配的内存就被动态分配到堆上,当利用free等函数释放内存时,被释放的内存从堆中被剔除。

    栈又称堆栈,是用户存放程序临时创建的变量,也就是我们函数{}中定义的变量,但不包括static声明的变量,static意味着在数据段中存放变量。除此之外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中,由于栈的先进后出特点,所以栈特别方便用来保存、恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存,交换临时数据的内存区。

    当我们调用malloc时,就会在堆上划分一块空间给我们使用,具体代码如下://创建了一个动态数组str,通过使用 malloc 申请了 10个 char 类型大小的堆存储空间。

    char * str = (char*)malloc(10*sizeof(char));

    动态数组的优势是长度可变,根据需要动态进行分配。当我不想申请新的变量,但是又想要扩大str的空间怎么办呢?这个时候realloc函数就起作用了。//通过使用这行代码,之前具有10 个 char 型存储空间的动态数组,其容量扩大为可存储 20 个 char 型数据。

    str = (char*)realloc(str, 20*sizeof(char));

    下面通过一个合并两个字符串的例子来更好地理解下动态分配过程。/*

    * @Description: 字符串的堆动态堆分配内存

    * @Version: V1.0

    * @Autor: Carlos

    * @Date: 2020-05-25

    * @LastEditors: Carlos

    * @LastEditTime: 2020-05-25

    */

    #include

    #include

    #include

    //打印测试语句

    #define DEBUG 0

    #if DEBUG

    #define DBG_PRINTF(fmt, args...) \

    do\

    {\

    printf("<> ", __FILE__, __LINE__, __FUNCTION__);\

    printf(fmt, ##args);\

    }while(0)

    # else

    # define DBG_PRINTF(fmt, args...)

    #endif

    int main()

    {

    char *s1 = NULL;

    char *s2 = NULL;

    s1 = (char *)malloc(5*sizeof(char *));

    strcpy(s1,"test");

    DBG_PRINTF("s1:%s\r\n",s1);

    s2 = (char *)malloc(7*sizeof(char *));

    strcpy(s2,"string");

    DBG_PRINTF("s2:%s\r\n",s2);

    int length1 = strlen(s1);

    int length2 = strlen(s2);

    //尝试将合并的串存储在 s1 中,如果 s1 空间不够,则用realloc动态申请

    if(length1

    s1 =(char*) realloc(s1,(length1 + length2+1) * sizeof(char));

    //合并两个串到 s1 中

    for(int i = length1; i < length1 + length2;i++)

    s1[i] = s2[i - length1];

    //串的末尾要添加 \0,避免出错

    s1[length1 + length2] = '\0';

    printf("s1+s2:%s", s1);

    //用完动态数组要立即释放

    free(s1);

    free(s2);

    return 0;

    }

    块链存储

    块链存储就是利用链表来存储字符串。本文使用的是无头结点的链表结构(即链表的第一个头结点也存储数据)。

    我们知道,单链表中的 "单" 强调的仅仅是链表各个节点只能有一个指针,并没有限制数据域中存储数据的具体个数。因此在设计链表节点的结构时,可以令各节点存储多个数据。

    例如,我们要用链表存储feizhu字符串,链表结构如下所示:

    bVcMDQu

    我们也可以每个链表存储四个字符,那么最后一个节点肯定不会占满。这时,我们可以使用#或者其他符号将其填满。

    bVcMDQv

    怎样确定链表中每个节点存储数据的个数呢?

    链表各节点存储数据个数的多少可参考以下几个因素:

    串的长度和存储空间的大小:若串包含数据量很大,且链表申请的存储空间有限,此时应尽可能的让各节点存储更多的数据,提高空间的利用率(每多一个节点,就要多申请一个指针域的空间);反之,如果串不是特别长,或者存储空间足够,就需要再结合其他因素综合考虑;

    程序实现的功能:如果实际场景中需要对存储的串做大量的插入或删除操作,则应尽可能减少各节点存储数据的数量;反之,就需要再结合其他因素。

    下面是具体的代码实现。/*

    * @Description: 字符串的块链表存储(无头结点的链表)

    * @Version: V1.0

    * @Autor: Carlos

    * @Date: 2020-05-25

    * @LastEditors: Carlos

    * @LastEditTime: 2020-05-25

    */

    #include

    #include

    #include

    //全局设置链表中节点存储数据的个数

    #define linkNum 3

    typedef struct link {

    //数据域可存放 linkNum 个数据

    char a[linkNum];

    //代表指针域,指向直接后继元素

    struct link * next;

    }Link;

    /**

    * @Description: 遍历链表,打印

    * @Param: Link * head 结构体头结点指针

    * @Return: 无

    * @Author: Carlos

    */

    void PrintLink(Link * head)

    {

    Link * p = head;

    while (p)

    {

    for (int i = 0; (i < linkNum) &&(p->a[i]!='#'); i++)

    {

    printf("%c", p->a[i]);

    }

    p = p->next;

    }

    }

    /**

    * @Description: 初始化链表

    * @Param: Link * head 结构体头结点指针。char * str 要操作的字符串

    * @Return: Link *结构体指针

    * @Author: Carlos

    */

    Link * InitLink(Link * head, char * str)

    {

    int length = strlen(str);

    //需要的节点个数 向上取整

    int nodenum = length/linkNum;

    Link *p = head;

    int j;

    //将数据存放到每个节点的数组中

    for(int i = 0;i<=nodenum;i++)

    {

    for( j = 0;j < linkNum;j++)

    {

    if (i*linkNum + j < length)

    {

    p->a[j] = str[i*linkNum+j];

    }

    //使用#填充未满的节点数组空间

    else

    {

    p->a[j] = '#';

    }

    }

    //链接新旧两个节点

    if (i*linkNum + j < length)

    {

    Link* q = (Link*)malloc(sizeof(Link));

    q->next = NULL;

    p->next = q;

    p = q;

    }

    }

    return head;

    }

    int main()

    {

    Link* head = (Link*)malloc(sizeof(Link));

    head->next=NULL;

    InitLink(head,"blockchain");

    PrintLink(head);

    return 0;

    }

    关于链表不明白的可以参考这篇博客史上最全单链表的增删改查反转等操作汇总以及5种排序算法(C语言)

    文中代码均已测试,有任何意见或者建议均可联系我。欢迎学习交流!

    如果觉得写的不错,请点个赞再走,谢谢!

    如遇到排版错乱的问题,可以通过以下链接访问我的CSDN。

    **CSDN:[CSDN搜索“嵌入式与Linux那些事”]

    展开全文
  • 字符str1、str2连接,三种存储方式一、定长存储 一、定长存储 #include<iostream> using namespace std; #define MAXLEN 255 typedef struct { char ch[MAXLEN + 1]; int length; }String; void StrAssign...

    串(字符串)是一种特殊的线性表,它的数据元素仅有一个字符组成。一般情况下处理的非数值型数据对象经常是字符串数据,例如在事务处理中,顾客的姓名、地址、货物产地等,一般都作为字符串处理。通常以“串的整体”作为处理对象。

    一 、串的存储结构

    串的顺序存储结构是用一组地址连续的存储单元来存储字符序列的。按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区。一般用定长数组来定义。
    在这里插入图片描述
    串的实际长度可以在预定义长度的范围内随意,超出预定义长度的串值则会被舍弃,称之为“截断”。

    在这里插入图片描述
    1.定长顺序存储
    2.堆分配存储(也是顺序存储结构)
    3.块链存储

    1 定长存储

    1.串的顺序存储结构
    串的顺序存储结构是用一组地址连续的存储单元来存储字符序列的。按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区。一般用定长数组来定义。
    在这里插入图片描述
    #define MAXLEN 255
    typedef struct {
    char ch[MAXLEN + 1];
    //存储串的一维数组,ch[0]~ch[255],共256个;
    //通常情况下ch[0]存放串的长度,或者闲置不用,真正串的类容从ch[1]开始
    int length;//串的当前长度
    }String;

    2 块链存储

    串要进行频繁插入删除操作时,顺序存储不方便,就要用到链式存储

    串的块链存储,指的是使用链表结构存储字符串。
    在这里插入图片描述
    从图 2 可以看到,使用链表存储字符串,其最后一个节点的数据域不一定会被字符串全部占满,对于这种情况,通常会用 ‘#’ 或其他特殊字符(能与字符串区分开就行)将最后一个节点填满。

    链表各节点存储数据个数的多少可参考以下几个因素:
    串的长度和存储空间的大小:若串包含数据量很大,且链表申请的存储空间有限,此时应尽可能的让各节点存储更多的数据,提高空间的利用率(每多一个节点,就要多申请一个指针域的空间);反之,如果串不是特别长,或者存储空间足够,就需要再结合其他因素综合考虑;
    程序实现的功能:如果实际场景中需要对存储的串做大量的插入或删除操作,则应尽可能减少各节点存储数据的数量;反之,就需要再结合其他因素。

    1 串的链式存储

    串的块链存储,指的是使用链表结构存储字符串。
    在这里插入图片描述
    缺点存储密度低
    如图第一个结点存储了字符A,占用一个字节,假如地址占用4个字节,那么存储密度1/(1+4)=0.2
    在这里插入图片描述

    2 块链存储

    为了解决存储密度引入,链式存储的块链
    将多个字符存储在一个结点,那么这一个节点叫做一个存储块,即块链
    在这里插入图片描述
    如图第一个结点存储了字符A、B、C、D,4个字符占用4个字节,假如地址占用4个字节,那么共占用8个字节,则存储密度 4/(4+4)=0.5

    在这里插入图片描述

    如果每个块存放50个字符,那么存储密度50/(50+4)=0.92
    在这里插入图片描述

    3 块链存储的定义

    在这里插入图片描述

    二、串连接三种方式实现(定长、堆、块链)

    字符串str1、str2连接,分别用定长存储、堆存储、块链存储实现,不能直接调用函数库中自带的连接函数。

    1 定长存储

    #include<iostream>
    using namespace std;
    #define MAXLEN 255//定义串的最大长度为255,<=255以内的任何串可用
    typedef struct {
    	char ch[MAXLEN + 1];//存储串的一维数组,ch[0]~ch[255],共256个
    	int length;//串的当前长度
    }String;
    void StrAssign(String* Str, char str[])//生成一个其值等于字符串常量 str 的串 Str
    {
    	int i = 0;
    	while (str[i] != '\0') i++;//计算str的长度
    	Str->length = i;
    	for (i = 0; i < Str->length; i++) {
    		Str->ch[i] = str[i];//从第一个字符开始,着个赋
    	}
    }
    void StrConcat(String str1, String str2, String* str3)//连接字符串1和2,并存在字符串3中
    {
    	str3->length = str1.length + str2.length;
    	int i;
    	for (i = 0; i < str1.length; i++) {//当串1的字符全部赋值给串3,退出当前for循环
    		str3->ch[i] = str1.ch[i];
    	}  //将str1赋值到str
    	for (; i < str3->length; i++) {//此for循环的i从串1长度str1.length开始到str3->length结束
    		str3->ch[i] = str2.ch[i - str1.length];
    	}  //将str2赋值到str
    }
    void print(String* str)
    {
    	int i;
    	for (i = 0; i < str->length; i++) {
    		cout << str->ch[i];
    	}
    	cout << endl;
    }
    int main()
    {
    	char st1[255], st2[255];
    	String str1, str2, str3;
    	cout << "请输入第一个串" << endl;
    	cin >> st1;
    	StrAssign(&str1, st1);
    	cout << "请输入第二个串" << endl;
    	cin >> st2;
    	StrAssign(&str2, st2);
    	StrConcat(str1, str2, &str3);
    	print(&str3);
    	return 0;
    }
    

    在这里插入图片描述

    2 堆分配存储

    #include<iostream>    //堆存储
    using namespace std;
    #define MAXSIZE 100
    typedef struct st {
    	char* ch;  //串存放的起始地址
    	int length;  //串的长度
    	int strsize; //分配的存储空间的大小
    }String;
    String CreateNullString() {    //初始化
    	String str;
    	str.length = 0;
    	str.ch = (char*)malloc(MAXSIZE * sizeof(char));
    	str.strsize = MAXSIZE;
    	return str;
    }
    void StrAssign(String* str1, char str[]) {//生成一个其值等于字符串常量 str 的串 str1
    	int i = 0;
    	while (str[i] != '\0') i++;//计算str的长度
    	if (str1->length < i) {
    		//增加存储空间,将较长的空间赋值为新的值
    		str1->ch = (char*)malloc(sizeof(char));
    		str1->strsize = i;
    	}
    	str1->length = i;
    	for (i = 0; i < str1->length; i++) {
    		str1->ch[i] = str[i];//从第一个字符开始,着个赋
    	}
    }
    void StrConcat(String* str, String str1, String str2) {
    	if (str->strsize < str1.strsize + str2.strsize) {
    		str->ch = (char*)realloc(str->ch, (str->length + str1.length) * sizeof(char));
    		str->strsize = str1.length + str2.length;
    	}
    	str->length = str1.length + str2.length;
    	int i;
    	for (i = 0; i < str1.length; i++) {
    		str->ch[i] = str1.ch[i];
    	}  //将str1赋值到str
    	for (; i < str->length; i++) {
    		str->ch[i] = str2.ch[i - str1.length];
    	}  //将str2赋值到str
    }
    void print(String* str) {
    	int i;
    	for (i = 0; i < str->length; i++) {
    		cout << str->ch[i];
    	}
    	cout << endl;
    }
    int main()
    {
    	char st1[255], st2[255];
    	String str1, str2, str3;
    	str1 = CreateNullString();
    	str2 = CreateNullString();
    	str3 = CreateNullString();
    	cout << "请输入第一个串" << endl;
    	cin >> st1;
    	StrAssign(&str1, st1);
    	cout << "请输入第二个串" << endl;
    	cin >> st2;
    	StrAssign(&str2, st2);
    	StrConcat(&str3, str1, str2);
    	print(&str3);
    	return 0;
    }
    

    在这里插入图片描述

    3 块链存储

    在这里插入图片描述

    思路(1):两个子串先分成块,再连接

    //将两个串先分别转换成块存储
    //将已经分好的块进行连接

    但这样有个问题,第一个串的最后一块可能不满,显然有些不合理,造成了空间浪费

    #include <stdio.h>
    #include <iostream>
    #include <cstring>
    #define CHUNKSIZE 4//用户自定义块的大小
    using namespace std;
    typedef struct Chunk {  //块链存储结构体
    	char ch[CHUNKSIZE];
    	struct Chunk* next;
    }Chunk;
    Chunk* initChunk(char[]);//初始化一个串 
    void print_Chunk(Chunk* h);//打印Chunk串 
    void contract(Chunk* t, Chunk* s);//将串s插入到串t某个字符后 
    int main()
    {
    	Chunk* s, * t;
    	char s_str[100];
    	char t_str[100];
    	cout << "请输入t串:";
    	cin >> t_str;
    	cout << "请输入s串:";
    	cin >> s_str;
    	t = initChunk(t_str);//将两个串先分别,转换成块存储
    	s = initChunk(s_str);//将两个串先分别,转换成块存储
    	cout << "链接后为:" << endl;
    	contract(t, s); //将已经存储好的块进行连接
    	print_Chunk(t);//打印连接后的块链
    	return 0;
    }
    Chunk* initChunk(char str[])
    {
    	Chunk* h, * temChunk, * lastChunk;
    	h = new Chunk;//为头结点分配内存, 头结点不储存信息 
    	lastChunk = h;
    	int num = strlen(str) / CHUNKSIZE;//计算出所需块链的个数
    	int mod = strlen(str) % CHUNKSIZE;
    	if (mod != 0)num++;//如果不是这整数个块,则块数num+1
    	int i, j;
    	//对每一个块赋值 
    	for (i = 0; i < num; i++)
    	{
    		temChunk = new Chunk;//为块链分配内存 
    		j = 0;
    		//当字符串还没有结束以及j<CHUNKSIZE的时候,进行赋值 
    		while (j < CHUNKSIZE && str[i])
    		{
    			temChunk->ch[j] = str[i * CHUNKSIZE + j];//将对应字符赋值
    			j++;
    		}
    		// 尾插法
    		//将当前已经完成的这个块,连接在上一个块的后面
    		lastChunk->next = temChunk;
    		lastChunk = temChunk;
    	}
    	//如果最后一个块没填满,通常用'#'补上
    	if (mod != 0)
    	{
    		int temp = CHUNKSIZE - mod;
    		for (size_t q = 0; q < temp; q++)
    		{
    			lastChunk->ch[mod + q] = '#';//最后一个块没填满,用'#'补上
    		}
    	}
    	lastChunk->next = NULL;
    	return h;
    }
    void print_Chunk(Chunk* h)
    {
    	Chunk* temChunk;
    	temChunk = h->next;
    	int i;
    	while (temChunk)//打印输出时,按块输出
    	{
    		for (i = 0; i < CHUNKSIZE; i++)
    		{
    
    			if (temChunk->ch[i] == NULL)
    			{
    				break;
    			}
    			else
    			{
    				cout << temChunk->ch[i] ;
    			}
    
    		}
    		temChunk = temChunk->next;//一个块输出完毕,继续输出下一个块
    		cout << " ";//为了使直观的反映内部存储结构,输出时块与块之间,以空格间隔
    	}
    	cout << endl;
    }
    void contract(Chunk* t, Chunk* s)
    {
    	while (t->next)
    	{
    		t = t->next;
    	}
    	t->next = s->next;//直接把s连在t之后	 
    }
    

    如图,第一个串的最后一块可能不满,显然有些不合理,造成了空间浪费。
    为了便于观察,他是4个一块,第一个串最后一块不满的用#补上

    //为了使直观的反映内部存储结构,输出时块与块之间,以空格间隔
    在这里插入图片描述
    第二个串最后一块不满的用#补上
    在这里插入图片描述

    思路(2)先连接,再分块存储

    //先把两个串连接
    //然后再按照块链的方式存储

    #include <iostream>
    #include<string>
    #include<cstring>
    #define CHUNKSIZE 5 //用户自定义块的大小
    using namespace std;
    
    typedef struct Chunk {//块链存储结构体
    	char ch[CHUNKSIZE];
    	struct Chunk* next;
    }Chunk;
    
    char s_s[200];
    Chunk* initChunk(char[]);//初始化一个块链 
    void print_Chunk(Chunk* h);//打印Chunk块 
    void StrConcat(char s1[], char s2[]);
    int main()
    {
    	Chunk* s, * t;
    	char s_str[100];
    	char t_str[100];
    	cout << "请输入t串:";
    	cin >> t_str;
    	cout << "请输入s串:";
    	cin >> s_str;
    	StrConcat(t_str, s_str);//先把两个串连接
    	t = initChunk(s_s);//然后再按照块链的方式存储
    	print_Chunk(t);//打印连接后的块链
    	return 0;
    }
    
    Chunk* initChunk(char str[])
    {
    	Chunk* h, * temChunk, * lastChunk;
    	h = new Chunk;//为头结点分配内存, 头结点不储存信息 
    	lastChunk = h;
    	int len = strlen(str);//串的总长度
    
    	int num = strlen(str) / CHUNKSIZE;//计算出所需块链的个数
    	int mod = strlen(str) % CHUNKSIZE;
    	if (mod != 0) num++;//如果不是这整数个块,则块数num+1
    
    	int i, j;
    	//对每一个块链赋值 
    	for (i = 0; i < num; i++)//创建num个块,组成一个块链
    	{
    		temChunk = new Chunk;//为块链分配内存 
    		j = 0;
    
    		//创建单个块,当这个块填满或者字符串结束时,退出本次while循环
    		//当字符串还没有结束以及j<CHUNKSIZE的时候,进行赋值 
    		while (str[i * CHUNKSIZE + j] != '\0' && j < CHUNKSIZE)
    		{
    			temChunk->ch[j] = str[i * CHUNKSIZE + j];//将对应字符赋值
    			j++;
    		}
    		// 尾插法
    		//将当前已经完成的这个块,连接在上一个块的后面
    		lastChunk->next = temChunk;
    		lastChunk = temChunk;
    
    		//如果最后一个块没填满,通常用'#'补上
    		//当字符串已经结束,并且最后一个块没满,则执行if语句
    		if ((i * CHUNKSIZE + j) == (len) && (CHUNKSIZE - mod!=0))
    		{
    			int temp = CHUNKSIZE - mod;
    			for (size_t q = 0; q < temp; q++)
    			{
    				temChunk->ch[j + q] = '#';//最后一个块没填满,用'#'补上
    			}
    		}
    	}
    	lastChunk->next = NULL;//块链完成,最后加上NULL结束
    
    
    	cout << endl << "当前块的大小为:" << CHUNKSIZE << endl;
    	cout << "该块链共有" << num << "个块组成" << endl << endl;
    	return h;
    }
    
    
    void print_Chunk(Chunk* h)
    {
    	Chunk* temChunk;
    	temChunk = h->next;
    	int i;
    
    	//输出连接后的串
    	cout << "连接后的串为:";
    	for (i = 0; i < strlen(s_s); i++) {
    		cout << s_s[i];
    	}
    	cout << endl;
    
    	//便于观察块链的内部真实存储结构,输出块链的每一个块的内容
    	cout << "块链的存储结构为:";
    	while (temChunk)
    	{
    		for (i = 0; i < CHUNKSIZE; i++)
    		{
    			if (temChunk->ch[i] == NULL)
    			{
    				break;
    			}
    			else
    			{
    				cout << temChunk->ch[i];
    			}
    		}
    		temChunk = temChunk->next;
    		cout << " ";//当一个块输出完毕,输出空格,即每个块之间用空格间隔,还是便于观察
    	}
    	cout << endl;
    }
    
    void StrConcat(char s1[], char s2[])
    {
    	int i = 0;
    	for (; i < strlen(s1); i++)
    	{
    		s_s[i] = s1[i];
    	}
    
    	for (; i < strlen(s1) + strlen(s2); i++)
    	{
    		s_s[i] = s2[i - strlen(s1)];
    	}
    }
    

    #define CHUNKSIZE 5 //用户自定义块的大小

    当CHUNKSIZE= 5时,
    第二个块只有3个字符,后面两个空缺部分用#填补

    //为了使直观的反映内部存储结构,输出时块与块之间,以空格间隔
    在这里插入图片描述
    当CHUNKSIZE= 4时,
    存储满两个完整的块
    在这里插入图片描述

    思路(3)在思路(1)上改进,第一个串的最后一块不满,用第二个串前移补上。但程序是实现上较为复杂,感兴趣的自己研究。

    展开全文
  • 字符存储方式

    千次阅读 2021-02-26 10:10:01
    1.整型数组的存储方式 int a[3]={11,22,33}; 为连续的空间,整个数组的大小是(数组个数 乘以 元素类型大小) 2.计算数组的大小,并算出数组的元素的大小及数组元素的个数 #include <stdio.h> #include <...

    1.整型数组的存储方式

    int  a[3]={11,22,33};
    

    为连续的空间,整个数组的大小是(数组个数 乘以 元素类型大小)

    2.计算数组的大小,并算出数组的元素的大小及数组元素的个数

    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
         int  a[3]={1,2,3};
         
         printf("a数组的大小是: %d\n",sizeof(a));
         printf("数组的元素大小是: %d\n",sizeof(a[0]));//数组占入空间的大小
         printf("数组的元素大小是: %d\n",sizeof(int));//数组占入空间的大小  
         printf("数组元素的个数是:%d\n",sizeof(a)/sizeof(a[0]));
    	 system("pause");
    	 return 0;
    }
    
    

    运行结果:
    在这里插入图片描述
    3.字符串的存储方式
    (1)第一种

    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
         
         char  a2[3]={'a','b','c'};
     
         printf("a2数组的大小是: %d\n",sizeof(a2));
         printf("数组的元素大小是: %d\n",sizeof(a2[0]));//数组占入空间的大小
         printf("数组的元素大小是: %d\n",sizeof(char));//数组占入空间的大小  
         printf("数组元素的个数是:%d\n",sizeof(a2)/sizeof(a2[0]));
    	 system("pause");
    	 return 0;
    }
    
    

    运行结果:
    在这里插入图片描述
    (2)第二种

    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
        
          char  a3[3]="abc";
     
         printf("a3数组的大小是: %d\n",sizeof(a3));
         printf("数组的元素大小是: %d\n",sizeof(a3[0]));//数组占入空间的大小
         printf("数组的元素大小是: %d\n",sizeof(char));//数组占入空间的大小  
         printf("数组元素的个数是:%d\n",sizeof(a3)/sizeof(a3[0]));
    	 
         system("pause");
    	 return 0;
    }
    
    

    运行结果:
    在这里插入图片描述
    (3)第三种

    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
         char  a4[]="abc";
     
         printf("a4数组的大小是: %d\n",sizeof(a4));
         printf("数组的元素大小是: %d\n",sizeof(a4[0]));//数组占入空间的大小
         printf("数组的元素大小是: %d\n",sizeof(char));//数组占入空间的大小  
         printf("数组元素的个数是:%d\n",sizeof(a4)/sizeof(a4[0]));
         
         system("pause");
    	 return 0;
    }
    

    运行结果:
    在这里插入图片描述
    在这里,数组大小不写,数组大小会根据初始化的时候元素个数来确定
    为什么输出的结果个数是4,因为多个一个字符,‘\0’。代表字符串的结束标志。

    4.字符串的末尾是\0,如何系统检测不到\0就打印字符

    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
          char  a4[]="abc";
          int i=0;
       
          while(a4[i]!='\0')
          {
               printf("%c",a4[i]);
               i++;      
          }    
         
         putchar('\n');
         system("pause");
    	 return 0;
    }
    
    

    运行结果
    在这里插入图片描述

    知识点总结:
    字符串在内存中,除了有效字符abc以外,还会在字符串的末尾补充\0,作为字符串的结束标志
    真正计算有效字符串的长度,用strlen(在下一章补充)。

    ——@上官可编程

    展开全文
  • 计算机编程中三种存储结构存是什么发布时间:2021-02-03 14:27:34来源:亿速云阅读:62作者:小新小编给大家分享一下计算机编程中三种存储结构存是什么,相信大部分人都还不怎么了解,因此分享这篇文章给...

    计算机编程中串的三种存储结构存是什么

    发布时间:2021-02-03 14:27:34

    来源:亿速云

    阅读:62

    作者:小新

    小编给大家分享一下计算机编程中串的三种存储结构存是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!是的,串是一种数据对象和操作都特殊的线性表结构。数据结构中提到的串,即字符串;字符串中的字符之间具有“一对一”的逻辑关系,所以严格意义上讲,串存储结构是一种线性存储结构。

    本教程操作环境:windows7系统、Dell G3电脑。

    数据结构中提到的串,即字符串,由 n 个字符组成的一个整体( n >= 0 )。这 n 个字符可以由字母、数字或者其他字符组成。

    数据结构中,字符串要单独用一种存储结构来存储,称为串存储结构。

    严格意义上讲,串存储结构也是一种线性存储结构,因为字符串中的字符之间也具有"一对一"的逻辑关系。只不过,与之前所学的线性存储结构不同,串结构只用于存储字符类型的数据。

    特殊的串空串:含有零个字符的串。例如:S = “”(双引号中没有任何东西),一般直接用 Ø 表示。

    空格串:只包含空格的串。注意和空串区分开,空格串中是有内容的,只不过包含的是空格,且空格串中可以包含多个空格。例如,a = ” ”(包含3个空格)。

    子串与主串:串中任意个连续字符组成的字符串叫做该串的子串,包含子串的串称为主串。例如:a = ”BEI”,b = ”BEIJING”,c = ”BJINGEI” 。对于字符串 a 和 b 来说,由于 b 中含有连续的字符串 a ,

    所以可以称 a 是 b 的子串,b 是 a 的主串;而对于 c 和 a ,虽然 c 中也含有 a 的全部字符,但不是连续的 “BEI” ,所以串 c 和 a 没有任何关系。

    子串在主串中的位置:对于串 a = ”BEI” 来说,首字符 ‘B’ 在串 b 的位置为 1 ,所以子串 a 在主串 b = “BEIJING” 中的位置是 1。子串在主串中的位置和字符在数组中的存放位置不同,子串在主串的位置从 1 开始数。

    两个串相等的标准:如果两个串的串值完全相同,那么这两个串相等。

    串的三种存储结构存

    储串的结构有三种:

    1 定长顺序存储;

    2 堆分配存储;

    3 块链存储。

    定长顺序存储

    采用固定长度的数组(即静态数组)存储串。

    例如:char a[7] = "abcdfg";

    此方式存储串时,需要预估串的长度提前申请足够的存储空间。目标串如果超过了数组申请的长度,超出部分会被自动舍弃(称为“截断”)。

    例如:char a[3] = "abcdfg";//实际上数组中只存储了 “abc” ,后边的被截断。堆分配存储

    采用动态数组存储串

    在C语言中,存在着一个被称之为“堆”的自由存储区,用 malloc 函数和 free 函数管理,malloc 函数负责申请空间,free 函数负责释放空间。

    例如:char * a = (char*)malloc(5*sizeof(char));//创建 a 数组,动态申请5个 char 类型数据的存储空间

    使用堆分配存储的优势在于:当发现申请的空间不够用时,可以通过 realloc() 函数重新申请更大的存储空间。例如:a = (char*)realloc(a, 10*sizeof(char));//前一个参数指申请空间的对象;第二个参数,重新申请空间的大小

    使用 malloc 函数申请的存储空间,不会自动释放,需要程序员调用 free() 函数手动释放。如果不手动释放,当程序执行彻底结束,由操作系统进行回收。例如:free(a);//释放动态数组a申请的空间

    举一个完整的例子,连接串 “abc” 和 “defg” 变为 “abcdefg” ;#include 

    #include 

    #include 

    int main()

    {

    char * a1=NULL;

    char * a2=NULL;

    a1=(char*)malloc(3*sizeof(char));

    strcpy(a1, "abc");//将字符串“abc”复制给a1

    a2=(char*)malloc(3*sizeof(char));

    strcpy(a2, "defg");

    int lengthA1=strlen(a1);

    int lengthA2=strlen(a2);

    if (lengthA1

    a1=(char*)realloc(a1, (lengthA1+lengthA2)*sizeof(char));

    }

    int i;

    for (i=lengthA1; i

    a1[i]=a2[i-lengthA1];

    }

    printf("%s",a1);

    free(a1);

    free(a2);

    return 0;

    }

    3c85215865576916050c84e88442a779.png

    注:在程序中,我们给 a1 和 a2 赋值的时候,使用了 strcpy 复制函数。在这里不能直接用:a1 = ”abc”这种方式,

    如果你这样做,程序编译会出错,告诉你,没有 malloc 的空间不能 free 。

    原因是: strcpy 函数是将字符串复制到申请的存储空间中,而直接赋值是字符串存储在别的内存空间(本身是一个常量,放在常量区)中,

    更改了指针 a1 和 a2 的指向,也就是说,之前动态申请的存储空间虽然申请了,结果还没用呢就丢了。

    块链存储

    块链存储,其实就是借用链表的存储结构来存储串。一般情况下使用单链表就足够了,而且不需要增设头结点。

    在构建链表时,每个结点可以存放一个字符,也可以存放多个字符。

    2d17b0e5914b0295cc464a136f30077f.png

    链表中最后一个结点的数据域不一定全被串值占满,通常会补上 “#” 或者其他特殊的字符和字符串中的字符区分开。

    每个结点设置字符数量的多少和存储的串的长度、可以占用的存储空间以及程序实现的功能相关。

    如果串包含数据量很大,但是可用的存储空间有限,那么就需要提高空间利用率,相应地减少结点数量(因为多一个节点,就多申请一个指针域的空间)。

    而如果程序中需要大量地插入或者删除数据,如果每个节点包含的字符过多,操作字符就会变得很麻烦,为实现功能增加了障碍。

    总结

    在平时编写程序,经常会用到例如:char *a = ”abcd”;这种方式表示字符串,和上面三种存储方式最主要的区别是:这种方式用于表示常量字符串,只能使用,不能对字符串内容做修改(否则程序运行出错);而以上三种方式都可以对字符串进行删改的操作。

    例如:#include 

    int main() {

    char* a="abcd";

    a[1]='b';

    return 0;

    }

    程序编译可以通过,运行失败,改成下面堆分配存储的方式就对了:#include 

    #include 

    #include 

    int main() {

    char * a=(char*)malloc(4*sizeof(char));

    strcpy(a, "abcd");

    a[1]='e';

    printf("%s",a);

    return 0;

    }

    3914f91a1549cb11b68bbef853d7139f.png

    三种存储表示方式中,最常用的是堆分配存储,因为它在定长存储的基础上通过使用动态数组,避免了在操作串时可能因为申请存储空间的不足而丢失字符数据;和块链存储方式相比,结构相对简单,更容易操作。

    以上是“计算机编程中串的三种存储结构存是什么”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

    展开全文
  • 众所周知,C语言中的数据类型不包括字符,但储存字符最常见的方式有两 其一数组直接定义法 char a2[]="sen"; 上述代码定义了一个储存字符的数组a2,并让a2的值为“sen” 其二数组储存法 char a1[]={'s','e','...
  • 一、复习普通变量与指针变量的区别 所有变量的基本属性:变量名称,值,地址(分配...字符数组char* arry[]在栈上申请空间,存储字符地址,字符实际是存储在只读存储区,在排序时交换的是字符地址。 #include
  • Android存储数据的5种方式

    千次阅读 2021-06-02 13:59:54
    使用键值对的方式存储数据2.通常用于:保存用户的偏好设置、选择是否保存密码、记录文档阅读的位置等3.实现方式(写入):a).获取SharedPreferences对象 getSharedPreferences("文件名",MODE_PRIVATE/MODE_MULTI_...
  • 1. 由于C语言没有字符类型,字符的使用需要依靠字符数组实现,本文用 3 个例子实现字符数组的输入输出操作。 2.本文中出现的 gets() 、puts() 函数需引入 string.h 头文件 #include <string.h> 方法...
  • 第一:多次使用substring_index()的方法DELIMITER$$DROPPROCEDUREIFEXISTS`array`$$CREATEPROCEDURE`array`()BEGINSET@array_content="wwwmysqlcomhcymysqlblog51ctocom";SET@i=1;SET@count=CHAR_LENGTH(@ar...
  • JSON字符存储方式

    千次阅读 2021-01-21 18:51:54
    json json字符 json格式的字符 “abc123truelkgsjhgo” 普通字符 “hgahgo” html格式字符 ...json格式就是满足对象和数组数据结构的一字符 json的使用方法: JSON.parse() 把json格式的字符
  • Android四数据存储的应用方式作为一个完整的应用程序,数据存储操作是必不可少的。因此,Android系统一共提供了四数据存储方式。分别是:SharePreference、文件存储、SQLite、 Content Provider。对这几种方式的...
  • 可用于存储一对字符的列表.是否有类似的方法来存储字符的三元组列表?我能想到的一方法是使用std :: vectorstd::vector > v (4, std::vector (3));但这不允许我使用手动的第一和第二存取器.所以,我写了自己...
  • MySQL把字符转化为数字的三种方式

    千次阅读 2021-08-11 15:57:07
    百度搜素之后发现是在这查询的时候MySQL把字符转化为数字,并且有几种方式: 1. 方法一: 字段值 + 0 MySql 会根据上下文自动转换类型,这里会将被本来是字符类型的字段值以数值型返回,如果字段存放的值为数值字符...
  • 1 三种存储表示     ,即:字符。要注意的是,C语言中是没有字符数据类型的,而将其作为一数据结构——“内容受限的线性表”进行实现,并对空串、空格的长度、子串与主等...
  • Python遍历字符的4种方式1.下标法2.for in3.iter内置函数4.enumerate下标法和enumerate适合需要判断后续字符的场景,比如循环到下标index处,要求判断index+1的字符这种。最典型的就是语法解析器,判断"(())"这种...
  • 原标题:plc通讯方式有哪三种?plc常见的三种通讯方式PLC = Programmable Logic Controller,可编程逻辑控制器,一数字运算操作的电子系统,专为在工业环境应用而设计的。它采用一类可编程的存储器,用于其内部存储...
  • C语言中字符的两定义方式

    多人点赞 2021-10-18 00:18:58
    我们直到C语言中是没有字符这种数据类型的,我们只能依靠数组进行存储,即字符数组,而我们在
  • 存储和基本操作

    2021-02-05 20:02:43
    一、 的定义 ,即字符是由零个或多个字符组成的有限序列,中字符的个数称为...是一特殊的线性表,数据元素之间呈线性关系 的数据对象限定为字符集(如中文字符、英文字符、数字字符、标点字符等) ...
  • JSON字符 json格式的字符 “abc123truedfgfgf” 普通字符 “< h1>sdsada< h1>” 标签字符 ...JSON格式就是满足对象和数组数据结构的一字符 JSON的使用方法 JSON.parse() 把
  • Ok,我们知道了,引擎就是一个程序的核心组件。简单来说,存储引擎就是指表的类型以及表在计算机上的存储方式存储引擎的概念是MySQL的特点,Oracle中没有...在MySQL中的存储引擎有很多,可以通过“SHOW ENGINE...
  • 一、数据类型的基本分类 整型家族 —— short char int long 浮点数家族 —— float double 构造类型(自定义类型)—— (1)数组类型 比如定义一个整形数组...二、简要介绍整形在内存中的存储 原码 反码 补码 2.
  • 案例:List集合存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合。 分析: (1)定义学生类 (2)创建List集合对象 (3)创建学上对象 (4)把学生添加到集合 (5)遍历集合(迭代器方式、for...
  • 背景:(关于进程通信的几种方式) 题目描述: 编写一主程序可以由用户选择如下三种进程通信方式: 使用管道来实现父子进程之间的进程通信 子进程向父进程发送自己的进程标识符,以及字符“is sending a message ...
  • python字符反转的四方法详解这篇文章主要介绍了python字符反转的四详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下1、用reduce函数方法book = '...
  • 众所周知,kafka中存储的数据是经过BASE64加密后的jsonObject,因此从kafka中读取的数据经过base64解码,得到的是json,利用JSONObect的方法可以对json进行解析,拿到对应的数据。那么要如何将scala对象或者java...
  • 字符存储方式3.字符长度计算 1.常用定义方式 int i; int a[3]={1,2,3}; //整型数据定义 //第一定义方式,和整型数据类似 有点幼稚!! char str1[5]={'a','b','c','d','e'}; //字符数组的定义 ...
  • 结构之堆分配存储详解(C语言版)
  • import java.util.ArrayList; ArrayList<String>array=new ArrayList<>(); array.add("hello"); array.add("world"); array.add("java"); for(int x=0;x<array.size();... }
  • 一、串口通信简介 ...串行通讯可以进一步分为单工、半双工和全双工三种。在串口通信中,常用的协议包括RS-232、RS-422和RS-485。它们的主要区别在于其各自的电平范围不相同。 二、串行和并行通信 刚说到串口通
  • 都是通过一个key对应一个value,而且key是唯一的方式进行存储的,但是indexedDB和localStorage有很不一样的一点,就是可以直接存储对象数组等,不需要想localStorage那样必须转为字符。 异步调用:IndexedDB是使用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 717,743
精华内容 287,097
关键字:

串的三种存储方式

友情链接: qaokie.zip