C语言面试考点之二

简介: C语言面试考点之二


  1. 全局变量和局部变量在内存中是否有区别?如果有,是什么区别?
全局变量储存在静态数据库,局部变量在堆栈
  1. 堆栈溢出一般是由什么原因导致的?
没有回收垃圾资源
  1. 局部变量能否和全局变量重名?
能,局部会屏蔽全局。
      在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。
      对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,
      比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内
  1. 如何引用一个已经定义过的全局变量?
extern 关键字
  1. 全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
可以,在不同的C文件中以static形式来声明同名全局变量。
      可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错

内存对齐问题

6. 设有以下说明和定义:(注意变量占用字节在不同平台下是不同的)

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));的执行结果是:52

DATE是一个union, 变量公用空间. 里面最大的变量类型是int[5], 占用20个字节. 所以它的大小是20

data是一个struct, 每个变量分开占用空间. 依次为int4 + DATE20 + double8 = 32.

所以结果是 20 + 32 = 52.

当然…在某些16位编辑器下, int可能是2字节,那么结果是 int2 + DATE10 + double8 = 20

  1. 写出下列代码的输出内容(考察指针函数的用法)
#include<stdio.h>
int inc(int a)
{
 return(++a);
}
int multi(int*a,int*b,int*c)
{
 return(*c=*a**b);
}
typedef int(*FUNC1)(int);
typedef int(*FUNC2)(int*,int*,int*);
void show(FUNC2 fun,int arg1, int*arg2)
{
 FUNC1 p=&inc; // 这里用&inc与inc都可以,都是取地址
 int temp =p(arg1);
 fun(&temp,&arg1, arg2);
 printf("%d\n",*arg2);
}
main()
{
 int a;
 show(multi,10,&a);
 return 0;
}

110

  1. 请找出下面代码中的所有错误
    说明:以下代码是把一个字符串倒序,如“abcd”倒序后变为“dcba”
#include"string.h"
main()
{
   char*src="hello,world";
   char* dest=NULL;
   int len=strlen(src);
   dest=(char*)malloc(len);
   char* d=dest;
   char* s=src[len];
   while(len--!=0)
   d++=s--;
   printf("%s",dest);
   return 0;
}

答:

方法1:

int main(){
  char* src = "hello,world";
  int len = strlen(src);
  char* dest = (char*)malloc(len+1);//要为/0分配一个空间
  char* d = dest;
  char* s = &src[len-1];//指向最后一个字符
  while( len-- != 0 )
  *d++=*s--;
  *d = 0;//尾部要加/0
  printf("%s/n",dest);
  free(dest);// 使用完,应当释放空间,以免造成内存汇泄露
  return 0;
}

方法2:

#include <stdio.h>
#include <string.h>
main()
{
char str[]="hello,world";
int len=strlen(str);
char t;
for(int i=0; i<len/2; i++)
{
t=str[i];
str[i]=str[len-i-1]; str[len-i-1]=t;
}
printf("%s",str);
return 0;
}
  1. 用两个栈实现一个队列的功能?要求给出算法和思路!
  2. 对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
    inline
  3. 代码输出什么?
unsigned char *p1;
    unsigned long *p2;
    p1=(unsigned char *)0x801000;
    p2=(unsigned long *)0x810000;
    请问p1+5=  ;
       p2+5=  ;

p1+5= 0x801005 ;

p2+5= 0x801014 ;(long型在32位编译器里为4byte,这里0x14=20)

  1. C/C++编译器中虚表是如何完成的?

14. 内存四区问题

char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char *str5 = "abc";
const char *str6 = "abc";
char *str7 = "abc";
char *str8 = "abc";
cout << ( str1 == str2 ) << endl;
cout << ( str3 == str4 ) << endl;
cout << ( str5 == str6 ) << endl;
cout << ( str7 == str8 ) << endl;

结果是:0 0 1 1

解答:str1,str2,str3,str4是数组变量,它们有各自的内存空间;

而str5,str6,str7,str8是指针,它们指向相同的常量区域。

  1. 以下代码中的两个sizeof用法有问题吗?
void UpperCase( char str[] ) // 将 str 中的小写字母转换成大写字母
{
    for( size_t i=0; i<sizeof(str)/sizeof(str[0]); ++i )
        if( 'a'<=str[i] && str[i]<='z' )
            str[i] -= ('a'-'A' );
}

这个sizeof是有问题的,数组传参不能只传首地址,还有传数组大小。

