第二章。数据类型

一、 变量

  • 变量依据其定义的类型,分为整型变量、字符型变量、浮点型变量和指针变量等。

  • 每个变量必须要有一个名字和它所在内存空间绑定。
    变量名和它所在空间的绑定

  • 变量的值是变量所对应的内存区域存放的二进制序列。变量的值不会因为变量的类型发生了改变而改 变,当变量被转换为对应的类型时,内存区域的二进制序列以该类型的形式翻译出来。这是强制类型转换能够成立的原因。

在这里插入图片描述

  • 局部变量:在函数内进行定义说明,其作用域仅限于函数内。
    (1)在主函数中定义的变量也只能在主函数中使用,不能在其他函数中使用。
    (2)形参变量是属于被调函数的局部变量,实参变量是属于主调函数的局部变量。
    (3)允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。

  • 全局变量:在函数外部定义的变量,不属于哪一个函数,它属于一整个源程序文件,作用域为整个源程序。
    全局变量的说明符为extern,但在一个函数之前定义的全局变量,在该函数内使用时可不再添加。

二、常量

  • 常量的值在其作用域内不会发生改变,也不能再被赋值,在其出现时就被当作一个立即数来使用。只能被访问、被读取,而不能被写,被赋值。
    类似于const关键字。

在这里插入图片描述

三、基本内置类型

1、整型(6种):带符号整型(int),带符号短整型(short int),带符号长整型(long int或long),无符号整型(unsigned int),无符号短整型(unsigned short int),无符号长整型(unsigned long)。
2、实型(3种):单精度(float),双精度(double),长双精度(long double)
3、构造类型
4、指针类型
5、枚举类型
6、void类型
在这里插入图片描述

  • 数据类型及其大小
    在这里插入图片描述
  • 陷阱——有符号vs无符号
int main()
{
char a[1000];
int i;
for(i=0;i<1000;i++)
    {
    a[i]=-1-i;
    }
    printf("%d",strlen(a));
    return 0;
}

答案是255

四、 static

一般情况下,局部变量是存放在栈空间,生命周期在块语句执行结束时便结束了,但是如果用static进行修饰的话,该变量便存放在静态数据区,其生命周期一直持续到整个程序执行结束为止。

题目:用数组进行两个字符串的连接。
在自己封装的func函数中,定义的c数组在函数结束后就会被释放,因此无法进行return。使用static延长该局部变量的生命周期,使其能够返回输出。

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

char*func(char a[50],char b[50]){
    int i=0;
    int j=0;
    int x=0;
    static char c[1024]={0};
    while(a[i]!='\0'){
       c[x]=a[i];
       x++;
       i++;
    }
    while(b[j]!='\0'){
        c[x+j]=b[j];
        j++;

    }
    printf("%s\n",c);
    return c;
}

int main(){
    char s1[100], s2[100];

	printf("Please Enter the first:");
	gets(s1);
	printf("Please enter the second:");
	gets(s2);

    char *ch=func(s1,s2);

    printf("---%s\n",ch);

    system("pause");

    return 0;
}

五、extern

表示外部引用,用extern修饰的变量可以在其它文件中使用
在一个文件中定义的全局变量可以在当前文件中使用extern获取到指定的变量。

六、const

用const来修饰,就意味着该变量里的值可以被访问,不能被修改。

int main(int argc, const char *argv[]) 
{ 
    int a = 100,b = 100;
     //int *p = &a; 
     //*p = 800; 
     //printf("a = %d\n",a); 

    //const int *p = &a; 
    //const修饰的是*p,表示指针指向的地址里面保存的值是一个常量 
    //int const *p =&a; //const修饰的是*p,表示指针指向的地址里面保存的值是一个常量 
    //int * const p = &a; //const修饰的是p,表示指针变量是一个常量,无法修改指针的指 向,但是可以修改指针指向的地址的值 
    const int * const p = &a; //表示指针指向的地址里面保存的值是一个常量,指针的值也是一 个常量(不能改变指针的指向) 
    //*p = 200; 
    p = &b; 
    printf("*p = %d\n",*p); 
    return 0; 
}

七、auto

C语言程序是面向过程的,在代码中会出现大量的函数模块,每个模块都有生命周期,在函数生命周期中声明的变量通常叫作局部变量,也叫作自动变量。

int fun()
{
    int a=10; //auto int a=10
    //do something
    return 0;
}

auto的出现意味着当前变量的作用域为当前函数或代码段的局部变量,意味着当前变量会在内存栈上进行分配。

八、register

用register来修饰,该变量会变成一个寄存器变量,让该变量的访问速度达到最快。
例:一个程序逻辑中有一个很大的循环,循环中有几个变量要频繁进行访问,这些变量可以声明为register类型。

