进击的暑假(一)

该博客围绕C语言复习展开,涵盖strlen和sizeof区别、字符串、数组指针等多种指针类型、数制转换、字节对齐、大小端以及柔性数组等内容,通过多个实例进行讲解,并给出相关原则和笔试题示例。

目录

C语言的复习

1.strlen和sizeof的区别?

2.字符串

3.数组指针、指针数组、函数指针、指针函数

4.数制转换

5.字节对齐

6.大小端 

7.柔性数组


C语言的复习

1.strlen和sizeof的区别?

这是个再基础不过的问题了,直接看代码吧。

实例1:

#include<iostream>
#include<string.h>
using namespace std;

int main()
{
    char str[] = "Hello";
    cout<<strlen(str)<<endl;//5
    cout<<sizeof(str)<<endl;//6多一个‘\0’
    return 0;
}

实例2:

#include<iostream>
#include<string.h>
using namespace std;

int main()
{
    char str[10] = "Hello";
    cout<<strlen(str)<<endl;//此时的长度还是5
    cout<<sizeof(str)<<endl;//此时的大小变为10
    return 0;
}

实例3:

#include<iostream>
#include<string.h>
using namespace std;

int main()
{
    char str[] = {'H','e','l','l','o'};
    cout<<strlen(str)<<endl;//没有字符串结束标志,所以长度是随机的
    cout<<sizeof(str)<<endl;//5
    return 0;
}

实例4:

#include<iostream>
#include<string.h>
using namespace std;

int main()
{
    char str[10] = {'H','e','l','l','o'};//字符串数组的未完全初始化,后面会用0填充
    cout<<strlen(str)<<endl;//5
    cout<<sizeof(str)<<endl;//10
    return 0;
}

 实例5:

#include<iostream>
#include<string.h>
using namespace std;

int main()
{
    char str[10];
    for(int i=0;i<5; ++i)
    {
        str[i] = 'a' + i;
    }
    cout<<strlen(str)<<endl;//gcc环境下是5,vcc环境下是15(具体要看什么时候遇到‘\0’)
    cout<<sizeof(str)<<endl;//10
    return 0;
}

 实例6:

#include<iostream>
#include<string.h>
using namespace std;
char str[10];//全局变量的初始化是用0填充的
int main()
{
    for(int i=0;i<5; ++i)
    {
        str[i] = 'a' + i;
    }
    cout<<strlen(str)<<endl;//5,第六个位置是‘\0’
    cout<<sizeof(str)<<endl;//10
    return 0;
}

实例7 :

#include<iostream>
#include<string.h>
using namespace std;
int main()
{
    static char str[10];//静态变量也是用0来初始化的
    for(int i=0;i<5; ++i)
    {
        str[i] = 'a' + i;
    }
    cout<<strlen(str)<<endl;//5
    cout<<sizeof(str)<<endl;//10
    return 0;
}

实例8:

#include<iostream>
#include<string.h>
using namespace std;
int main()
{
    char *str = "Hello";
    cout<<strlen(str)<<endl;//5
    cout<<sizeof(str)<<endl;//4,str是指针类型(求的是类型的大小)
    return 0;
}

 实例9:

#include<iostream>
#include<string.h>
using namespace std;
void fun(char str[1000])//把str看成指针的类型
{
    cout<<strlen(str)<<endl;//5
    cout<<sizeof(str)<<endl;//4
}
int main()
{
    char str[] = "Hello";
    cout<<strlen(str)<<endl;//5
    cout<<sizeof(str)<<endl;//6,
    fun(str);//真实传送的信息不是整体的数组,而是数组的首地址
    return 0;
}

实例10:

#include<iostream>
#include<string.h>
using namespace std;
short *ar[10][10];//指针数组,ar是数组名,数组里面是short类型的指针
int main()
{
    cout<<sizeof(ar)<<endl;//400
    return 0;
}

实例11:

#include<iostream>
#include<string.h>
using namespace std;
short (*ar)[10][10];//ar是个short类型的指针
int main()
{
    cout<<sizeof(ar)<<endl;//4
    return 0;
}

 实例12:

#include<iostream>
#include<string.h>
using namespace std;
int main()
{
    char *pcColor = "CSOFTX3000";
    char acColor[] = "CSOFTX3000";
    cout<<strlen(pcColor)<<endl;//10
    cout<<strlen(acColor)<<endl;//10
    cout<<sizeof(pcColor)<<endl;//4
    cout<<sizeof(acColor)<<endl;//11

}

