文章目录
- 1、动态开辟一个M*N的二维数组
- 2、动态开辟空间失败了,有什么异常捕获机制
- 3、宏定义:计算数组大小
- 4、C语言中可以定义一个函数来计算数组大小吗
- 5、宏定义:计算两个数中比较小的那一个
- 6、写出来,一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
- 7、广度展开树
- 8、C语言有几种排序,具体实现代码
- 9、排序的时间复杂度
- 10、重载函数,指针向量,引用
- 11、指针常量,常量指针,const
- 12、调用的哪个函数,foo能否执行
- 13、#define 定义一个常量 表示全年一共多少秒
- 14、设计一个函数,实现字符串逆序
- 15、有符号和无符号运算问题
- 16、结构体对齐问题,一个char,一个int,一个short,如何占空间最小
- 共用体占用内存
- 17、关键字 static 的作用是什么?
- 18、关键字 const 有什么含意?
- 19、关键字 volatile 有什么含意?并给出三个不同的例子
- 20、全局变量和局部变量的区别
- 21、嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量 a,写两段代码,第一个设置 a 的 bit 3,第二个清除 ai的 bit 3。在以上两个操作中,要保持其它位不变。
- 22、嵌入式系统中经常要用到无限循环,你怎么样用 C编写死循环呢?
- 23、中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展一让标准 C支持中断。具代表事实是,产生了一个新的关键字 _interrupt下面的代码就使用了 interrupt 关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。
- 24、字符串操作
- 25、什么是堆栈,为什么需要
- 26、死锁的四个条件,及处理办法
- 27、算法题,合并数组
1、动态开辟一个M*N的二维数组
参考:讲解
#include<stdio.h>
#include<stdlib.h>
int main() {
int hang, lie;
printf("请输入行和列");
scanf("%d%d", &hang, &lie);
int i,n=0,j;
//二维数组的数组名储存的是一个二级指针,可以通过malloc来确定二维指针指向的一级指针个数。
int** a = (int**)malloc(hang * sizeof(int*));
for (i = 0; i < hang; i++) {
a[i] = (int*)malloc(lie * sizeof(int));//a[i]中存储的其实就是一级指针,每个一级指针指向其对应的行。
for (j = 0; j < lie; j++) {
a[i][j] = n; //a[i][j]才是二维数组最真实的储存元素的地方
n++;
}
}
//把1、2、3、4.....赋值进二维数组
for (i = 0; i < hang; i++) {
for (j = 0; j < lie; j++) {
printf("%d ", a[i][j]);
}
}
//注意!!free函数的操作对象只能是一级指针,不能直接释放二维数组的数组名。
for (i = 0; i < hang; i++) {
free(a[i]);
}
a = NULL;
}
2、动态开辟空间失败了,有什么异常捕获机制
malloc开辟空间失败返回为null,判断一下。
3、宏定义:计算数组大小
/* 计算数组 arr 大小 */
#include <stdio.h>
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
int main(void)
{
int my_array[] = {1, 2, 3, 4, 5};
printf("The array has %lu elements.\n", ARRAY_SIZE(my_array));
return 0;
}
4、C语言中可以定义一个函数来计算数组大小吗
参考:指针退化
不可以!!!!
5、宏定义:计算两个数中比较小的那一个
#define MIN(A, B) ((A) > (B) ? (B) : (A))
6、写出来,一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
一个有10个指针的数组:*a[10];
该指针指向一个函数:(*a[10])();
该函数有一个整形参数: (*a[10])(int);
并返回一个整型数: int (*a[10])(int)
1.定义一个 整型数(An integer)
int a;
2.定义一个指向整形数的指针(A pointer to an integer)
int *a;
3.定义一个指向指针的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer)
int **a; //很明显是一个二重指针
4.定义一个有10个整型数的数组(An array of 10 integers)
int a[10];
5.定义一个有10个指针的数组,该指针是指向一个整形数的(An array of 10 pointers to integers)
int *a[10];
6.定义一个指向有10个整型数数组的指针(A pointer to an array of 10 integers)
int (*a)[10];
7.一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer )
int (*a)(int);
8.一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数(An array of ten pointers to functions that take an integer argunment and return an integer)
int (*a[10])(int);
7、广度展开树
8、C语言有几种排序,具体实现代码
参考:排序
9、排序的时间复杂度
参考:复杂度
参考:理解O(n^2)
10、重载函数,指针向量,引用
void CalculateArea (const double* const ptrRadius, double st ptrArea);
void CalculateArea (const double& radius, double& area);
问题是:你会认为这是重载函数吗,你使用的话你会倾向于哪一个
11、指针常量,常量指针,const
指针常量
int* const ptr; //表示存储的地址是不可变的,即不能改变指针的指向;
常量指针
const int* ptr; //表示指向的值是不可变的,即不能通过该指针修改其指向的值。
int const * ptr;
12、调用的哪个函数,foo能否执行
class Obj;
Obj getObj(int);
void foo(Obj& obj) / /(1)
void foo(Obj&& obj) / /(2)
int main
{
Obj&& r = getObj(32);
foo(r);
}
调用的1
能
13、#define 定义一个常量 表示全年一共多少秒
#define SECONDS_IN_A_YEAR 365*24*60*60
14、设计一个函数,实现字符串逆序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int inverse(char *p)
{
if (p == NULL)
{
return -1;
}
char *str = p;
int begin = 0;
int end = strlen(str) - 1;
char tmp;
while (begin < end)
{
//交换元素
tmp = str[begin];
str[begin] = str[end];
str[end] = tmp;
begin++; //往右移动位置
end--; //往左移动位置
}
return 0;
}
int main(void)
{
//char *str = "abcdefg"; //文件常量区,内容不允许修改
char str[] = "abcdef";
int ret = inverse(str);
if (ret != 0)
{
return ret;
}
printf("str ========== %s\n", str);
return 0;
}
15、有符号和无符号运算问题
unsigned int a = 6;
int b = -20,
if(a+b>6)puts(">6");else puts("<=6");
输出什么?为什么?
输出>6
当有符号和无符号运算时,统一转换为无符号,而在有符号的情况下是将最高位置1来表示负数,所以负数转为无符号时将会是一个很大的数。
(原因是当表达式中存在有符号
类型和无符号类型时所有的操作数都自动转换为无符号类型)
16、结构体对齐问题,一个char,一个int,一个short,如何占空间最小
参考:结构体对齐
char,short, int
共用体占用内存
17、关键字 static 的作用是什么?
关键字static的意思是静态的,主要有三种作用:(修饰函数,全局变量,局部变量)
18、关键字 const 有什么含意?
const含义:只要一个变量前用const来修饰,就意味着该变量里的数据只能被访问,而不能被修改,也就是意味着“只读”(readonly)。
const规则: const在谁后面谁就不可以修改,const在最前面则将其后移一位;const修饰一个变量时,一定要给这个变量初始化,若不初始化,在后面也不能初始化。
const作用:
1:可以用来修饰变量,修饰函数参数,修饰函数返回值,且被const修饰的东西,都受到强制保护,可以预防其它代码无意识的进行修改,从而提高了程序的健壮性(是指系统对于规范要求以外的输入能够判断这个输入不符合规范要求,并能有合理的处理方式。ps:即所谓高手写的程序不容易死);
2:使编译器保护那些不希望被修改的参数,防止无意代码的修改,减少bug;
3:增强代码的可读性,给读代码的人传递有用的信息,声明一个参数,是为了告诉用户这个参数的应用目的。
const意味着“只读”就可以了。尽管这个答案不是完全的
答案,但我接受它作为一个正确的答案。(如果你想知道更详细的答案,仔细读一下Saks
的文章吧。)如果应试者能正确回答这个问题,我将问他一个附加的问题:下面的声明都
是什么意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也
就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也
就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一
个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不
可修改的)。如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提
一句,也许你可能会问,即使不用关键字const,也还是能很容易写出功能正确的程序,那
么我为什么还要如此看重关键字const呢?我也如下的几下理由:
1). 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数
为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃
圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃
圾让别人来清理的。)
2). 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
3). 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其
被无意的代码修改。简而言之,这样可以减少bug的出现。
19、关键字 volatile 有什么含意?并给出三个不同的例子
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去
假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读
取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
1). 并行设备的硬件寄存器(如:状态寄存器)
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3). 多线程应用中被几个任务共享的变量
回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最
基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求vo
latile变量。不懂得volatile内容将会带来灾难。
假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看
一下这家伙是不是直正懂得volatile完全的重要性。
1). 一个参数既可以是const还可以是volatile吗?解释为什么。
2). 一个指针可以是volatile 吗?解释为什么。
3). 下面的函数有什么错误:
int square(volatile int *ptr)
{
return ptr * ptr;
}
下面是答案:
1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。
它是const因为程序不应该试图去修改它。
2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer
的指针时。
3). 这段代码的有个恶作剧。这段代码的目的是用来返指针ptr指向值的平方,但是,由
于ptr指向一个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = ptr;
return a * b;
}
由于ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不
是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
20、全局变量和局部变量的区别
全局变量和局部变量的区别有:
1.有效范围不一样,2.内存空间不同,3.使用区间不同。
局部变量只在本函数范围有效,在此函数以外是不能使用这些变量;全局变量的有效范围是从定义变量的位置开始到本源文件结束。
局部变量是程序运行到该函数时给该变量分配内存空间,函数结束则释放该内存空间。
全局变量是程序运行时事先分配内存空间,当程序结束时释放内存。全局变量:作用于整个程序文件;局部变量:作用于所属语句块或函数中。
21、嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量 a,写两段代码,第一个设置 a 的 bit 3,第二个清除 ai的 bit 3。在以上两个操作中,要保持其它位不变。
#define BIT3 (0x1 < <3)
static int a;
void set_bit3(void)
{
a |= BIT3; //位或
}
void clear_bit3(void)
{
a &= ~BIT3;//位与
}
22、嵌入式系统中经常要用到无限循环,你怎么样用 C编写死循环呢?
while(1)
{
}
一些程序员更喜欢如下方案:
for(;;)
{
}
23、中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展一让标准 C支持中断。具代表事实是,产生了一个新的关键字 _interrupt下面的代码就使用了 interrupt 关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。
_interrupt double compute area (double radius)
{
double area = PI *radius *radius;
printf(" nArea = %f", area);
return area;
}
一般来说,中断服务函数,无返回值。无参数。
这个函数有太多的错误了,以至让人不知从何说起了:
1). ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。
2). ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。
3). 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额
处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短
而有效率的,在ISR中做浮点运算是不明智的。
4). 与第三点一脉相承,printf()经常有重入和性能上的问题。如果你丢掉了第三和第四
点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明
了。
24、字符串操作
字符串拷贝
#include <stdio.h>
char* MyStrcpy(char* str1, char* str2)
{
char* pMark = str1;
while (*str2 != '\0')
{
*str1 = *str2;
str1++;
str2++;
}
*str1 = '\0';
return pMark;
}
int main()
{
char str[20];
char str1[] = "abcde";
printf("%s\n", MyStrcpy(str, str1));
return 0;
}
字符串长度strlen
#include <stdio.h>
int MyStrlen(char* str)
{
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
str = '\0';
return count;
}
int main()
{
char str[] = "abcde";
printf("%d\n", MyStrlen(str));
return 0;
}
字符串拼接
#include <stdio.h>
char* MyStrCat(char* str1, char* str2)
{
char* pMark = str1;
while (*str1 != '\0')
{
str1++;
}
while (*str2 != '\0')
{
*str1 = *str2;
str1++;
str2++;
}
*str1 = '\0';
return pMark;
}
int main()
{
char str[10] = "abcd";
char* str1 = "1234";
printf("%s\n", MyStrCat(str,str1));
return 0;
}
字符串比较
#include <stdio.h>
int MyStrcmp(char* str1,char* str2)
{
/*while (*str1 != '\0' && *str2 != '\0') //第一种方法
{
if (*str1 > *str2)
{
return 1;
}
else if (*str1 < *str2)
{
return -1;
}
else
{
str1++;
str2++;
}
}
if (*str1 > *str2)
{
return 1;
}
else if (*str1 < *str2)
{
return -1;
}
else
{
return 0;
}*/
while (*str1 != '\0' || *str2 != '\0') //第二种方法
{
if (*str1 > *str2)
{
return 1;
}
else if (*str1 < *str2)
{
return -1;
}
else
{
str1++;
str2++;
}
}
return 0;
}
int main()
{
printf("%d\n", MyStrcmp("abc", "abc"));
printf("%d\n", MyStrcmp("ab", "abc"));
printf("%d\n", MyStrcmp("ac", "abc"));
return 0;
}
查找一个字符在另外一个字符串中第一次出现的下标
#include <stdio.h>
int T1(char* str, char ch)
{
int count = 0;
while (*str != '\0')
{
if (*str == ch)
{
return count;
}
str++;
count++;
}
return -1;
}
int main()
{
printf("%d\n", T1("abcd", 'b'));
return 0;
}
统计字符串中单词的个数
#include <stdio.h>
int T4(char* str)
{
int count = 0;
while (*str != '\0')
{
if (*str == ' ')
{
count++;
}
str++;
}
return count + 1;
}
int main()
{
printf("%d\n", T4("i love you"));
return 0;
}
将一个字符串插入到另一个字符串中
#include <stdio.h>
void T5(char* str1, char* str2, int n)
{
char* phead = str1 + n - 1;
char* pend = str1 + strlen(str2);
while(phead <= pend)
{
*(pend + strlen(str2)) = *pend;
pend--;
}
while (*str2 != '\0')
{
*phead = *str2;
phead++;
str2++;
}
}
int main()
{
char str[20] = "abcd";
T5(str, "12345", 3);
printf("%s\n", str);
return 0;
}
翻转字符串
#include <stdio.h>
void T6(char* str)
{
char* pbegin = str;
char* pend = str + strlen(str) - 1;
while (pbegin < pend)
{
char ptemp = *pbegin;
*pbegin = *pend;
*pend = ptemp;
pbegin++;
pend--;
}
}
int main()
{
char str[20] = "abcd";
T6(str);
printf("%s\n", str);
return 0;
}
GetString()
#include <stdio.h>
#include <stdlib.h>
char* Getstring()
{
int size = 5;
char* str = (char*)malloc(sizeof(char) * size);
int count = 0;
char ch;
while ((ch = getchar()) != '\n')
{
str[count] = ch;
count++;
if (count == size)
{
size += 5;
str = realloc(str, size);
}
}
str[count] = '\0';
return str;
}
int main()
{
char* str = Getstring();
printf("%s\n", str);
free(str);
return 0;
}
25、什么是堆栈,为什么需要
栈区(stack)
栈是一种先进后出的内存结构,由编译器自动分配释放,存放函数的参数值、
返回值、局部变量等。在程序运行过程中实时加载和释放,因此,局部变量的
生存周期为申请到释放该段栈空间。
堆区(heap)
堆是一个大容器,它的容量要远远大于栈,但没有栈那样先进后出的顺序。用
于动态内存分配。堆在内存中位于 BSS 区和栈区之间。一般由程序员分配和释
放,若程序员不释放,程序结束时由操作系统回收。
26、死锁的四个条件,及处理办法
27、算法题,合并数组
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素