C语言基础知识之二维数组,void类型,空结构体,大小端模式,typedef,预处理

C语言基础知识一

一.二维数组

连续存储,即内存地址是连续的。

#include <stdio.h>

int main(int argc, char *argv[])
{
    int a[2][2];
    int i, j;

    a[0][0] = 1;
    a[0][1] = 2;
    a[1][0] = 3;
    a[1][1] = 4;

    //第二种赋值方式,定义加初始化
    int b[2][2] = {1,2,3,4};
    int c[2][2] = {{1,2},{3,4}};

    printf("size:%d\n", sizeof(a));

    // sizeof(a):代表整个二维数组的内存大小
    // sizeof(a[0]):代表二维数组的一行的内存大小
    // sizeof(a)/sizeof(a[0]):就是代表数组总共有几行
    printf("row: %d\n", sizeof(a)/sizeof(a[0]));

    // sizeof(a[0][0])代表二维数组中一个元素的内存大小
    // sizeof(a[0])/sizeof(a[0][0])表示数组总共有几列
    printf("col: %d\n", sizeof(a[0])/sizeof(a[0][0]));

    // 遍历数组
    for (i = 0; i < sizeof(a)/sizeof(a[0]); i++) {
        for (j = 0; j < sizeof(a[0])/sizeof(a[0][0]); j++) {
            printf("a[%d][%d]:%d [%p]\n",i ,j ,a[i][j], &a[i][j]);
        }
    }
    return 0;
}

在这里插入图片描述
二.void类型

*1.void 表示任何类型的指针都可以直接赋值给它,无需进行强制类型转换,反之并不成立。

void *p1;
int *p2;
//正确,
p1 = p2;
//错误,
p2 = p1;

2.void指针
不能对void指针进行算法操作

void *pvoid;
pvoid++;
pvoid += 1;
//主要是进行算法操作的指针必须是确定知道其只想数据类型大小的。

int *pint;
pint++; //正确

void *pvoid;
(char *)pvoid++; //ANSI:正确  GNU: 正确char *)pvoid += 1; // ANSI:错误,GNU:正确

3.const修饰的只读变量

编译器通常不为普通const只读变量分配存储空间,而是将它们保存在符号表中,这使得他成为一个编译期间的值,没有了存储与读内存的操作,使得他的效率也很高的。

如:
#define M 3 //宏常量
const int N = 5; //此时并未将N放入内存

int i = N; //此时为N分配内存,以后不再分配
int I = M; //预编译期间进行宏替换,分配内存
int j = N; //没有内存分配
int J = M; //再进行宏替换,又一次分配内存

修饰指针:

//记忆的诀窍:先忽略类型名,我们看const离哪个近,就是修饰谁。
const int *p;  //p可变,p指向的对象不可变
int const *p;  //p可变,p指向的对象不可变
int * const p; //p不可变,p指向的对象可变
const int * const p; //指针p和p指向的对象都不可变

修饰函数的返回值:

const修饰符也可以修饰返回值,返回值不可被改变
const int Fun(void);
在另一个连接文件中引用const只读变量
extern const int i;     //正确的声明
extern const int j = 10;//错误,只读变量的值不能改变

三.空结构体有多大

#include <stdio.h>

int main(int argc, char *argv[])
{
	struct student {
	}stu;
	//看具体的编译而言的,在vc++6.0上显示为1byte
	//在gcc下编译为0byte
    printf("sizeof(stu) = %d\n", sizeof(stu));
    return 0;
}

四.union类型数据

#include<stdio.h>

union {
    int i;
    char a[5];
} *p,u;

int main()
{
    p = &u;
    p->a[0] = 0x39;
    p->a[1] = 0x38;
    p->a[2] = 0x37;

    // 由于union字节对齐原因,大小为8
    printf("sizeof(u) %d\n", sizeof(u));
    //显示结果是小端模式:即高存高,低存低
    // 0x373839
    printf("i = %#x\n", p->i);
    return 0;
}

五.大端模式和小端模式

#include<stdio.h>

int checkBigEndianOrLittleEndian() {
    union {
        int i;
        char a;
    } ch;

    ch.i = 1;
    return (ch.a == 1);
}

int main() {
    printf("check system : %d\n", checkBigEndianOrLittleEndian());
}

六.typedef

typedef struct student {
	char name[32];
	int age;
} Stu_st, *Stu_pst;

// 其实就是整体上struct student取个别名为Stu_st,将struct student *取个别名Stu_pst
所以
1.struct student stu1  等价于  Stu_st stu1
2.struct student *stu2  等价于 Stu_pst stu2 等价于 Stu_st *stu2

如果将typedef与const放在一起来看看:

const Stu_pst stu3;
Stu_pst const stu4;

//大多数人认为第一个中const修饰的是stu3指向的对象,
//第二个中const修饰的是stu4这个指针。
//其实编译器来说只认为Stu_pst是一个类型名,所以
//上面的两个均是表示为修饰的是stu3,stu4这个指针。

#include<stdio.h>

typedef struct student {
    char name[32];
    int age;
}Stu_st, *Stu_pst;

int main() {
    const Stu_pst stu3 = {"tom", 32};
    Stu_pst const stu4 = {"danny", 18};

    //下面两条语句可以编译通过就证明
    //修饰的是stu3,stu4这个指针,并非stu3,stu4指向的对象。
    stu3->age = 22;
    stu4->age = 23;

    //当指针发生改变时,编译就会报错的
    stu4 = stu3;
    return 0;
}

七.预处理
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值