九、volatile

十、typedef

  1. 给变量一个易记期望意义明确的新名字。
  2. 简化一些比较复杂的类型声明。

例1:

typedef long byte_4;

作用:
给已知数据类型long起个新名字,叫做byte_4

例2:

typedef struct tag_my_struct
{
    int i_num;
    long l_length;
}my_struct;

作用:
定义一个新的结构类型

struct tagMyStruct
{
    int i_num;
    long l_length;
};

typedef为这个新的结构起了一个名字,叫作my_struct

typedef struct tag_my_struct my_struct
  • typedef与#define的问题

通常来讲,typedef要比#define要好,特别是在有指针的场合。
其根本原因在于#define只是简单的文本替换,而typedef则是为一个类型起新名字

#define 宏定义有一个特别的长处:可以使用#ifdef、#ifndef 来进行逻辑判断,还可以使用#undef来取消定义。
typedef也有一个长处:它符合范围规范,使用typedef定义的变量类型,其作用范围限制在所定义的函数或者文件内(取决于此变量定义的位置),而宏定义没有这种特性。

十一、复合数据类型

1.struct结构体

#include <stdio.h>
struct Student
{
    int num;
    char name[20];
    int age;
    //结构体中不能保存函数,但可以用函数指针
    void(*func)();
};

void func()
{
    struct Student stu;
}
void print()
{
    pritnf("hello world!\n");
}

int main(int argc,char **argv)
{
    //初始化
    struct Student stu={1,"zhangsan",12};
    struct Student stu2={.num=1,.name="lesi",.age=15,.func=print};
    //如何访问结构体变量
    printf("stu2 num=%d\n",stu2.num);
    printf("stu.name=%s\n",stu.name);
    //结构体指针
    struct Student *pstu=&stu;//*pstu=stu;
    
    printf("stu.num=%d\n",(*pstu).num);
    printf("stu.name=%s\n",(*pstu).name);
    printf("stu.num=%d\n",pstu->num);//(*pstu).num;
    printf("stu.num=%d\n",(&stu)->num);
    //通过键盘给结构体赋值
    scanf("%d",&(stu.num));
    scanf("%s",stu.name);
    scanf("%d",&(stu.age));

}
  • 当结构体使用指针时要记得释放。
#include <stdio.h>
struct Student
{
    int num;
    char *name;
    int age;
};

int mian(int argc ,char **argv)
{
    struct Student stu;
    scanf("%d",&(stu.num));
    stu.name=(char*)malloc(sizeof(char)*100);
    if(NULL==stu.name)
    {
        printf("malloc error!");
        exit(1);
    }
    scanf("%s",stu.name);
    scanf("%d",&(stu.age));
    //释放
    free(stu.name);
    stu.name=NULL;
    
}
  • struct对齐方式:
struct node
{
    char ch1;
    int num;
    char ch;
}

ch1—4,num—4,ch—4
共12个字节

struct node
{   
    char ch;
    char ch1;
    int num;
    
};

ch—4,ch1占用ch开辟的4个字节中剩下的,num—4
共8个字节

  • 强制修改字节
#pragma pack(4)

2. 共用体union

union Student
{
    int num;
    char ch;
};

int main(int agc,char **argv)
{
    union Student stu={.num=1,.ch='a'};
    union Student *pstu=&stu;
    printf("stu.num=%d\n",stu.num);
    printf("stu.ch=%c\n",pstu->num);
}

输出结果:
stu.num=97
stu.ch=a

存储方式:所有成员公用同一段内存空间(最长字节的变量)(数据覆盖)
在这里插入图片描述

  • union的大小
//保存的成员中最大字节长度的成员所决定;
union Student
{
    int num;
    char ch[7];
}

共8个字节

  • 题目
p.num=0;
p.ch[0]=0;
pch[1]=1;

pritnf("p.num=%d\n",p.num);

在这里插入图片描述
输出:256

  • 判断大小端字节序
    大端CPU把高子杰写到低地址上,小端反之。
    在这里插入图片描述
union Student stu2;
stu2.num=0x12345678;

if(stu2.ch==0x78)
{
    printf("Little!\n");
}
else
{
    printf("big!\n");
}

3.enum枚举

//定义一系列的整数宏
enum Result
{
    OK=1;
    NO;
    SUCCESS,
    FAILED
}

int main(int argc,char**argv)
{
    int num=SUCCESS;
    printf("num=%d\n",num);
    return 0;
}

打印为3

  • enum VS #define
    enum优点:定义一系列整数宏更加便捷,在编译阶段。
    #define:预处理、不安全,做傻瓜式替换。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值