Bootstrap

【C语言】经典C语言笔试面试题目

01. 请填写bool , float, 指针变量 与“零值”比较的if语句。

提示:这里“零值”可以是0, 0.0 , FALSE 或者“空指针”。
例如 int n 与“零值”比较的 if 语句为:
if ( n == 0 )
if ( n != 0 )

以此类推。

请写出 bool flag 与“零值”比较的 if 语句:
if(flag)
{

}

if(!flag)
{

}

请写出 float x 与“零值”比较的if 语句:
const float EPSINON = 0.00001;
if ((x >= - EPSINON) && (x <= EPSINON)
{

}

不可将浮点变量用“==” 或“!=” 与数字比较,应该设法转化成“>=” 或“<=” 此类形式。

请写出char *p 与“零值”比较的if 语句
if (p == NULL)
{

}
if (p != NULL)
{

}

02. 以下为Linux下的32 位C 程序,请计算sizeof 的值。

char  str[] = "Hello";
char *p = str ;
int   n = 10;
sizeof(str) = ?		// 6
sizeof(p) = ?		// 4
sizeof(n) = ?		// 4
void Func ( char str[100])
void * p = malloc( 100 );
sizeof(str) = ?		// 4
sizeof(p) = ?		// 4

03. 用变量a 给出下面的定义

  1. 一个有10个指针的数组,该指针是指向一个整型数的;
  2. 一个指向有10个整型数数组的指针;
  3. 一个指向函数的指针,该函数有一个整型参数并返回一个整型数;
  4. 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数;
1)int *a[10];
2)int (*a)[10]
3)int (*a)(int);
4)int (*a[10])(int)

04. 设有以下说明和定义:

typedef union
{
	long i;
	int k[5];
	char c;
} DATE;

struct data
{
	int cat;
	DATE cow;
	double dog;
} too;
DATE max;

则语句printf("%d",sizeof(struct date)+sizeof(max));的执行结果是:20

注解:
DATE是一个union, 变量公用空间. 里面最大的变量类型是int[5], 占用20个字节. 所以它的大小是20。data 是一个struct, 每个变量分开占用空间. 依次为int4 +DATE20 + double8 = 32.所以结果是20 + 32 = 52.
当然在某些16位编辑器下, int 可能是2字节,那么结果是int2 + DATE10 + double8 = 20

05. 请问以下代码有什么问题:

int main()
{
char a;
char *str=&a;
strcpy(str,"hello");
printf(str);
return 0;
}

注解:
没有为str分配内存空间,将会发生异常问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,因为越界进行内在读写而导致程序崩溃。

06. 请问以下代码有什么问题:

char* s="AAA";
printf("%s",s);
s[0]='B';
printf("%s",s);

注解:
"AAA" 是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。
cosnt char* s="AAA";然后又因为是常量,所以对s[0]的赋值操作是不合法的。

07. int (*s[10])(int) 表示的是什么?

int (*s[10])(int) 函数指针数组,每个指针指向一个int func(int param) 的函数。

08. c和c++ 中的struct有什么不同?

注解:
cc++中struct的主要区别是c中的struct不可以含有成员函数,而c++中的struct可以。c++structclass的主要区别在于默认的存取权限不同,struct默认为public,而class默认为private

09. 以下代码会出现什么问题?

void getmemory(char *p)
{
	p=(char *) malloc(100);
	strcpy(p,“hello world”);
}
int main( )
{
	char *str=NULL;
	getmemory(str);
	printf(%s/n”,str);
	free(str);
	return 0;
}

程序崩溃,getmemory中的malloc不能返回动态内存,free()str操作很危险。

改进方案:

#pragma warning(disable:4996)
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

void getmemory(char** p)
{
	*p = (char*)malloc(100);
	strcpy(*p, "hello world");
}
int main()
{
	char* str = NULL;
	getmemory(&str);
	printf("%s\n", str);
	free(str);
	return 0;
}

