数组

数组初始化方法

/* 以下为自动类型 */
​
/* 一维数组 */
int arr[] = {1, 3, 5}; //不指定长度,由编译器自动计算
int arr[5] = {0, }; //指定长度,按顺序初始化元素,未初始化的会自动初始化为0
​
int arr[] = {1, 3, [5]=2, [0]=3, 6, };
//可以通过指定下标初始化,不连续的部分自动初始化为0,先前元素的值以最后一个初始化结果为准
//以上数组成员等同于{3, 3, 0, 0, 0, 2, 6},编译器会把数组大小设置成能装下所有初始值
​
/* 二维数组 */
int arr[2][2] = {1,3,[1][1]=5,}; //和一维数组类似
int arr[][2] = {{1,3}, {2, 4}}; //必须指定列数

和指针的关系

#include <stdio.h>
​
int main(int argc, char const *argv[])
{
   int arr[2][2] = {1,3,[1][1]=5,};
   int *p = arr[0];
   int size = sizeof(arr)/sizeof(int);
   for(int i=0; i<2; i++) {
       for(int k=0; k<2; k++)
           printf("ptr = %p       val = %d\n",(*(arr+i))+k, *(*(arr+i)+k));
  }
   printf("%d,",arr[0][0]);
   printf("%d,",arr[0][1]);
   printf("%d,",arr[1][0]);
   printf("%d\n",arr[1][1]);
   printf("sizeof p = %d, p=%p\n", sizeof(p), p);
   printf("sizeof arr = %d, sizeof int = %d\n", sizeof(arr), sizeof(int));
   printf("arr = %p, arr+1 = %p arr[0][0] = %d\n", arr, arr+1, *p);
​
   return 0;
}
pi@WIN-3MPRRM0J097:/mnt/c/Users/Administrator/Desktop$ ./test
ptr = 0x7fffcec1bc90       val = 1
ptr = 0x7fffcec1bc94       val = 3
ptr = 0x7fffcec1bc98       val = 0
ptr = 0x7fffcec1bc9c       val = 5
1,3,0,5
sizeof p = 8, p=0x7fffcec1bc90
sizeof arr = 16, sizeof int = 4
arr = 0x7fffcec1bc90, arr+1 = 0x7fffcec1bc98 arr[0][0] = 1

指针

在C中,指针+1指的是 【增加一个存储单元 】。对数组而言,指针+1后的地址是下一个元素的地址,而不是下一个字节的地址。所以,这就是为什么必须声名指针所指向对象的类型的原因之一:只知道地址还不够,还有知道指向对象存储多少字节,否则不能正确取回地址上的值。

枚举

enum color{ <---------  枚举类型名(可以不写)
   red, <----- 成员名(是常量,默认从0开始)
   pink = 2,
   blue   <----- 会从3开始
}my_color; <------- 变量名(可以不写并单独定义,可以同时定义多个,只能赋值成员的值,否则无意义)

联合体

union Data          <-------类型名(可以不写)
{   <------Data 将占用 20 个字节的内存空间
  int i;
  float f;
  char  str[20];
}data; <-------变量名

结构体对齐

#pragma pack(8) //ANSI C
​
__attribute__ ((packed)) //GNU C 取消结构体对齐

类型强制转换

丢失精度:比如int 类型抓换成char类型将会丢失高位数据。

升级:int -> unsigned int -> long -> unsigned long -> long long -> unsigned long long -> float -> double -> long double

注意将int 负数转换成unsigned int 后会变成一个很大的正数。

运算符

优先级:

短路原则:|| (逻辑或)和&& (逻辑与)都有短路原则

浮点数比较

C 中默认浮点常量为double类型,浮点数比较都不能使用== 或者 !=运算符

float的有效值小数点后6位

与零比较 if(num >= -0.000001 && num <= 0.000001)

inline

函数调用都有一定的开销,内联函数会用内联代码替换函数调用。编译器可能会用内联代码替换函数调用,并(或)执行一些其他优化,但是也可能不起作用。由于并未给内联函数预留单独的代码块,所以无法获得内联函数的地址(实际上能够获得地址,但是这样做之后编译器将会生成一个非内联函数)。

内联函数一般较为短小,如果函数执行的时间比调用的时间多太多,也就失去了内联优化的意义。

inline static void eatline(void)
{
   while(getchar() != '\n')
      continue;
}
int main()
{
  ...
       eatline();
  ...
}
/*===================================================*/
//编译器会把内联函数的调用做成以下形式
int mian()
{
  ...
   while(getchar() != '\n')
       continue;
  ...
}

const

const限定符告诉编译器 const修饰的变量是一个只读变量,从而对这个变量起到保护的作用,如定义一个指向只读变量的指针并把这个指针指向一个只读寄存器。

我们不能直接修改这个变量的值,虽然我们可以用一个指针指向这个只读变量并修改它,但是这样做是危险且无意义的。

volatile

volatile 限定符告诉编译器 volatile修饰变量的值可能会被不是程序本身改变。因此,这样程序调用的时候就会每次到相对应的内存地址中读取。