char str[] = {1,2,3,4};
  printf("%d\n", sizeof(str)/sizeof(str[0]));   //4
     printf("%d\n", sizeof(str));             //4
     
  int str[] = {1,2,3,4};
  printf("%d\n", sizeof(str)/sizeof(str[0]));   //4
     printf("%d\n", sizeof(str));             //16
  1. 一个32位的机器,该机器的指针是多少位
    指针是多少位只要看地址总线的位数就行了。80386以后的机子都是32的数据总线。所以指针的位数就是4个字节了。
  2. 代码输出什么?
main()
{
  int a[5]={1,2,3,4,5};
   int *ptr=(int *)(&a+1);
   printf("%d,%d",*(a+1),*(ptr-1));
}

输出:2,5

(a+1)就是a[1],(ptr-1)就是a[4],执行结果是2,5

&a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int)

int ptr=(int )(&a+1);
则ptr实际是&(a[5]),也就是a+5
原因如下:
&a是数组指针,其类型为 int (
)[5];
而指针加1要根据指针类型加上一定的值,
不同类型的指针+1之后增加的大小不同
a是长度为5的int数组指针,所以要加 5
sizeof(int)

所以ptr实际是a[5]

但是prt与(&a+1)类型是不一样的(这点很重要)

所以prt-1只会减去sizeof(int*)

a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5].

  1. 请问以下代码有什么问题:
int  main()
{
  char a;
  char *str=&a;
  strcpy(str,"hello");
  printf(str);
  return 0;
}

没有为str分配内存空间,将会发生异常

问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。

  1. 用宏定义写出swap(x,y)
#define swap(x, y) (x = x + y;y = x - y; x = x - y;)
  1. 数组a[N],存放了1至N-1个数,其中某个数重复一次。写一个函数,找出被重复的数字.时间复杂度必须为o(N)函数原型:int do_dup(int a[],int N)
  2. 什么是预编译 何时需要预编译:

char * const p;
char const * p
const char *p

上述三个有什么区别?

char * const p; //常量指针,p的值不可以修改

char const * p;//指向常量的指针,指向的常量值不可以改

const char *p; //和char const *p

  1. 请问以下代码有什么问题:
int  main()
{
  char a;
  char *str=&a;
  strcpy(str,"hello");
  printf(str);
  return 0;
}

没有为str分配内存空间,将会发生异常

问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。

  1. int (*s[10])(int) 表示的是什么?
    int (*s[10])(int) 函数指针数组,每个指针指向一个int func(int param)的函数。
  2. 有以下表达式:
    int a=248; b=4;int const c=21;const int *d=&a;
    int *const e=&b;int const *f const =&a;
    请问下列表达式哪些会被编译器禁止?为什么?
    *c=32;d=&b;*d=43;e=34;e=&a;f=0x321f;
    *c 这是个什么东东,禁止
    *d 说了是const, 禁止
    e = &a 说了是const 禁止
    const *f const =&a; 禁止
  3. 交换两个变量的值,不使用第三个变量。即a=3,b=5,交换之后a=5,b=3;
    有两种解法, 一种用算术算法, 一种用^(异或)
    a = a + b;
    b = a - b;
    a = a - b;
    or
    a = a^b;// 只能对int,char…
    b = a^b;
    a = a^b;
    or
    a ^= b ^= a;
  4. c和c++中的struct有什么不同?
    c和c++中struct的主要区别是c中的struct不可以含有成员函数,而c++中的struct可以。c++中struct和class的主要区别在于默认的存取权限不同,struct默认为public,而class默认为private
  5. 下面代码有什么问题
#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;
   }

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

  1. 下面代码有什么问题
char szstr[10];
strcpy(szstr,"0123456789");
  产生什么结果?为什么?
  长度不一样,会造成非法的操作,破坏其他内存区的数据

(void )ptr 和 ((void**))ptr的结果是否相同?其中ptr为同一个指针

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

  1. 问函数既然不会被其它函数调用,为什么要返回1?
int main()
{
   int x=3;
   printf("%d",x);
   return 1;
}

mian中,c标准认为0表示成功,非0表示错误。具体的值是某中具体出错信息

  1. 要对绝对地址0x100000赋值,我们可以用
    (unsigned int*)0x100000 = 1234;
    那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?
    ((void ()( ))0x100000 ) ( );
    首先要将0x100000强制转换成函数指针,即:
    (void ()())0x100000
    然后再调用它:
    ((void ()())0x100000)();
    用typedef可以看得更直观些:
    typedef void(
    )() voidFuncPtr;
    *((voidFuncPtr)0x100000)();
  2. 已知一个数组table,用一个宏定义,求出数据的元素个数
#define NTBL
#define NTBL (sizeof(table)/sizeof(table[0]))
  1. 输出多少?并分析过程