PS:

‘\0’实际上就是数字0,前面的反斜杠是转义字符。

全局变量和静态变量都是用0来初始化的。

2.字符串

#include<iostream>
#include<string.h>
using namespace std;

int main()
{
    int val = "0123456789"[3];//常量的字符串
    cout<<val<<endl;//51
    return 0;
}

3.数组指针、指针数组、函数指针、指针函数

int (*a)[3];// 数组指针
int* a[3];//指针数组
int (*a)(int,int);//函数指针
int* a(int,int);//指针函数

 PS:*号的优先级是小于( )和[ ]的,a[ ]是个数组,a( )是个函数,*a是个指针

实例1:

int a;//一个整型数
int* a;//一个指向整型数的指针
int**a;//一个指向指针的指针,它指向的指针是指向一个整型数
int a[10];//一个有10个整型数的数组
int* a[10];//一个有10个指针的数组,该指针指向一个整型数
int(*a)[10];//一个指向有10个整型数的指针
int(*a)(int b);//一个指向函数的指针,该函数有一个整型参数并返回一个整型数
int(*a[10])(int);//一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数

 实例2:

int *(*(*fun))(int*))[10];//fun是个函数指针(参数为int*,返回值为指针),返回指针指向的是有10个整型指针的数组
int (*func) (int*, int(*)(int*));//func是个函数指针,其返回值为整型值,第一个参数为整型指针,第二个参数为函数指针(参数为int*,返回值为int)
int(*func[5])(int*);//func为指针数组,指针指向函数(返回值为int,参数为int*)
int(*(*func)[5])(int *);//func是个数组指针,数组里面有5个函数指针,这些指针是个函数指针(返回值为int,参数为int*)
int(*(*func)(int*))[5];//func是个函数指针(返回值为指针,参数为int*),返回的指针指向一个有5个整型的数组
int*(*func(int*))[5];// func是个指针函数 ,指向一个有5个整型指针的数组

 实例3:

将实例2中的复杂声明,用typedef改写。

int *(*(*fun))(int*))[10];
等价于
typedef int* Ar[10];
typedef Ar* (*Fun)(int*);
Fun fun;
**********************************
int (*func) (int*, int(*)(int*));
等价于
typedef int(*Pfun)(int*)
typedef int (*Func)(int*,Pfun pf);
Func func;
**********************************
int(*func[5])(int*);
等价于
typedef int(*pFun)(int*);
typedef pFun(*Func)[5];
Func func;
**********************************
int(*(*func)[5])(int *);
等价于
typedef int(*Pfunc)(int *);
typedef Pfunc(*Func)[5];
Func func;
**********************************
int(*(*func)(int*))[5];
等价于
typedef int *Ar[5];
typedef Ar*(*pFun)(int*);
pFun func

**********************************
int*(*func(int*))[5];
等价于
typedef int* Ar[5];
Ar*func(int*);

 这块的东西比较绕,不建议直接给出结论,很有可能会出错,还是一步一步来说明比较好.

4.数制转换

整数转二进制和多进制。 

5.字节对齐

实例1:

#include<iostream>
#include<stack>
using namespace std;

typedef struct Test
{
    short a;//2+6
    struct//实际的变量
    {
        int b;//4+4
        double c;//8
        char d;//1+7
    };
    long e;//4+4
}Test;
int main()
{
    cout<<sizeof(Test)<<endl;//40
    return 0;
}

实例2:

#include<iostream>
#include<stack>
using namespace std;
#pragma pack(4)
typedef struct Test
{
    short a;//2+2
    struct t
    {
        int b;//4
        double c;//8
        char d;//1+3
    }tt;//有tt,有实际的大小
    long e;//4
}Test;
int main()
{
    cout<<sizeof(Test)<<endl;//24
    return 0;
}

 实例3:

#include<iostream>
#include<stack>
using namespace std;
#pragma pack(4)
typedef struct Test
{
    short a;//2+2
    struct t//是个类型,可以不用管
    {
        int b;//4
        double c;//8
        char d;//1+3
    };
    long e;//4
}Test;
int main()
{
    cout<<sizeof(Test)<<endl;//8
    return 0;
}

 实例4:

#include<iostream>
#include<stack>
using namespace std;
#pragma pack(4)
typedef struct Test
{
    char a:3;//位域
    char b:2;
    char c:1;
}Test;
int main()
{
    cout<<sizeof(Test)<<endl;//1
    return 0;
}