10. 以下代码产生什么结果?为什么?

char szstr[10];
strcpy(szstr,"0123456789");

注解:
长度不一样,出现段错误。szstr至少应该为11*(char)的长度

11. 给定结构体计算sizeof(A) = ?

struct A
{
	char t:4;
	char k:4;
	unsigned short i:8;
	unsigned long m;
};

sizeof(A) = 8
32linux系统为例。
t占了 4个bit,剩下 4 bit 可以被占用。char一共有8bit,一个字节。
k占了 4个bit,前面有 4 bit 正好可以占用。t和k一共占 8 bit,一个字节。
i占了 1个字节,空了一个字节下来。这里有 2 个字节。
long 需要4个字节,前面空的两个字节不够,由于 对齐原则,不能直接占后面的空间。
在这里插入图片描述

12. 给定结构体计算sizeof(name1) = ?

struct name1{
	char str;
	short x;
	int num;
};

sizeof(name1) = 8

13. 给定结构体计算sizeof(name2) = ?

struct name2{
char str;
int num;
short x;
};

sizeof(name1) = 12

14. 程序哪里有错误

wap( int* p1,int* p2 )
{
	int * p;
	*p = *p1;
	*p1 = *p2;
	*p2 = *p;
}

p 为野指针(指向一个已删除的对象或未申请访问受限内存区域的指针)

15. void-ptr-和voidptr-的结果是否相同其中ptr为同一个指针

(void *)ptr(*(void**))ptr值是相同的

16. 关于内存的思考题(1)你能看出有什么问题?

void GetMemory(char *p)
{
   p = (char *)malloc(100);
}
void Test(void)
{
    char *str = NULL;
    GetMemory(str);
    strcpy(str, "hello world");
    printf(str);
}

请问运行Test 函数会有什么样的结果?

答:程序崩溃。因为GetMemory并不能传递动态内存,Test函数中的str一直都是NULL
strcpy(str, "hello world");将使程序崩溃。

改进方案:

void GetMemory(char **p)
{
   *p = (char *)malloc(100);
}
void Test(void)
{
    char *str = NULL;
    GetMemory(&str);
    strcpy(str, "hello world");
    printf(str);
}

关于内存的思考题(2)你能看出有什么问题?

char *GetMemory(void)
{
    char p[] = "hello world";
    return p;
}
void Test(void)
{
    char *str = NULL;
    str = GetMemory();
    printf(str);
}

请问运行Test 函数会有什么样的结果?

答:可能是乱码。因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是NULL,但其原现的内容已经被清除,新内容不可知。

关于内存的思考题(3)你能看出有什么问题?

void GetMemory(char **p, int num)
{
    *p = (char *)malloc(num);
}
void Test(void)
{
    char *str = NULL;
    GetMemory(&str, 100);
    strcpy(str, "hello");
    printf(str);
}

请问运行Test函数会有什么样的结果?

答:(1)能够输出hello;(2)内存泄漏

关于内存的思考题(4)你能看出有什么问题?

void Test(void)
{
    char* str = (char*)malloc(100);
    strcpy(str, "hello");
    free(str);
    if (str != NULL)
    {
        strcpy(str, "world");
        printf(str);
    }
}

请问运行Test函数会有什么样的结果?

答:篡改动态内存区的内容,后果难以预料,非常危险。
因为free(str);之后,str成为野指针,if(str != NULL)语句不起作用。
vs2019中编译通过,并成功打印word,这得益于系统并不会立刻被系统回收,free后会被某些程序托管,就好比。每次释放很小的空间,不停的释放,系统不停地回收,这并不合理,应该是达到一定的条件,才会被系统回收。但这块空间暂时已经不能被用户正常使用。

17. 关键字volatile有什么含意? 并给出三个不同的例子。

答:一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

下面是volatile变量的几个例子:
1). 多线程应用中被几个任务共享的变量
2). 并行设备的硬件寄存器(如:状态寄存器)
3). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