使用volatile的情况有3种:

//1、指向寄存器的指针。因为该指针指向的值在程序运行过程中可能会被硬件置位。
   unsigned int * reg = 0x1234FFFF;
//2、在中断中使用的全局变量。应为该全局变量随时被主程序或者中断程序修改。
//3、在多线程中共同使用的全局变量。应为该全局变量随时会被其他进程修改。

register

存储类别说明符register可以声明寄存器变量。编译器必须根据必须根据寄存器或最快可用内存的数量来衡量你的请求,或者直接忽略你的请求。注意 对于register变量不能使用地址运算符(取地址),因为CPU寄存器不是内存,没办法使用内存的操作方式。

static

存储类别说明符static修饰的变量具有静态存储周期(他们在内存的地址不变,并且在离开他们所在的函数后这些变量不会消失)。static修饰的全局变量和函数具有文件作用域(无连接),这将不能在其他文件中调用这些全局变量和函数。

对于函数,在定义时除非使用static 关键字,否则默认使用extern (全局作用域)。

extern

我们可以使用extern引用声明一个外部变量(全局变量)或函数。注意 外部变量只能初始化一次,且必须在定义该变量的时候。C99和C11只要求编译器识别局部标识符的前63个字符和外部标识符的前31个字符。

宏定义

定义一个标准MIN宏

#define MIN(x, y)   \
({ \
   typeof(x) __tmp0 = (x); \ //防止i++的情况
   typeof(y) __tmp1 = (y); \
  (void) (&__tmp0 == __tmp1); \
       //如果两个变量的类型不一样,那么编译器就会给一个warning,加上void是防止部分编译器在不使用运算结果时报warning
       __tmp0 < __tmp1 ? __tmp0:__tmp1;
})

宏定义的作用:在程序预处理的时候进行文本替换

头文件中:#ifndef #define #endif的作用:防止头文件重复包含

宏定义中##的作用:将两个宏记号组合成一个

#define FUNC_ARG(x) arg ## x
//当x为0时,该宏替换之后为 arg0

宏定义在#的作用:将宏参数视为一个字符串

#define DBUG_PRINT(x)   printf("DEBUG:" #x "\n");
//如果x为hello,该宏替换之后为 printf("DEBUG:" "hello" "\n");

已经内置且不能取消定义的宏:

__FILE__    //当前程序的.c文件名
__TIME__ //编译时间
__DATE__ //预处理的日期
__LINE__ //当前行号
   
__func__ //预定义标识符,不是宏定义。当前函数名(C99)

#line和#error

#line //指令重置__LINE__和__FILE__ 宏报告的行号和文件名
#line 100 //将当前行号设置为100
#line 200 "hello.c" //把当前行号设置为10,把文件名设置为hello.c
​
#error //指令让预处理器发出一条错误消息,该消息包含指令中的文本。
//如果可能的话,编译过程应该中断。
#ifndef XXX
#error undefined XXX
#endif
​
//编译器输出结果如:xxx.c:13:2:error: #error undefine XXX

typedef

typedef一个指向函数的指针

typedef int (*pfunc_t)(int *args,unsigned int size);//给函数指针起个别名
​
pfunc_t func;//定义一个函数指针
​
int cut(int *args, unsigned int size)
{
   return size;
}
​
func = cut;

全局变量(外部变量)

未初始化的全局变量会自动初始化为0,这适用于数组和自定义元素(结构体等)。

全局变量只能使用常量进行初始化。

复合字面量

C99允许使用复合字面量。字面是除符号常量外的常量由于复合字面量是匿名的所以不能先创建然后在使用它,必须在创建的同时使用它。复合字面量是提供只临时需要的值的一种手段。

int *p;
p = (int[]){1,2,4,5}; //可以指定数组大小也可不写让编译器自动识别
​
printf("hello!" "world\n"); //编译器会将两个字符串常量进行拼接

malloc()/calloc()/free()

void * malloc(size_t size);
void free(void *ptr); //不能双重释放一个指针,但是可以释放一个空指针
void *calloc(size_t nmemb, size_t size); //申请到的内存值会初始化为0

存储类别

存储类别 存储期 作用域 链接 声名方式
自动 自动 块 无 块内
寄存器 自动 块 无 块内,使用register关键字
静态外部链接 静态 文件 外部 所有函数外
静态内部链接 静态 文件 内部 所有函数外,使用static关键字
静态无链接 静态 块 无 块内,使用register关键字

存储空间

BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的或者初始值为0的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。

数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

代码段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新 分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

