1.
(1)题目
外部变量,指的是处于函数外部的全局静态变量,所以选c
(2)知识点
1. static
(1)函数外部的全局变量
当一个变量在函数外部定义并使用static
关键字修饰时,这个变量的作用域被限制在定义它的源文件内部。其他源文件无法直接访问该变量
(2)函数内部的局部范围
当static关键字用于函数内部的局部变量时,该变量的生命周期将扩展到整个程序的运行周期,而非一般的函数调用周期,这个变量在第一次进入进入声明它的函数时给它分配内存并初始化,切在后续调用该函数时,变量保留其值,不再重新分配内存并初始化
2.
本题,a 0-7 b 8-15 c 16-23 答案为c,三个字节
(1)位域
位域通过在结构体中定义具有指定宽度(以位为单位)的成员来实现
在 C 语言中,位域(Bit Fields)是一种特殊的结构体成员,允许用户定义和操作位级别的数据。位域主要用于内存紧凑型数据存储和对硬件寄存器的直接操作。每个位域成员可以占用结构体中一个或多个比特位,而不是通常的字节单位
#include <stdio.h>
struct BitField {
unsigned int a : 3; // 占用3个比特位
unsigned int b : 5; // 占用5个比特位
unsigned int c : 2; // 占用2个比特位
};
int main() {
struct BitField bf;
bf.a = 5; // 5的二进制是101,占3位
bf.b = 17; // 17的二进制是10001,占5位
bf.c = 2; // 2的二进制是10,占2位
printf("a: %u, b: %u, c: %u\n", bf.a, bf.b, bf.c);
return 0;
}
(2)结构体存储(内存对齐原则)
1. 结构体成员变量只能存放在内存地址为自身基本类型长度整数倍的内存单元中
2. 结构体大小必须为最大成员变量类型整数倍的大小
3. 程序入栈出栈遵循先入后出
4. c语言运算符优先级和结合性
(1)优先级
()[] -> . > 单目 > 双目 > 三目 > 逗号运算符
特例: ||(逻辑或三目) > 赋值运算符(双目) > 逗号运算符
(2)结合性
大部分自左至右
单目运算符、三目运算符(? ;)、赋值运算符 自右向左
5. 大小端字节序
(1)小端存储:低地址存放低数据位、高地址存放高数据位
(2)大端存储:低地址存放高数据位、高地址存放低数据位
共用体
int x 地址 char y
44 0x2000 0
33 0x2001 1
22 0x2002 2
11 0x2003 3
6. 函数指针
(1)定义
指向函数的指针
(2)定义函数指针
例如需要定义一个返回值为整数,并接收两个整数参数的函数
int add(int a, int b) {
return a + b;
}
int (* fun)(int, int);
7. 已知一个数组table,用一个宏定义,并求出数据的元素个数
#include <stdio.h>
#define TABLE {1, 2, 3, 4, 5}
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
int main(void)
{
int table[] = TABLE;
int size = ARRAY_SIZE(table);
return 0;
}
8. static的用途
(1)静态全局变量:限制全局变量的作用域,使其只在声明它的文件内可见
(2)静态局部变量:延长局部变量的生命周期,使其在函数多次调用间保持其值
(3)静态函数:限制函数的作用域,使其只在声明它的文件内可见
9. 数组和链表的区别
(1)内存分配和空间访问
1. 数组
数组在内存空间分配时是连续的,访问元素只需要通过数组下标访问即可
2. 链表
链表的内存空间分配是动态变化的,不连续,访问元素要通过指针遍历链表
(2)插入和删除数据
1. 数组
数组在删除和插入数据时,需要移动其他元素来保持数组的连续性,比较繁琐
2. 链表
链表的插入和删除元素不需要移动其他元素,只需要通过指针来操作链表节点即可
(3)适用场景
1. 数组
数组适用于频繁访问元素的场景
2. 链表
适用于频繁插入和删除的场景
(4)实现复杂度
1. 数组
只需要简单创建即可
2. 链表
需要创建链表标签、各节点结构体和指针操作
10.
第三句代码解析:ptr++ 后置++,先用后加
*(ptr++) += 100;
*ptr = *ptr + 100;
ptr++;
11.
对传入的指针str要进行操作来改变指向,需要传二级指针
void GetMemory(char **p)
{
*p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str);
}
12.
主函数中a只是一个char型字符变量,不能进行长字符串的拷贝
#include <stdio.h>
#include <string.h>
int main(void)
{
char a[32] = {0};
char *str = a;
strcpy(str, "hello");
printf("%s\n", str);
}
13.
unsigned char ucCmdNum; 中ucCmdNum取值范围是0~255
此题中超出作用范围,会陷入死循环
14.
本题中,考察对memcpy源代码的理解,函数形参和返回值均为void
void *memcpy(void *dest, const void *src, size_t n)
{
unsigend char *d = (unsigend char *)dest;
const unsigend char *s = (const unsigend char *)src;
size_t i = 0;
for (i = 0; i < n; i++)
{
d[i] = s[i];
}
return dest;
}
15.
int strcmp(char *source, char *dest)
{
while (*source == *dest && *source != '\0')
{
source++;
dest++;
}
return *source - *dest;
}
16. 实现单向链表的冒泡排序(以无头链表为例子)
int LinklistBubbleSort(Linklist *plist)
{
Linknode *ptmpnode1 = NULL;
Linknode *ptmpnode2 = NULL;
Linknode *pendnode = NULL;
Datatype tmpdata = 0;
ptmpnode1 = plist->phead;
if (NULL == ptmpnode1 || NULL == ptmpnode1->pnext)//判断链表是否为控链表或只有一个元素
{
return -1;
}
while (1)
{
ptmpnode1 = plist->phead;
ptmpnode2 = ptmpnode1->pnext;
if (pendnode == ptmpnode2)//排序结束的标志
{
break;
}
while (ptmpnode2 != pendnode)
{
if (ptmpnode1->data > ptmpnode2->data)
{
tmpdata = ptmpnode1->data;
ptmpnode1->data = ptmpnode2->data;
ptmpnode2->data = tmpdata;
}
ptmpnode1 = ptmpnode1->data;
ptmpnode2 = ptmpnode2->data;
}
pendnode = ptmpnode2;
}
return 0;
}