嵌入式面试常见问题(一)

目录

1.什么情况下会出现段错误?

2.swap() 函数为什么不能交换两个变量的值 

3.一个函数有六个参数 分别放在哪个区?

4.定义一个变量,赋初值和不赋初值分别保存在哪个区?

5.linux查看端口状态的命令 

6.结构体中->和.的区别 


1.什么情况下会出现段错误?

答:一种可能是栈溢出

        在Linux环境下,每一个用户进程默认有8MB大小的栈空间,如果你在函数内定义大容量的数组或局部变量,就可能造成栈溢出,也会引发一个段错误。内核中的线程也是如此,每一个内核线程只有8KB的内核栈,在实际使用中也要非常小心,防止堆栈溢出

比如查看当前栈的大小,为8M

运行代码如下:

#include
int main()
{
	char buf[8*1024*1024];
	printf("hello world!\n");
	return 0;
}

运行后就会出现如下错误

将栈的大小设置为10M就可以正常输出:

linux进程栈大小最好不要设置为无限大,不然数据不安全

嵌入式面试常见问题(一)_第1张图片

定义大的buf不建议使用数组,一般使用堆区 ,比如malloc

第二种是因为递归

第三种是空指针解引用、数组越界访问、使用已释放的内存

发生段错误的根本原因在于非法访问内存,即访问了权限未许可的内存空间

2.swap() 函数为什么不能交换两个变量的值 

嵌入式面试常见问题(一)_第2张图片

        形参只有在函数被调用时才会在函数栈帧内分配存储单元,用来接收传进来的实参值。函数运行结束后,形参单元随着栈帧的销毁而被释放。变量作为实参传递时,只是将其值复制到形参的存储空间,在函数运行期间,改变形参的值并不会改变原来实参的值,因为两者存储在栈中不同的内存单元上

3.一个函数有六个参数 分别放在哪个区?

        在函数调用过程中,当要传递的参数个数小于4时,直接使用R0~R3寄存器传递即可;当要传递的参数个数大于4时,前4个参数使用寄存器传递,剩余的参数则压入堆栈保存。

嵌入式面试常见问题(一)_第3张图片

        ·在上面的程序中,main()函数调用了f()函数,并传过去6个实参求和。根据ATPCS规则,除了前4个参数使用寄存器R0~R3传递剩下的2个参数要通过压栈来传递。在参数传递过程中,各个参数压栈、出栈的顺序也要有一个约定,如上面的6个参数,是从右往左依次压入堆栈 。

4.定义一个变量,赋初值和不赋初值分别保存在哪个区?

在C语言中,全局变量的存储方式取决于是否给变量赋予了初始值。

  1. 全局变量有初始值

    • 如果全局变量有初始值,它将保存在数据段(Data Segment)中的已初始化数据区(Initialized Data Segment)。
    • 初始化的全局变量在程序执行之前就会被分配内存,并且初始值会在程序加载时被复制到数据段中。
  2. 全局变量无初始值

    • 如果全局变量没有初始值,它将保存在数据段中的未初始化数据区(Uninitialized Data Segment),也被称为BSS段(Block Started by Symbol)。
    • 未初始化的全局变量在程序加载时会被分配内存,但是内存中的值是未定义的通常是0或者是垃圾值)。

5.linux查看端口状态的命令 

在Linux系统中,可以使用以下命令来查看端口状态:

  1. netstat命令:

    netstat -tuln
    

    该命令用于显示当前系统的网络连接、监听端口和网络统计信息。参数说明:

    • -t:显示TCP协议相关的连接和监听端口。
    • -u:显示UDP协议相关的连接和监听端口。
    • -l:仅显示监听状态的端口。
    • -n:以数字形式显示端口和IP地址,而不进行域名解析。
  2. ss命令:

    ss -tuln
    

    该命令也用于显示当前系统的网络连接、监听端口和网络统计信息。参数说明:

    • -t:显示TCP协议相关的连接和监听端口。
    • -u:显示UDP协议相关的连接和监听端口。
    • -l:仅显示监听状态的端口。
    • -n:以数字形式显示端口和IP地址,而不进行域名解析。

这些命令会列出当前系统上正在监听的端口以及与其他主机建立的连接。可以根据需要选择合适的命令,并结合其他参数进行进一步筛选和过滤。

6.结构体中->和.的区别 

在C语言中,结构体(struct)是一种自定义的数据类型,用于组合多个不同类型的变量成为一个单独的实体。当我们定义一个结构体变量后,可以使用两种不同的运算符来访问结构体成员,即->.

  1. -> 运算符:

    • -> 运算符用于访问指向结构体的指针所指向的成员。
    • 当我们有一个指向结构体的指针时,可以使用 -> 运算符来访问结构体成员。
    • 语法:指针变量->成员名
    • 示例:
      struct Person {
          char name[20];
          int age;
      };
      
      struct Person p;
      struct Person *ptr = &p;
      
      ptr->age = 25;  // 使用->访问指针所指向的结构体成员
      
  2. . 运算符:

    • . 运算符用于访问结构体变量的成员。
    • 当我们有一个结构体变量时,可以使用 . 运算符来访问结构体成员。
    • 语法:结构体变量.成员名
    • 示例:
      struct Person {
          char name[20];
          int age;
      };
      
      struct Person p;
      
      p.age = 25;  // 使用.访问结构体变量的成员
      

总结:

  • -> 运算符用于访问指向结构体的指针所指向的成员。
  • . 运算符用于访问结构体变量的成员。
  • 使用 -> 运算符时,操作数必须是指向结构体的指针。
  • 使用 . 运算符时,操作数必须是结构体变量本身。

需要注意的是,如果结构体变量是通过动态内存分配(如使用malloc函数)获得的,那么我们需要使用 -> 运算符来访问结构体的成员。而如果结构体变量是在栈上声明的,那么我们可以使用 . 运算符或 -> 运算符来访问结构体的成员,具体取决于我们使用的是结构体变量还是指向结构体的指针。

你可能感兴趣的:(嵌入式面试题总结,面试,算法,linux,c语言)