栈(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变 量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以 栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

断言库

assert.h 头文件支持的断言库是一个用于辅助调试程序的小型库。

//#define NDEBUG    //该宏可以关闭assert(),如果需要开启断言可以注释此行
#include <assert.h>
int main()
{
...
      assert(z > 0);
  ...
}
assert()宏接受一个整形表达式作为传参。如果表达式的值为假,assert()宏就在标准错误流(stderr)中写入错误信息,从而打印到屏幕上。并调用abort()函数终止程序。如果assert()终止了程序,它首先会显示失败的测试、包含测试的文件和行号。

Linux C语言面试考点的更多相关文章

  1. C语言面试问答(3)

    12个滑稽的C语言面试问答——<12个有趣的C语言问答>评析(3) 前文链接:http://www.cnblogs.com/pmer/p/3322429.html 5,atexit wit ...

  2. linux驱动工程面试必问知识点

    linux内核原理面试必问(由易到难) 简单型 1:linux中内核空间及用户空间的区别?用户空间与内核通信方式有哪些? 2:linux中内存划分及如何使用?虚拟地址及物理地址的概念及彼此之间的转化, ...

  3. 转载~kxcfzyk:Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解

    Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解   多线程c语言linuxsemaphore条件变量 (本文的读者定位是了解Pthread常用多线程API和Pthread互斥锁 ...

  4. 10个经典的C语言面试基础算法及代码

    10个经典的C语言面试基础算法及代码作者:码农网 – 小峰 原文地址:http://www.codeceo.com/article/10-c-interview-algorithm.html 算法是一 ...

  5. 阿里Linux Shell脚本面试25个经典问答

    转载: 阿里Linux Shell脚本面试25个经典问答 Q:1 Shell脚本是什么.它是必需的吗? 答:一个Shell脚本是一个文本文件,包含一个或多个命令.作为系统管理员,我们经常需要使用多个命 ...

  6. Linux C语言操作MySQL

    原文:Linux C语言操作MySQL 1.MySQL数据库简介 MySQL是一个开源码的小型关系数据库管理系统,体积小,速度快,总体成本低,开源.MySQL有以下特性: (1) 使用C和C++编写, ...

  7. C语言面试问答5

    12个滑稽的C语言面试问答——<12个有趣的C语言问答>评析(5) 前文链接:http://www.cnblogs.com/pmer/archive/2013/09/17/3327262. ...

  8. linux c语言定时器

    原文来自于:http://hi.baidu.com/opetrhsxszbckzd/item/126966cae5f9524aa9ba94f5 我只是把其重新排版标注一下. linux c语言定时器 ...

  9. Linux改变语言设置的命令

    --Linux语言设置--------------2013/09/22Linux中语言的设置和本地化设置真是一个很繁琐的事情,时不时的会出现乱码的情况,在这篇文章中讨论的是shell中出现乱码的一些解 ...

  10. linux c语言 select函数用法

    linux c语言 select函数用法 表头文件 #i nclude<sys/time.h> #i nclude<sys/types.h> #i nclude<unis ...

随机推荐

  1. AWS服务 简介

    1 Amazon Elastic Compute Cloud (Amazon EC2) 是一种提供可调节计算容量的 Web 服务 – 简单来说,就是 Amazon 数据中心里的服务器 – 您可以使用它 ...

  2. dotnet core微服务框架Jimu介绍

    jimu是一个基于.Net6.0 简单易用的微服务框架,参考了很多开源库以及想法,使用了大量的开源库(如 DotNetty, consul.net, Flurl.Http, Json.net, Log ...

  3. 串(C语言实现)

    文章目录 1.串的数据类型定义 数据对象 1.1 数据关系 1.2 基本操作 2.串的存储结构 2.1 串的顺序存储 2.2 串的链式存储 3.串的模式匹配算法 3.1BF 算法 3.2KMP 算法 ...

  4. 顺序表(C语言)

    文章目录 1.定义顺序表结构体 2.初始化顺序表 3.插入元素 3.1顺序表头插 3.2 顺序表尾插 4.删除顺序表指定元素 5.查找元素 6.输出顺序表 7.销毁顺序表 在数据结构的世界里,顺序表是 ...

  5. Win11右键默认显示更多设置

    以管理员方式运行CMD,运行: reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2} ...

  6. Linux_rpm包的管理

    介绍 rpm用于互联网下载包的打包及安装工具,它包含在某些Linux分发版中.它生成具有.RPM扩展名的文·件.RPM是RedHat Package Manager ( RedHat软件包管理工具)的 ...

  7. Lattice ICE40LP8K开发

    一.开发工具: ICEcube2,界面非常原始,只有PLL IP核添加功能,其他IP核貌似只能使用primitive替换. 不支持时序分析.在线仿真等功能. 二.原语使用 全局布线资源 在 iCE40 ...

  8. zookeeper 分布式锁服务

    分布式锁服务在大家的项目中或许用的不多,因为大家都把排他放在数据库那一层来挡.当大量的行锁.表锁.事务充斥着数据库的时候.一般web应用很多的瓶颈都在数据库上,这里给大家介绍的是减轻数据库锁负担的一种 ...

  9. Nuxt.js 应用中的 webpack:progress 事件钩子

    title: Nuxt.js 应用中的 webpack:progress 事件钩子 date: 2024/11/27 updated: 2024/11/27 author: cmdragon exce ...

  10. sql注入-数据库表基本操作

    一.数据库 linux下登录: mysql -u root -p 查看数据库: show databases; 可以在phpmyadmin面板点击SQL进行操作 1. 增加/创建 创建xxx数据库,并 ...