18. const有什么用途?

【标准答案】
(1)可以定义const常量
(2)const可以修饰函数的参数、返回值,甚至函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。

19. static有什么用途?

限制变量的作用域(static全局变量);
设置变量的存储域(static局部变量)。

20. 堆栈溢出一般是什么原因?

没有回收垃圾资源。

21. 如何引用一个已经定义过的全局变量?

可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。

22. 用宏定义写出两数交换

#define Min(X, Y) ((X)>(Y)?(Y):(X))// 结尾没有 ;

23. 带参宏和无参宏的区别

                    带参宏              带参函数
处理时间             编译时               运行时
参数类型                无                需定义
程序长度              变长                  不变
占用存储空间            否                    是
运行时间      不占运行时间          调用和返回时占

24. A.c 和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里(栈还是堆或者其他的)?

static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。他们都放在静态数据区,但是编译器对他们的命名是不同的。如果要使变量在其他模块也有意义的话,需要使用extern关键字。

25. 用两个栈实现一个队列的功能?要求给出算法和思路

设2个栈为A,B, 一开始均为空.
入队:
将新元素push入栈A;

出队:
(1)判断栈B是否为空;
(2)如果不为空,则将栈A中所有元素依次pop出并push到栈B
(3)将栈B的栈顶元素pop出;

26. 用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL

27. 请写出以下代码的输出

#include <stdio.h>
int main()
{
int a,b,c,d;
a=10;
b=a++;
c=++a;
d=10*a++;
printf("b, c, d:%d, %d, %d", b, c, d);
return 0;
}
b, c, d: 10, 12, 120

28. 请计算 p1+5=?p2+5=?

unsigned char *p1;
unsigned long *p2;
p1=(unsigned char *)0x801000;
p2=(unsigned long *)0x810000;
p1+5 = 0x801005;
p2+5 = 0x810020;

29. 请计算以下代码的输出

main()
{
	int a[5]={1,2,3,4,5};
	int * ptr=(int*)(&a+1);
	printf(%d,%d”,*(a+1),*(ptr-1));
}
2, 5

30. 请计算以下代码的输出

int modifyvalue()
{ 
	return(x+=10);
}
int c hangevalue(int x )
{
	return(x+=1);
}
void main()
{
	int x =10;
	x++;
	changevalue(x);
	x++;
	modifyvalue();
	printf("First output:%dn",x);
	x++;
	changevalue(x);
	printf("Second output:%dn",x);
	modifyvalue();
	printf("Thirdoutput:%dn",x);
}
First output:12
Second output:13
Thirdoutput:13

31. 请写出以下代码的输出

void foo(void)
{
	unsigned int a = 6;
	int b = -20;
	(a+b> 6)? puts("> 6") : puts("<= 6");
}

输出是">6"
当表达式中存在有符号类型和无符号类型时所有的数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。

32. 编写strnpy()函数

已知strcpy函数的原型是char *strcpy(char *strDest,const char *strSrc);其中strDest是目的字符串,
strSrc 是源字符串。
1)不调用C++/C 的字符串库函数,请编写函数strcpy 。
2)strcpy 能把 strSrc 的内容复制到strDest,为什么还要char * 类型的返回值?

void my_strcpy(char* dest, char* sou)
{
	while (*sou != '\0')
	{
		*dest = *sou;
		dest++;
		sou++;
	}
}

优化:


#include<assert.h>
void my_strcpy(char* dest, char* sou)
{
	assert(dest && sou);
 
	while (*dest++=*sou++)
	{
		;
	}
}

写法二:


#include<assert.h>
char *my_strcpy(char* dest,const char* sou)
{
	assert(dest && sou);
	char* ret = dest;
	while (*dest++=*sou++)
	{
		;
	}
	return ret;
}

33. 写出二分查找的C代码

