C数据类型讲解

这篇博客详细讲解了C语言中的数据类型,包括结构体的命名、初始化、结构体指针、地址与字节对齐,以及float、枚举、数组、字符串等基础知识。博主还探讨了指针、函数指针、共用体和字节对齐的重要性,并通过实例解释了各种概念。
摘要由CSDN通过智能技术生成

报错

不安全代码报错

‘strcpy‘: This function or variable may be unsafe. Consider using strcpy_s instead.运行出错问题
开头加上这句话就没问题了

#define _CRT_SECURE_NO_WARNINGS

详细
在这里插入图片描述

结构体

命名

1、命名和一开始的值大小

  • 如果一开始都没有初始化,那么其中的值就是随机的;但当有一个数赋值了,其他没赋值的就是0
  • 如果初始化的时候没有用typedef,那么之后如果要定义一个机构体的话就需要在前面加上struct。不然就直接名字就行了;如果没有加上typedef的话这样的句式就是直接声明了一个结构体变量了,如下图所示
  • typedef :将前面的命名为后面的 typedef unsigned char BYTE;将unsigned char命名为BYTE
#include <stdio.h>
int main(int argc, char *argv[])
{
   
	typedef struct
	{
   
		char book;
		int gift;
	}TEST;
	TEST test;
	printf("book的值为%d\ngift的值为%d\n",test.book,test.gift);
	
	return 0;
}

在这里插入图片描述

#include <stdio.h>

    struct TEST
	{
   
		char a;
		char book;
		int gift;
	};
	
int main(int argc, char *argv[])
{
   

	struct TEST test={
   
		.book=10
	};
	printf("a的值为%d\nbook的值是:%d\ngift的值为%d\n",test.a,test.book,test.gift);
	
	return 0;
}

在这里插入图片描述
在这里插入图片描述

初始化

  • 结构体声明只是进行一个结构体框架的描绘,并不会在内存中分配存储空间,直到真正定义一个结构体变量的时候,才会在内存中分布这个空间
  • 注意末尾要有分号
  • 主要看OneNote,这里进行一点补充。就是当进行初始化时,如果不指定某一个是什么什么,直接一排的数据,那是按照顺序一个一个轮下去赋值的
#include <stdio.h>	
typedef struct
	{
   
		char Chinese;
		int *English[2];
		char Jap[5];
		int k;
	}Book;

int a=1,b=2,c=3;

int main(int argc, char *argv[])
{
   
	Book book={
   
		't',
		&a,
		b,c,
		.k=5
	};
	
	printf("Chinese的值为%c\r\n",book.Chinese);
	//这里一定要加*,不然打印出来的值就是错误的。因为存储的是地址,所以需要值的话就需要+* 进行解引用 
	printf("English[0]的值为%d\r\n",*book.English[0]);
	//这里不能加*,不然就是错误的  因为实际保存的就是一个4字节的int 不是地址解引用了 那肯定就是错误的呀
	printf("English[1]的值为%d\r\n",book.English[1]);
	printf("Jap[0]的值为%d\r\n",book.Jap[0]);
	printf("k的值为%d\r\n",book.k);	
}

在这里插入图片描述

结构体指针

  • 赋值出去后用->,直接赋值用点
  • 指向结构体变量的指针称为结构体指针,数组名是指向数组第一个元素的地址可以将数组名直接赋值给指针变量,但是结构体的变量名不是指向结构体的地址了,所以必须使用取址运算符

在这里插入图片描述

#include <stdio.h>	
typedef struct{
   
		char Chinese;
		int English;
		char Jap[5];
	}Book;

void fun(Book *a)
{
   
	a->Chinese=2;//当传递的是一个指针的时候需要这样写
	printf("a.Chinese的值为%d\r\n",a->Chinese);
}

int main(int argc, char *argv[])
{
   
	Book book;
	book.Jap[2]=3;//直接写的话就用点
	fun(&book);//必须要用取址运算符
	printf("Jap[2]的值为%d\r\n",book.Jap[2]);
	
}

在这里插入图片描述

  • 结构体组成的数组。取其中任一项,加不加&都一样
#include <stdio.h>	
typedef struct{
   
		char Chinese;
		int English;
		char Jap[100];
	}Book;

int main(int argc, char *argv[])
{
   
	char buf[20]="岛国人";
	Book list[3];
	list[1].Chinese=3;
	
	//这里和下面这句 list[2].Jap前面加不加&都是一样的,都可以 
	//\r\n也会复制进去,起到相同的作用。所有最后的现象是有了两次换行 
	sprintf(list[2].Jap,"日本人是%s\r\n",buf);
	
	printf("Jap中的值是:%s\r\n",list[2].Jap);
	
}