unsigned short A = 10;
printf("~A = %u/n", ~A);
char c=128;
printf("c=%d/n",c);

第一题,~A =0xfffffff5,int值 为-11,但输出的是uint。所以输出4294967285

第二题,c=0x10,输出的是int,最高位为1,是负数,所以它的值就是0x00的补码就是128,所以输出-128。

这两道题都是在考察二进制向int或uint转换时的最高位处理。

  1. 分析下面的程序:
void GetMemory(char **p,int num)
{
    *p=(char *)malloc(num); 
}       
int main()
{
    char *str=NULL;
   
    GetMemory(&str,100);
   
    strcpy(str,"hello");
   
    free(str);
   
    if(str!=NULL)
    {
        strcpy(str,"world");
    }   
       
    printf("/n str is %s",str);
    getchar();
} 

问输出结果是什么?输出str is world。

free 只是释放的str指向的内存空间,它本身的值还是存在的.

所以free之后,有一个好的习惯就是将str=NULL.

此时str指向空间的内存已被回收,如果输出语句之前还存在分配空间的操作的话,这段存储空间是可能被重新分配给其他变量的,

尽管这段程序确实是存在大大的问题(上面各位已经说得很清楚了),但是通常会打印出world来。

这是因为,进程中的内存管理一般不是由操作系统完成的,而是由库函数自己完成的。

当你malloc一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),然后在这块空间中记录一些管理信息(一般是在你申请的内存前面一点),并将可用内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此你是可以继续访问这块地址的,只不过。。。。。。。。楼上都说过了,最好别这么干。

  1. char a[10],strlen(a)为什么等于15?运行的结果
#include "stdio.h"
#include "string.h"
void main()
{
char aa[10];
printf("%d",strlen(aa));
}

sizeof()和初不初始化,没有关系;

strlen()和初始化有关。

char (*str)[20];/str是一个数组指针,即指向数组的指针./

char *str[20];/str是一个指针数组,其元素为指针型数据./

  1. 代码输出什么?
#include <iostream.h>
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
typedef struct  AA
{
        int b1:5;
        int b2:2;
}AA;
void main()
{
        AA aa;
        char cc[100];
         strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");
       memcpy(&aa,cc,sizeof(AA));
        cout << aa.b1 <<endl;
        cout << aa.b2 <<endl;
}

答案是 -16和1

首先sizeof(AA)的大小为4,b1和b2分别占5bit和2bit.

经过strcpy和memcpy后,aa的4个字节所存放的值是:

0,1,2,3的ASC码,即00110000,00110001,00110010,00110011

所以,最后一步:显示的是这4个字节的前5位,和之后的2位

分别为:10000,和01

因为int是有正负之分  所以:答案是-16和1

  1. 求函数返回值,输入x=9999;
int func ( x )
{
    int countx = 0;
    while ( x )
    {
        countx ++;
        x = x&(x-1);
    }
    return countx;
}

结果呢?

知道了这是统计9999的二进制数值中有多少个1的函数,且有

9999=9×1024+512+256+15

9×1024中含有1的个数为2;

512中含有1的个数为1;

256中含有1的个数为1;

15中含有1的个数为4;

故共有1的个数为8,结果为8。

1000 - 1 = 0111,正好是原数取反。这就是原理。

用这种方法来求1的个数是很效率很高的。

不必去一个一个地移位。循环次数最少。

  1. 改错:
#include <stdio.h>
int main(void) {
    int **p;
    int arr[100];
    p = &arr;
    return 0;
}

解答:

搞错了,是指针类型不同,

int **p; //二级指针

&arr; //得到的是指向第一维为100的数组的指针

修改如下:

#include <stdio.h>
int main(void) {
int **p, *q;
int arr[100];
q = arr;
p = &q;
return 0;
}
  1. 下面这个程序执行后会有什么错误或者效果:
#define MAX 255
 int main()
{
   unsigned char A[MAX],i;//i被定义为unsigned char
   for (i=0;i<=MAX;i++)
   A[i]=i;
}

解答:死循环加数组越界访问(C/C++不进行数组越界检查)

MAX=255

数组A的下标范围为:0…MAX-1,这是其一…

其二.当i循环到255时,循环内执行:

A[255]=255;

这句本身没有问题…但是返回for (i=0;i<=MAX;i++)语句时,

由于unsigned char的取值范围在(0…255),i++以后i又为0了…无限循环下去.

  1. A.c 和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里(栈还是堆或者其他的)?
    static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。
    他们都放在数据区,但是编译器对他们的命名是不同的。
    如果要使变量在其他模块也有意义的话,需要使用extern关键字。
  2. 在对齐为4的情况下