实例5:

#include<iostream>
#include<stack>
using namespace std;
#pragma pack(4)
typedef struct Test
{
    char a:3;//位域
    char b:2;
    char c:1;
    char d:3;//位域是不跨字节存储的
}Test;
int main()
{
    cout<<sizeof(Test)<<endl;//2
    return 0;
}

 实例6:

#include<iostream>
#include<stack>
using namespace std;
typedef struct Test
{
    char a:3;//1+3,只用了3个bit位
    int b:2;//4,只用了2个bit位
}Test;
int main()
{
    cout<<sizeof(Test)<<endl;//8
    return 0;
}

实例7:

#include<iostream>
using namespace std;
int main()
{
    typedef struct Test{
    }T;
    cout<< sizeof(T)<<endl;//1
    return 0;
}

实例8:

#include<iostream>
using namespace std;
#pragma pack(4)
unsigned short *puc[10][10];
typedef union unRec{
    unsigned long ull;
    unsigned short usl[7];
    unsigned char ucp;
}REC_S;
REC_S stm, *pst;
int main()
{
    cout<< sizeof(puc) <<endl;// 400
    cout<< sizeof(stm) <<endl;// 16(按四字节对齐)
    cout<< sizeof(pst) <<endl;// 4
    cout<< sizeof(*pst) <<endl;// 16
    return 0;
}

PS:掌握两个原则:(1)不跨字节存储(2)不跨类型存储

实例9:

#include<iostream>
using namespace std;
struct Test
{
    int a;// 4 + 4
    double b;// 8
    char c; // 1 + 3
    int p[0];//4
};

int main(){
    //Test t;
    cout<< sizeof(Test)<<endl;//24
    return 0;
}

6.大小端 

什么是大小端?

如果在允许调试的情况下,直接定义一个int x = 1,然后调试去看其内存到底是怎么存的,是大端还是小端。大小端的主要区别:在输出的时候,方向是不同的。无论是大端存储还是小端存储,都需要保证存入的是什么值,输出的也是什么值。

下面是用编码的方式来检查机器的大小端。

#include<iostream>
using namespace std;
bool CheckModule()
{
    union {
        char ch;
        int a;
    }un;
    un.a = 1;
    return un.ch == 1;//从低地址开始拿数据
}
int main()
{
    bool flag = CheckModule();
    if(flag)
        cout<<"This is Little Modle."<<endl;
    else
        cout<<"This is Big Modle."<<endl;
    return 0;
}

下面来看一道关于大小端的笔试题:

#include<iostream>
#include <iomanip>
using namespace std;
int main()
{
    union {
        short k;
        char i[2];
    }*s,a;
    s = &a;
    s->i[0] = 0x39;
    s->i[1] = 0x38;
    cout<<setbase(16) <<a.k<<endl;// 3839
}

联合体应用的例子(IP的整数表示转点分十进制)

#include<iostream>
using namespace std;
union IP{
    unsigned long val;
    struct {
        unsigned char ip1;
        unsigned char ip2;
        unsigned char ip3;
        unsigned char ip4;
    };
};
int main()
{
    unsigned long value = 749194;
    IP ip;
    ip.val = value;
    cout<<(int)ip.ip1<<"."<<(int)ip.ip2<<"."<<(int)ip.ip3<<"."<<(int)ip.ip4;
}

PS:按小端存的话就用小端的方式读,按大端存的话就用大端的方式读。

7.柔性数组

1.字符型的柔性数组环境vc6.0下

#include<iostream>
using namespace std;
struct Test
{
    int a;// 4 + 4
    double b;// 8
    char c[0]; //0 柔性数组不开辟空间
};

int main(){
    char str[] = "hello cpp.";
    Test t;
    cout<<t.c<<endl;// hello cpp
    return 0;
}

2. int 型的柔性数组

#include <iostream>
using namespace std;

struct Test
{
    int a ;
    double b;
    int pi[0];//柔性数组,在结构体内不需要开辟空间,只能放在结构体的最后一个
};//无论开辟的整型数组有多大,结构体的大小总是不变的
int  main()
{
    Test *pt = (Test*)malloc(sizeof(Test) + sizeof(int ) * 10);

    for (int i = 1; i <= 10 ; ++i) {
        pt->pi[i -1] = i;
    }

    for (int i = 0; i < 10; ++i) {
        cout<<pt->pi[i]<<" ";
    }
    free(pt);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值