在这里插入图片描述

  • 当你赋值给结构体的指针那项为地址的话,打印时要加取地址符 * 。直接赋值一个值的话打印的时候不用加取地址符 *
  • 下面有一个lwip中的使用例子
#include <stdio.h>
typedef struct
{
   
	int *num;
	char *str1;
	int book;
}A;

int main(int argc, char *argv[])
{
   
	A a;
	int b=10;
// 
	a.num=b;
	printf("a.num的值为%d\r\n",a.num);//直接用变量的话打印也是直接变量 
	
	a.num=&b;
	printf("a.num的值为%d\r\n",*a.num);//如果赋值为地址的话,那么打印时要用* 
//	
	a.str1="奔腾激光";
	printf("a.str1的值为:%s\r\n",a.str1);
//
	a.book=10;
	printf("a.book的值为%d\r\n",a.book);
 
}

在这里插入图片描述
lwip中的例子

err_t
netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
{
   
  LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;);
  LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;);
  LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;);

  if (buf->ptr == NULL) {
   
    return ERR_BUF;
  }
  *dataptr = buf->ptr->payload;
  *len = buf->ptr->len;
  return ERR_OK;
}
/** Main packet buffer struct */
struct pbuf {
   
  /** next pbuf in singly linked pbuf chain */
  struct pbuf *next;

  /** pointer to the actual data in the buffer */
  void *payload;

  /**
   * total length of this buffer and all next buffers in chain
   * belonging to the same packet.
   *
   * For non-queue packet chains this is the invariant:
   * p->tot_len == p->len + (p->next? p->next->tot_len: 0)
   */
  u16_t tot_len;

  /** length of this buffer */
  u16_t len;

  /** a bit field indicating pbuf type and allocation sources
      (see PBUF_TYPE_FLAG_*, PBUF_ALLOC_FLAG_* and PBUF_TYPE_ALLOC_SRC_MASK)
    */
  u8_t type_internal;

  /** misc flags */
  u8_t flags;

  /**
   * the reference count always equals the number of pointers
   * that refer to this pbuf. This can be pointers from an application,
   * the stack itself, or pbuf->next pointers from a chain.
   */
  LWIP_PBUF_REF_T ref;

  /** For incoming packets, this contains the input netif's index */
  u8_t if_idx;
};

4、sizeof结构体

  • 有没有赋值,sizeof结构占的大小是固定的。因为创建的变量大小是固定的,赋值只是变量这个地方装上了值。
  • 比如说一个箱子占用的体积是1L,装不装东西都是1L。
#include <stdio.h>
int main(int argc, char *argv[])
{
   
	typedef struct
	{
   
		char *book;//地址变量占8个字节 
		int gift;//int占8个字节 
	}TEST;
	TEST test;
	printf("还未赋值时sizeof(test)的大小是:%d\n",sizeof(test));
	
	test.book="一本好书";
	test.gift=5;
	printf("赋值后sizeof(test)的大小是:%d\n",sizeof(test));	
	 
	
	return 0;
}

在这里插入图片描述

地址与字节对齐

介绍

结构体变量的地址和他第一个成员的地址是一样的。
在这里插入图片描述
1、以多少字节为单位开辟内存

  • 给结构体变量分配内存的时候,会去给结构体变量中找出基本类型的成员,哪个基本类型的成员占字节数多(这个多,是指一个数据所占的字节数),就以它为的大小为单元去开辟内存。
  • 比如全是char,则以1字节开辟内存(结构体中只有3个char,结构体就占用3字节的内存空间)。int(或者float)最大时就以4字节开辟(比如结构体有一个int变量一个char变量,他们占用8个字节)
  • 注意出现double就要分情况了,在vc6.0和visual studio中,以8字节为单位开辟内存(一个double和一个char,则sizeof就是16个字节)。在Linux环境的gcc中,以4字节为单位开辟。但是无论在那种环境,double型变量,都是占用8个字节。
  • 如果出现指针,此时没有超过4个字节的变量,那么就以4个字节为单位开辟内存
  • 如果出现了数组,数组可以看成多个变量的集合。
  • 在内存中存储结构体成员的时候,按定义的结构体成员的顺序存储。

在这里插入图片描述
2、字节对齐
视频讲解
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3、为什么要字节对齐

  • 用空间来换时间,提高CPU读取数据的效率。
    在这里插入图片描述

指定对齐

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

成草

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

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

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

打赏作者

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

抵扣说明:

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

余额充值