int binary_search(int* arr, int k ey, int n)
{
    int low =  0;
    int h igh = n - 1 ;
    int m id;
    while (low <= high)
    {
        mid = (high + low) / 2;
        if (arr[mid] > k)
            high = mid -1 ;
        else if (arr[mid] < k)
            low = mid + 1;
        else
            return mid;
    }
    return -1;
}

33. 编写一个C函数,该函数将给定的字符串转换成整数

int Invert(char* str) 
{ 
    int num =0; 
    while(*str!='\0') 
    { 
        int d igital=*str-48; 
        num=num*10+digital; 
        str=str+1; 
    } 
    return num; 
} 

34. 编写一个C函数,该函数将给定的整数转换成字符串

void IntToCharChange(int num,  char* pval) 
{ 
    char strval[100]; 
    int i , j; 
    int val0 = 0; 
    int val1 = 0; 
    val0 = num; 
    for(i=0; i<100; i++) 
    { 
        val1 = val0 % 10; //取余
        val0 = val0 / 10; // 取整
        strval[i] = val1 + 48;  // 数字—字符
        if(val0 < 10) 
        { 
            i++; 
            strval[i] = val0 + 48; 
            break; 
        } 
    } 
    for(j=0; j<=i; j++)  // 倒置
    pval[j] = strval[i-j]; 
    pval[j] = '\0'; 
}

35. 实现strcmp()函数

int mystrcmp(const c har* str1, const char* str2)
{
    assert((str1 != NULL) && (str2 != NULL));
    int ret = 0;
    while (!(ret = *(unsigned char*)str1 - * (unsigned char*)str2) && *str2)
    {
        str1++;
        str2++;
    }
    if (ret > 0)
        ret = 1;
    else if (ret < 0)
        ret = -1;
    return ret;
}

36. 编写一个C函数,该函数将给定的字符串逆序

void AntitoneValue(cha r* father, char* child) 
{ 
	int i ; 
	char source[100]; 
	int j = 0; 
	while(father[j]) //放入source ,[j] 为长度
	{ 
		source[j] = father[j]; 
		j++; 
		if(j > 99) 
		return; 
	} 
	source[j] = '\0'; 
	for(i=0; i<j; i++) 
	child[i] = source[j-i-1];  // 反序
	child[i] = '\0'; 
} 

37. 编写一个C函数,该函数在给定的内存区域搜索给定的字符,并返回该字符所在位置索引值

int search(char* cpSource, intn , char ch)  // 起始地址,搜索长度,目标字符
{
    int i;
    for(i=0; i<n && *(cpSource+i) != ch; ++i);
    return i;
}

38 . 编写一个C函数,该函数在一个字符串中找到可能的最长的子字符串,该字符串是由同一字符组成

int C hildString(char*p)
{
    char *q =p;
    int s tringlen=0, i=0,j=1,len=0,maxlen=1;
    while(*q!=’\0)          //不能用strlen, 求得长度stringlen
    {
        Stringlen++;
        q++;
    }
    while( i<  String len )
    {
        if(*(p+i)==*(p+j)& & j< St ri ngle n )
        {
            len++;                    // 统计子串长度
            i++;
            j++;
        }
        else
        {
            if(len>maxlen)           // 统计最大子串长度
            {
                maxlen=len+1;
                len=0;
            }
            else
            len=0;
            i++;
            j++;
        }
    }
    return   maxlen;
}

39. 怎么判断链表中是否有环

int testLinkRing(Link *head)
{
    Link *t1=head,*t2=head;
    while( t1->next && t2->next)
    {
        t1 = t1->next;
        if (NULL == (t2 = t2->next->next))
            return 0; // 无环
        if (t1 == t2)
            return 1;
    }
    return 0;
}

注解:
用两个指针来遍历这个单向链表,第一个指针p1,每次走一步;第二个指针p2,每次走两步;当p2 指针追上p1的时候,就表明链表当中有环路了

40. 编写一个C函数,该函数在将一个链表反向