struct BBB
{
   long num;
   char *name;
   short int data;
   char ha;
   short ba[5];
}*p;
p=0x1000000;
p+0x200=____;
(Ulong)p+0x200=____;
(char*)p+0x200=____;

解答:假设在32位CPU上,

sizeof(long) = 4 bytes

sizeof(char *) = 4 bytes

sizeof(short int) = sizeof(short) = 2 bytes

sizeof(char) = 1 bytes

由于是4字节对齐,

sizeof(struct BBB) = sizeof(p)
= 4 + 4 + 2 + 1 + 1/补齐/ + 2
5 + 2/补齐/ = 24 bytes (经Dev-C++验证)

p=0x1000000;

p+0x200=____;

= 0x1000000 + 0x200*24

(Ulong)p+0x200=____;

= 0x1000000 + 0x200

(char*)p+0x200=____;

= 0x1000000 + 0x200*4

可以参考一下指针运算的细节

  1. 写一段程序,找出数组中第k大小的数,输出数所在的位置。例如{2,4,3,4,7}中,第一大的数是7,位置在4。第二大、第三大的数都是4,位置在1、3随便输出哪一个均可。函数接口为:int find_orderk(const int* narry,const int n,const int k)
    要求算法复杂度不能是O(n^2)
  2. 请问一下程序将输出什么结果?
char *RetMenory(void)
{
       char p[] = “hello  world”;
       return p;
}
void Test(void)
{
       char *str = NULL;
       str = RetMemory();
       printf(str);
}

RetMenory执行完毕,p资源被回收,指向未知地址。返回地址,str的内容应是不可预测的, 打印的应该是str的地址

相关文章
|
1月前
|
网络协议 编译器 Linux
【C语言】结构体内存对齐:热门面试话题
【C语言】结构体内存对齐:热门面试话题
|
19天前
|
Java 程序员
面试高频考点!关于构造方法的那些事儿
本文介绍了Java中的构造方法,包括其基本概念、默认构造方法、构造方法的重载、构造方法的细节以及执行顺序。通过具体示例,详细解释了构造方法在对象初始化中的重要作用,帮助读者在面试中更好地应对相关问题。
24 1
|
1月前
|
Java 程序员
Java 面试高频考点:static 和 final 深度剖析
本文介绍了 Java 中的 `static` 和 `final` 关键字。`static` 修饰的属性和方法属于类而非对象,所有实例共享;`final` 用于变量、方法和类,确保其不可修改或继承。两者结合可用于定义常量。文章通过具体示例详细解析了它们的用法和应用场景。
28 3
|
5月前
|
存储 安全 编译器
C语言面试题1-10
指针声明后立即初始化。 内存释放后将指针置为NULL。 避免越界访问。 10. 一个指针变量占几个字节? 一个指针变量的大小与系统和编译器相关。在32位系统中,指针变量占4个字节;在64位系统中,指针变量占8个字节。 通过深入了解以上问题,能够更好地掌握C语言内存管理的核心概念,提高编写高效、安全代码的能力。
55 1
|
1月前
|
Serverless 编译器 C语言
【C语言】指针篇- 深度解析Sizeof和Strlen:热门面试题探究(5/5)
【C语言】指针篇- 深度解析Sizeof和Strlen:热门面试题探究(5/5)
|
3月前
|
C语言
C语言操作符(补充+面试)
C语言操作符(补充+面试)
45 6
|
3月前
|
算法 C语言
【面试题】【C语言】寻找两个正序数组的中位数
【面试题】【C语言】寻找两个正序数组的中位数
30 0
|
5月前
|
存储 安全 编译器
C语言面试题11至20题
在C语言中,可以使用以下方式实现循环: for循环:用于确定次数的循环。 for (int i = 0; i < 10; i++) { // 循环体 } while循环:用于条件控制的循环。 while (condition) { // 循环体 } do-while循环:至少执行一次的条件循环。 do { // 循环体 } while (condition); 通过深入理解这些面试题,可以更好地准备编程面试,展示对编程原理和技术细节的深刻掌握。
48 3
|
5月前
|
存储 缓存 C语言
C语言面试题30至39题
. 用变量a给出下面的定义 由于题目未明确定义,这里给出几个常见定义: 整数变量:int a; 字符变量:char a; 浮点变量:float a; 双精度浮点变量:double a; 指针变量:int *a; 通过理解和掌握这些面试题,可以更好地准备编程面试,展示对编程原理和技术细节的深刻掌握。
52 2
|
6月前
|
存储 算法 C语言
从C语言到C++_39(C++笔试面试题)next_permutation刷力扣
从C语言到C++_39(C++笔试面试题)next_permutation刷力扣
61 5