C语言基础

一.请描述下堆和栈的区别

1.内存方面:

        在内存中一般由系统管理,按照先进后出的原则,栈的空间容量较小,访问速度相对较快。堆在内存中由程序员手动申请和释放,使用完毕一定要释放不然会造成内存泄漏,堆的空间容量相对较大,可以动态的扩展空间,由于堆访问需要通过指针寻址,所以访问速度相对较慢。

2.数据结构方面:

        栈是顺序存储结构,在数据结构中一般分为顺序栈与链式栈,存储的数据一般先进后出。

        堆在数据结构中一般用二叉树实现,分为大顶堆和小顶堆。

二.指针数组和数组指针的写法

1.指针数组

指针数组本质是数组,数组里面存放的是指针(变量的地址)。

 例如: int a = 10;

           int b = 20;

            int c = 30;

            int *arr[3] = {&a, &b, &c};

2.数组指针

数组指针本质是一个指针,指向的是一个数组的地址

例如:int arr[3] = {10, 20, 30};

           int (*p)[3] = &arr;

注意:在这里为什么要定义成这样,如果我们定义成int *p[3] = &arr;那么分析一下,由于[]的优先级比*高,所以在这里是定义了一个p数组,类型是int *型,所以要将二者括起来(*p),让*p是一个整体。

三.函数指针和指针函数的写法,函数指针一般用在什么地方?

1.函数指针

函数指针本质上是一个指针,指向一个函数

写法:

int (*pFunc)(int, int)

2.指针函数

指针函数本质上是一个函数,返回的类型是一个指针类型

写法:

int *pfunc(int, int)

3.二者的用法

函数指针一般用在调用函数(需要调用函数大小不知道函数名,只知道函数地址的情况)和作为函数的参数,建立函数指针表(函数指针数组)管理多个函数。

指针函数一般用在根据条件动态选择需要使用的函数。

四.请描述C语言五种内存模型

1. BSS段(Block Started by Symbol): 用来存放程序中未初始化的全局变量和静态变量的内存区域,在程序执行前会被清零。

2. 数据段(data segment): 用来存放程序中已初始化的全局变量和静态变量的内存区域。

3. 代码段(text segment): 用来存放程序执行代码的内存区域。

4. 堆(heap):用来存放进程运行中被动态分配的内存段,大小不固定,可动态扩张或缩减。调用malloc分配内存时,新分配的内存就被动态添加到堆上,调用free释放内存时,会从堆中释放。

5. 栈(stack):存放程序中的局部变量,函数参数,返回地址(但不包括static声明的变量,static变量放在数据段中),以及函数调用的上下文的信息。

五.指针常量与常量指针的定义以及区别,分别用在什么地方?

int a = 10;
int b = 20;
int const *p = &a;    //常量指针,指针是一个常量,指针p不能修改变量a的值,但是可以修                    
                       改p的指向。
const int *p = &a;    //常量指针, *p = 20不可以,p = &b可以;
int* const p = &a;    //指针常量,指向的是一个常量的地址,指针p不能修改指向但是可以修 
                        改变量a的值。 p = &b不行, *p = b可以。

        常量指针一般用值传递,可以确保传递的值不被修改。

        指针常量可以确保指针指向的地址不会改变,不会意外指向其他的非法地址,减少段错误的出现概率。

六.strlen与sizeof的区别?

        strlen是一个函数,主要计算字符串'\0'之前的长度。

        sizeo是一个关键字,主要用于计算类型的大小。

char buf[64] = {"hello"};
char *p = buf;
char buf2[] = {"hello"};

strlen(buf);  //5,字符串长度为5
sizeof(buf);  //64, char占一个字节,64个char大小为64

strlen(p);   //5, 字符串长度为5
sizeof(p);   //32位系统中大小为4, 64位系统中大小为8

strlen(buf2);  //5 字符串长度为5
sizeof(buf2);  //6, 数组最后结尾包括了'\0',所以大小为6

7.define与typedef的区别?

1.用法不同:

        typedef用来定义一种数据类型的别名,增强程序的可读性

        define主要用来定义常量,以及书写复杂使用频繁的宏。

2.执行时间不同:

        typedef是编译过程的一部分,有类型检查的功能。

        define是宏定义,是预处理阶段的部分,在编译前,只进行字符串的替换,没有类型的检查。

3.作用域不同:

        typedef有作用域限定。

        define不受作用域约束,只要是在define声明后的引用都可以使用。

8.const关键字的含义以及常见用法

1.const+类型:使该类型变成常量,也就是该类型的值为常量。

2.const+变量:使该变量成为常量。

3.const+指针:指针常量int const *p/const int *p,指针存放的值不能改变,指向的地址以改变。

                         常量指针int* const p,指针指向的地址不可改变,所存放的值可以改变。

使用const可以防止因为意外修改数据导致程序出现错误。

9.C语言程序文件的编译过程分为几个步骤?每个步骤都做什么事情?

1.预处理阶段(-E): 将C语言源程序预处理,生成.i文件。

2.编译阶段(-S): 预处理后的.i文件编译成为汇编语言,生成.s文件。

3.汇编阶段(-C): 将汇编语言文件经过汇编,生成目标文件.o文件。

4.链接阶段(-O): 将各个模块的.o文件链接起来生成一个可执行程序文件。

10.编写一个程序,判断当前是大端字节序还是小端字节序

1.用指针来写

unsigned char num = 0x12345678;     //左边为高地址
char *p = (char *)#
if (*p == 0x78)
{
    //小端(高对高,低对低)
}
else
{
    //大端(高对低,低对高)
}

2.使用联合体

union
{
    int num;
    char c;
}port;

port.num = 0x12345678;
if (port.c == 0x78)
{
    //小端(高地址存放低字节,低地址存放高字节)
}
else
{
    //大端(高地址存放高字节,低地址存放低字节)
}

11.编写类似strcpy函数的实现,函数原型: char *strcpy(char *strDest, const char *strSrc);

char *strcpy(char *strDest, const char *strSrc)
{
    assert((*strDest != NULL) && (*strSrc) != NULL);
    char *p = strDest;
    while ((*strDest++ = *strSrc++) != '\0')
    {
        return p;    
    }
}

12.编写类似atoi函数的实现,函数原型:int atoi(char *str);

这里的atoi函数实现了0-9字符串转整数0-9,通过遍历字符串的每一位,将每个字符转换成整数再将其移动到前面一位。

int aoti(char *str)
{
    assert(str != NULL) //判断输入是否合法
    int result = 0;      //计算结果
    int sign = 1;        //标志位0和1  1表示正数 0表示负数
    int index = 0;       //记录下标
    
    if (str[0] = '-')
    {
        sign = -1;        
        index = 1;
    }

    for (; str[i] != '\0'; ++i)
    {
        assert(str[i] >= '0' && str[i] <= '9');  //如果中间出现非数字字符则报错
        assert(result <= INIT_MAX / 10);          //判断是否越界  INIT_MAX是int的最大值
        result = result * 10 + (str[i] - '0');  //将遍历到的字符串asii码减去'0'得到数字 然后                
                                                   *10将当前位移到前面一位
    }
    return result * sign; 
}

后记

        本人是一个马上毕业的小白,这是我人生中的第一篇博客,秉持着将博客作为笔记本的理念,将近期学到的比较重要的东西归纳总结出来,俗话说万事开头难,加上本人文笔有限,所以本文中可能出现比较多的错误,希望各位大佬能够多多批评指导,也希望通过这个平台,加强自己的专业素养,未来也能够做到独挡一面的嵌入式工程师。

        

  • 16
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值