void reverse(test* head)
{
    test* pe = head;
    test* ps = head->next;
    while(ps)
    { 
        pe->next = ps->next;
        ps->next = head;
        head = ps;
        ps =  pe->next;
    }
}

注解:
从第一个元素开始,ps指向他,将他ps指向头节点ps->next = head,将ps设为头节点head = ps; 操作下一个元素ps= pe->next;等,于是依次将每个元素翻到原头节点前面。

41. 编写一个C函数,该函数将二维数组行列元素互换,存到一个新数组

#include <stdio.h>
main()
{   
    int a [2][3]={{1,2,3},{4,5,6}};
    int b[3][2],i,j;
    printf("array a :\n");
    for(i=0;i<=1;i++)
    {   
        for(j=0;j<=2;j++)
        {   
            printf("%5d",a[i][j]);
            b[j][i]=a[i][j];
        }
        printf("\n");
    }    
    printf("array b :\n");
    for(i=0;i<=2;i++)
    {   
        for(j=0;j<=1;j++)
        printf("%5d",b[i][j]);
        printf("\n");
    }
}

42. 编写一个C函数,该函数实现输入一行字符,统计其中有多少个单词

#include <stdio.h>
main()
{   
char str i ng[81];
int i,num=0,word=0;
char c;
gets(string);
for(i=0;(c=string[i])!='\0';i++)
if(c==' ')  
word=0;
else if(word==0)
{   
word=1;  num++;   }
printf("There are %d word s in the line\n",num);
}

43. 编写一个C函数,该函数实现计算字符串中字串出现的次数

int main()
{
    char str1[20],str2[20],*p1,*p2;
    int sum=0;
    printf("please input two strings\n");
    scanf("%s%s",str1,str2);
    p1=str1;p2=str2;
    while(*p1!='\0')
    {
        if(*p1==*p2)
        {
            while(*p1==*p2&&*p2!='\0')
            {
                p1++;
                p2++;
            }
        }
        else
        p1++;
        if(*p2=='\0')
        sum++;
        p2=str2;
    }
    printf("%d",sum);
    getch();
}

44. 写一个内存拷贝函数memcpy,不用任何库函数

void* memcpy(void* pvTo, const void* pvFrom, size_t size)
{
assert((pvTo != NULL) && (pvFrom ! = NULL));
byte* pbTo= pvTo;
byte* pbFrom = pbFrom;
while (size-- >  0)
{
*pbTo++ = *pbFrom++;
}
return pvTo;
}

45. 有两个磁盘文件A和B, 各存放一行字母,要求把这两个文件中的信息合并(按字母顺序排列),输出到一个新文件C 中。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int cmp(const void* a, const void* b)
{
	return *(char*)a - *(char*)b;
}

int main()
{
	// 读文件
	FILE* f_read_A = fopen("A.txt", "r");
	FILE* f_read_B = fopen("B.txt", "r");

	if (f_read_A == NULL || f_read_B == NULL)
	{
		return 0;
	}

	char buf_a[100] = { 0 };
	char buf_b[100] = { 0 };
	int a = 0, b = 0;
	char ch;
	while ((ch = getc(f_read_A)) != EOF)
	{
		buf_a[a++] = ch;
	}

	while ((ch = getc(f_read_B)) != EOF)
	{
		buf_b[b++] = ch;
	}

	char* buf_c = strcat(buf_a, buf_b);
	qsort(buf_c, strlen(buf_c), sizeof(char), cmp);
	printf("%s\n", buf_c);

	//写文件
	FILE* f_write_C = fopen("C.txt", "w");
	if (f_write_C == NULL)
	{
		return 0;
	}

	for (int i = 0; i < strlen(buf_c); i++)
	{
		fputc(buf_c[i], f_write_C);
	}

	fclose(f_read_A);
	fclose(f_read_B);
	fclose(f_write_C);

	return 0;
}
;