C语言 面试题,C语言面试题目

  C语言 面试题,C语言面试题目

  主页:安全可靠

  作者:博客后起之秀2021年Top2

  我们的口号:一点点,大梦想

  作者要求:由于博主水平有限,难免有错误和失实之处。我也非常渴望知道这些错误。求铁汁批评指正。

  热点栏目:蓝桥杯基础算法分析

  首先复习一个知识点:

  传统上,数组名表示第一个元素的地址。

  有两个例外:

  Zeof(数组名):sizeof中放入单个数组名,此时的数组名不再代表第一个元素的地址,而是整个数组。计算整个数组的大小,单位是字节(注意这个单个的名字!);数组名:获取整个数组的地址。好了,介绍完这个知识点,请看下面这一系列的钢笔试题:

  一.一维数组//一维数组

  #包含stdio.h

  int main()

  {

  int a[]={ 1,2,3,4 };

  printf(%d\n ,sizeof(a));//16

  //将单个数组名A放入sizeof,此时的数组名代表整个数组,计算整个数组的大小(注意这个单个名称!)

  printf(%d\n ,sizeof(a 0));//4/8-32位平台上为4字节,64位平台上为8字节

  //此时sizeof中放置了多个数组名A,所以A表示第一个元素的地址,类型为int*,a 0跳过0个整数表示第一个元素的地址。

  //地址就是指针,32位平台占用4个字节,64位平台占用8个字节。

  printf(%d\n ,sizeof(* a));//4

  //此时,A表示第一个元素的地址。如果取消对它的引用,就会得到第一个元素,所以这里会计算第一个元素的大小。

  printf(%d\n ,sizeof(a 1));//4/8

  //此时,A表示第一个元素的地址,类型为int*,a 1跳过一个整数,所以a 1表示第二个元素的地址,也就是2的地址。

  printf(%d\n ,sizeof(a[1]));//4

  //计算第二个元素的大小

  printf(%d\n ,sizeof(a));//4/8

  //a取整个数组的地址,类型为int(*)[4],属于数组指针,数组指针还是指针。

  printf(%d\n ,sizeof(* a));//16

  //理解1:可以认为*和运算抵消了,此时只剩下sizeof(a),a)。a表示整个数组,计算整个数组的大小;

  //理解2: A,取出整个数组的地址,其类型为int(*)[4]数组指针类型,然后解引用。此时,整个数组被访问,其大小为16字节。

  printf(%d\n ,sizeof(a 1));//4/8

  //a取出整个数组的地址,类型为int(*)[4]数组指针。1跳过整个数组的地址,但地址是4/8字节。

  printf(%d\n ,sizeof(a[0]));//4/8

  //a[0],取出第一个元素的地址。

  printf(%d\n ,sizeof(a[0]1));//4/8

  //a[0] 1,跳过1个整数,所以a[0] 1访问第二个元素的地址。

  返回0;

  }

  第二,字符数组

  1.问题1注意这样一个概念:

  尺寸:

  Zeof只关注占用空间的大小;Sizeof不讲究类型;Sizeof是运算符

  strlen():

  Strlen()关注字符串中“\0”之前的字符数;Strlen()仅用于字符串;Strlen()是一个库函数。好的,请看下面的代码:

  代码1:

  #包含stdio.h

  int main()

  {

  char arr[]={ a , b , c , d , e , f };

  printf(%d\n ,sizeof(arr));//6

  //计算整个数组的大小

  printf(%d\n ,sizeof(arr 0));//4/8

  //计算第一个元素的地址

  printf(%d\n ,sizeof(* arr));//1

  //计算第一个元素的大小

  printf(%d\n ,sizeof(arr[1]));//1

  //计算第二个字符的大小

  printf(%d\n ,sizeof(arr));//4/8

  //arr,取出整个数组的地址,地址就是指针。

  printf(%d\n ,sizeof(arr 1));//4/8

  //arr 1,跳过了整个数组,但还是地址。

  printf(%d\n ,sizeof(arr[0]1));//4/8

  //arr[0]表示第一个字符的地址,类型是char*,所以arr[0] 1跳过一个字符,指向第二个字符的地址。

  返回0;

  }代码2:

  #包含stdio.h

  int main()

  {

  char arr[]={ a , b , c , d , e , f };

  printf(%d\n ,strlen(arr));//随机值

  //strlen()遇到“\0”的结尾。计算了 \0 前的字符数,但arr中没有 \0 ,所以不知道它在哪里结束,所以这里是随机值。

  printf(%d\n ,strlen(arr 0));//随机值

  //同上

  printf(%d\n ,strlen(* arr));//内存访问冲突

  //strlen()中的参数是指针类型(可以认为其中存储了地址),*arr表示第一个元素,即‘a’,其ACSII值为97,

  //所以strlen(*arr)将 97 作为内存地址访问,会导致内存访问冲突。

  printf(%d\n ,strlen(arr[1]));//内存访问冲突

  //同上,arr[1]表示 b ,ACSII值为98,strlen(arr[1])表示 98 作为内存地址访问。

  printf(%d\n ,strlen(arr));//随机值

  //arr,取出整个数组的地址。因为数组里没有 \0 ,所以不知道会在哪里结束。

  printf(%d\n ,strlen(arr 1));//随机值

  printf(%d\n ,strlen(arr[0]1));//随机值

  返回0;

  }

  这是这行代码的另一个重点:

  printf(%d\n ,strlen(* arr));

  stren()需要的是一个地址,从这个地址开始向后搜索字符,直到 \0 。计算 \0 前的字符数,但*arr表示第一个元素,即 a 。此时,ACSII值“a”被传递给strlen(),strlen()将从97开始。

  2.问题2代码1:

  #包含stdio.h

  int main()

  {

  char arr[]= abcdef ;

  printf(%d\n ,sizeof(arr));//7

  //注意sizeof(arr)计算arr数组占用的内存空间,包括 \0

  printf(%d\n ,sizeof(arr 0));//4/8

  //比较简单,就不赘述了。

  printf(%d\n ,sizeof(* arr));//1

  printf(%d\n ,sizeof(arr[1]));//1

  printf(%d\n ,sizeof(arr));//4/8

  printf(%d\n ,sizeof(arr 1));//4/8

  printf(%d\n ,sizeof(arr[0]1));//4/8

  返回0;

  }代码2:

  有了上面的经验,那么下面的对你来说一定不难!

  #包含stdio.h

  int main()

  {

  char arr[]= abcdef ;

  printf(%d\n ,strlen(arr));//6

  printf(%d\n ,strlen(arr 0));//6

  printf(%d\n ,strlen(* arr));//内存访问冲突

  printf(%d\n ,strlen(arr[1]));//内存访问冲突

  printf(%d\n ,strlen(arr));//6(这里要特别注意)

  printf(%d\n ,strlen(arr 1));//随机值

  printf(%d\n ,strlen(arr[0]1));//5

  返回0;

  }

  3.问题3代码1:

  #包含stdio.h

  int main()

  {

  char * p= abcdef

  printf(%d\n ,sizeof(p));//4/8

  printf(%d\n ,sizeof(p 1));//4/8

  printf(%d\n ,sizeof(* p));//1

  printf(%d\n ,sizeof(p[0]));//1

  printf(%d\n ,sizeof(p));//4/8

  printf(%d\n ,sizeof(p 1));//4/8

  printf(%d\n ,sizeof(p[0]1));//4/8

  返回0;

  }代码2:

  #包含stdio.h

  int main()

  {

  char * p= abcdef

  printf(%d\n ,strlen(p));//6

  printf(%d\n ,strlen(p 1));//5

  printf(%d\n ,strlen(* p));//内存访问冲突

  printf(%d\n ,strlen(p[0]));//内存访问冲突

  printf(%d\n ,strlen(p));//随机值(注意哦,这是特别容易出错的地方,特别容易错写成6)

  //这里我想说的是,P指的是常量字符串,和字符数组不一样。p有自己的空间。

  printf(%d\n ,strlen(p 1));//随机值

  printf(%d\n ,strlen(p[0]1));//5

  返回0;

  }

  补充常量字符串在指针类型中,我们知道有一种指针类型是char*,它有两种用法:

  一般用途:

  #包含stdio.h

  int main()

  {

  char ch= w

  char * pc=ch

  * pc= a

  printf(%c\n ,ch);

  返回0;

  }这个用法比较简单,我就不多赘述了。看一下下面的用法:

  #包含stdio.h

  int main()

  {

  char * p= abcdef

  printf(%s\n ,p);

  返回0;

  }

  注意,上面的abcdef是一个常量字符串。内存中存储的只读数据区(只读不可写)特别容易让我们以为字符串abcdef放在字符指针P中,其实本质上就是字符串abcdef在P中第一个字符的地址。

  所以下面的代码是有问题的:

  #包含stdio.h

  int main()

  {

  char * p= abcdef

  * p= w//目的是把‘a’改成‘w’(bug)

  返回0;

  }上面第6行的代码是错误的,因为常量字符串不能修改,所以为了避免上面的错误,可以将第5行的代码修改为:

  const char * p= abcdef这样就可以避免上面的错误。

  面试问题:

  #包含stdio.h

  int main()

  {

  char str1[]=hello bit ;

  char str2[]=hello bit ;

  char* str3=hello bit ;

  char* str4=hello bit ;

  if (str1==str2)

  printf(str1和str2相同\ n );

  其他

  printf(str1和str2不相同\ n );

  if (str3==str4)

  printf(str3和str4相同\ n );

  其他

  printf(str3和str4不相同\ n );

  返回0;

  }

  思考解决问题:

  Str1和str2是两个字符数组。数组的操作方式是把右边的常量字符串复制到数组的空间里,所以是两个空格,但是内容是一样的。作为数组名,str1和str2是数组第一个元素的地址,所以str1!=str2str3和str4是指向同一个常量字符串的两个字符指针,而常量字符串存储在单独的内存区(只读数据区)。当几个指针指向同一个常量字符串时,实际上是指向同一个内存块。

  三。二维数组# includesdio.h

  int main()

  {

  int arr[3][4]={ 0 };

  printf(%d\n ,sizeof(arr));//12*4=48

  //sizeof(数组名),以字节为单位计算整个数组的大小。

  printf(%d\n ,sizeof(arr[0][0]));//4

  printf(%d\n ,sizeof(arr[0]));//4*4=16

  //arr[0]相当于第一行的数组名。由于是单独放在sizeof里面,所以计算第一行的数组大小,单位是字节。

  printf(%d\n ,sizeof(arr[0]1));//4/8

  //arr[0]相当于第一行的数组名。由于arr[0]不是单独放在sizeof内部,所以此时它表示第一行的第一个元素的地址。

  printf(%d\n ,sizeof(*(arr[0]1)));//4

  //前面提到的arr[0]表示第一行第一个元素的地址,所以*(arr[0] 1)表示arr[0][1]元素本身

  printf(%d\n ,sizeof(arr 1));//4/8

  //arr数组名表示第一个元素的地址,也就是第一行数组的地址,所以arr 1表示第二行数组的地址。

  printf(%d\n ,sizeof(*(arr 1)));//4*4=16

  //前面提到的arr 1代表第二行数组的地址,对其进行解引用。被访问的第二行数组放在sizeof内部,计算第二行数组的大小。

  printf(%d\n ,sizeof(arr[0]1));//4/8

  //arr[0]表示第一行数组的地址,那么arr 1表示第二行数组的地址,地址就是指针。

  printf(%d\n ,sizeof(*(arr[0]1)));//4*4=16

  //前面提到arr[0] 1表示第二行数组的地址,所以解引用它表示第二行数组,单独放入sizeof,计算第二行数组的大小。

  printf(%d\n ,sizeof(* arr));//4*4=16

  //arr表示第一个元素的地址,即数组第一行的地址。它的解引用表示第一行数组,分别放在sizeof中,计算第一行数组的大小。

  printf(%d\n ,sizeof(arr[3]));//4*4=16

  //这里我们可能会认为arr[3]越界了,但是对这个问题没有影响。sizeof会推导出arr[3]的类型是int[4]

  返回0;

  }

  第四,模拟字符串库函数。

  1.strlen()函数原型:

  功能函数:

  求绳子的长度

  注意:返回值类型是size_t,这个size_t到底是什么?

  其实size_t是为sizeof运算符的返回值设计的。可以简单的认为size_t就是众所周知的无符号int。因为是求长度,所以肯定不会是负数,所以用的是无符号整数,但是也容易出现bug。请看下面的代码:

  解释下面的代码。输出结果是什么?

  #包含stdio.h

  #包含字符串. h

  int main()

  {

  if(strlen( ABC )-strlen( abcdef )0)

  printf(“”);

  其他

  printf(=);

  返回0;

  }是的,答案是输出" "。为什么?3-6=-3鸭子,怎么回事?

  这是因为strlen的返回值是size_t,属于无符号数,所以两个无符号数相减,答案一定是无符号数。

  那怎么修改呢?

  方案1:强制类型转换

  #包含stdio.h

  #包含字符串. h

  int main()

  {

  if((int)strlen( ABC )-(int)strlen( abcdef )0)

  printf(“”);

  其他

  printf(=);

  返回0;

  }方案二:直接比较

  #包含stdio.h

  #包含字符串. h

  int main()

  {

  if (strlen(abc) strlen(abcdef ))

  printf(“”);

  其他

  printf(=);

  返回0;

  }注意:

  以字符串 \0 作为结束标记,strlen返回字符串中 \ 0 之前的字符数(不包括 \ 0 );参数中指向的字符串必须以“\ 0”结尾;注意strlen函数的返回值是size_t类型,属于无符号类型(特别容易出错)。

  代码示例:

  #包含stdio.h

  #包含字符串

  int main()

  {

  int len=strlen( abcdef );

  printf(%d\n ,len);

  返回0;

  }自定义函数模拟实现strlen():

  方法:

  计数器递归方法指针-指针法

  方法1:计数器方法

  int my_strlen(const char* str)

  {

  断言(str);//断言字符串不为空

  int count=0;

  while (*str!=\0)

  {

  数数;

  str

  }

  返回计数;

  }方法二:递归法

  int my_strlen(const char* str)

  {

  断言(str);//断言字符串不为空

  //找到边界

  if (*str==\0 )

  {

  返回0;

  }

  int count=my _ strlen(str 1);

  //注意str和str 1是不同的概念

  数数;

  返回计数;

  }

  这里需要注意的是,str和str 1不是同一个概念。先用str,这个题目可以写成str的形式,可以先用。

  方法3:指针-指针

  指针指针实际上表示两个指针中间的元素数量。注意中间没有几个字节。

  int my_strlen(const char* str)

  {

  断言(str);

  const char * cur=str

  while (*cur!=\0)

  {

  cur

  }

  返回cur-str;

  }

  2.2.strcpy()函数的原型:

  功能函数:

  将源字符串复制到目标字符串,并返回目标字符串第一个元素的地址。

  解释以下代码:

  #包含stdio.h

  #包含字符串. h

  int main()

  {

  char arr 1[]= abcdef ;

  char arr 2[20]={ 0 };

  printf(%s\n ,strcpy(arr2,arr 1));

  返回0;

  }本体是将字符串arr2复制到字符串arr1,返回ARR2第一个元素的地址(目标字符串第一个元素的地址)。所以上面代码的输出是:abcdef,所以这里的问题是,字符串arr1中的 \ 0 会被复制到字符串arr2中吗,所以这里用下面的代码来验证这个问题:

  #包含stdio.h

  #包含字符串. h

  int main()

  {

  char arr 1[]= abcdef ;

  char arr 2[20]= XXXXXXXXXX ;

  printf(%s\n ,strcpy(arr2,arr 1));

  返回0;

  }首先,当字符串arr1还没有复制到arr2时,它们存储的数据如下:

  执行strcpy(arr2,arr1)时,此时存储在arr2中的数据如下:

  可以看到,将字符串arr1(源字符串)复制到字符串arr2(目标字符串)会自动复制源字符串末尾的 \ 0 ,并返回目标字符串起始位置的地址。

  这里还有一个问题:如果源字符串末尾没有加 \ 0 (这里以字符数组的形式演示,正常字符串的末尾会自动填充 \ 0 ),请看下面的代码:

  #包含stdio.h

  #包含字符串. h

  int main()

  {

  char arr1[]={ a , b , c , d , e , f };

  char arr 2[20]= XXXXXXXXXX ;

  printf(%s\n ,strcpy(arr2,arr 1));

  返回0;

  }代码执行结果:

  所以需要注意的是,如果要将源字符串复制到目标字符串,必须确保源字符串包含 \ 0 ,否则复制会失败。

  因此,在使用strcpy复制字符串时,需要注意以下几点:

  源字符串必须以“\ 0”结尾;复制时,源字符串中的“0”将被复制到目标字符串中;目标字符串(目标空间)必须足够大,以确保源字符串可以被存储;还有一点就是目标字符串必须是可变的。

  请看下面的代码:

  #包含stdio.h

  #包含字符串. h

  int main()

  {

  char arr 1[]= abcdef ;

  const char * p= XXXXXXXXXX

  printf(%s\n ,strcpy(p,arr 1));

  返回0;

  }

  执行程序是错误的,因为此时的目标字符串是由const修饰的,不可修改。

  自定义功能模拟实现strcpy()

  代码执行:

  char* my_strcpy(char* dest,const char* src)

  {

  char * ret=dest

  断言(dest src);

  While (*dest=*src )//太棒了

  {

  ;

  }

  返回ret

  }

  3.3.strcat()函数的原型:

  功能函数:

  将源字符串追加到目标字符串的末尾,并返回目标字符串第一个字符的地址。

  解释以下代码:

  #包含stdio.h

  #包含字符串. h

  int main()

  {

  char arr 1[30]= hello ;

  char arr 2[]= world ;

  strcat(arr1,arr 2);

  printf(%s\n ,arr 1);

  返回0;

  }上面的代码是将“world”拼接到“hello”的后面,所以打印出来的结果如下:

  其实使用strcat库函数的注意事项和strcpy很像,这里就不重复解释了:

  源字符串必须以“\ 0”结尾;目标空间必须足够大,以容纳源字符串的内容;目标必须是可变的。

  所以想象一下:如果让我们自己实现strcat函数,我们该怎么办?先想想大概意思。首先,我们需要找到目标字符串的结束标记 \0 ,然后将源字符串拼接到目标字符串的后面,最后返回目标字符串第一个字符的地址。这似乎很简单,所以让我们来实现它:

  通过自定义函数模拟实现strcat()

  代码执行:

  char* my_strcat(char* dest,const char* src)

  {

  char * ret=dest

  断言(dest src);

  //1,找到目标字符串的\0

  While (*dest)//注意,把*dest写成循环条件是错误的,因为\0会被跳过。请小心。

  {

  dest

  }

  //2.复制源字符串

  while (*dest=*src)

  {

  ;

  }

  返回ret

  }

  4.4.strcmp()函数的原型:

  功能函数:

  比较相应位置字符的字典顺序。

  标准:

  第一个字符串和第二个字符串,则返回一个大于0的数字;第一个字符串==第二个字符串,则返回0;第一个字符串和第二个字符串,则返回小于0的数字。

  敲黑板:

  两个字符串不能直接比较或者加减,因为字符串代表第一个字符的地址。也就是说,如果直接进行比较,比较的不是字符串的内容,而是地址,所以是错误的。

  通过自定义函数模拟实现strcmp()

  代码执行:

  int my_strcmp(const char* str1,const char* str2)

  {

  断言(str 1 str 2);

  While (*str1==*str2)//注意是循环体中判断相等的情况。想想为什么。

  {

  if (*str1==\0 )

  返回0;

  str1

  str2

  }

  if(* str 1 * str 2)//return * str 1-* str 2;

  返回1;

  其他

  return-1;

  }

  5.模拟记忆功能。

  1.memcpy()函数原型:

  注意,内存操作函数中的第三个参数单位是字节。

  为什么是void*型?

  因为设计者在设计的时候不知道这个库函数会用什么类型来复制,所以最好设计成void*。

  请看下面的代码:

  #包含stdio.h

  #包含字符串. h

  int main()

  {

  int arr1[]={ 1,2,3,4,5,6,7,8,9,10 };

  int arr 2[5]={ 0 };

  memcpy(arr2,arr1 5,5 * sizeof(arr 1[0]);

  int I=0;

  for(I=0;i5;我)

  {

  printf(%d ,arr 2[I]);

  }

  返回0;

  }

  自定义功能模拟实现memcpy()

  代码执行:

  void* my_memcpy(void* dest,const void* src,size_t num)

  {

  void * ret=dest//注意返回类型是void*,不是void,

  断言(dest src);

  while(num-)//先用它,然后-

  {

  *(char *)dest=*(char *)src;//想想为什么把类型强制转换成char*,因为只有它最合适

  dest=(char *)dest 1;//注意直接dest,src是错误的,因为是空类型。

  src=(char *)src 1;

  }

  返回ret

  }

  2.memmove()函数原型:

  实际上,C语言只要求:

  Memy可以复制不重叠的内存空间,memmove处理那些重叠的内存副本。也就是说,如果memcpy的函数是A,那么memmove的函数就是A B。

  那么什么是重叠内存副本呢?请看下面的代码:

  #包含stdio.h

  #包含字符串. h

  int main()

  {

  int arr1[]={ 1,2,3,4,5,6,7,8,9,10 };

  memmove(arr1 2,arr1,5 * sizeof(arr 1[0]);//当处理相同的空间时,会出现重叠的内存副本

  int I=0;

  for(I=0;i 10我)

  {

  printf(%d ,arr 1[I]);

  }

  返回0;

  }自定义功能模拟实现memmove

  代码执行:

  void* my_memmove(void* dest,const void* src,size_t num)

  {

  void * ret=dest

  断言(dest src);

  If (dest src)//从前到后复制

  {

  while (num -)

  {

  *(char *)dest=*(char *)src;

  dest=(char *)dest 1;

  src=(char *)src 1;

  }

  }

  Else//从后向前复制

  {

  //src=(char *)src num-1;//一定要-1

  //dest=(char *)dest num-1;

  //while (num -)

  //{

  //*(char *)dest=*(char *)src;

  //dest=(char *)dest-1;

  //src=(char *)src-1;

  //}

  while(num-)//首先使用它,然后-,在循环中,它是num在-(真奇妙)之后

  {

  *((char*)目标编号)=*(char *)src编号);

  }

  }

  返回ret

  }

  六、遇见安然遇见你,不辜负守则。

  今天的面试问题到此为止。有所收获的老铁,正愁用小手搞三网融合。

  安然无恙。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • c语言调用退出函数 c语言退出整个程序怎么写
  • c语言中怎么给函数初始化 c语言的初始化语句
  • c语言编写函数计算平均值 c语言求平均函数
  • 详解c语言中的字符串数组是什么,详解c语言中的字符串数组结构,详解C语言中的字符串数组
  • 表达式求值c++实现,c语言实现表达式求值
  • 看懂c语言基本语法,C语言详解,C语言的基本语法详解
  • 用c语言实现快速排序算法,排序算法设计与实现快速排序C语言,C语言实现快速排序算法实例
  • 深入解析c语言中函数指针的定义与使用方法,深入解析c语言中函数指针的定义与使用情况,深入解析C语言中函数指针的定义与使用
  • 描述E-R图,E-R图举例,关于C语言中E-R图的详解
  • 折半查找法C语言,折半查找算法(算法设计题)
  • 折半查找法C语言,c语言折半法查找数据,C语言实现折半查找法(二分法)
  • 扫雷小游戏c++代码设计,c语言扫雷游戏源代码,C语言实现扫雷小游戏详细代码
  • 怎样统计程序代码行数,C语言统计行数,C#程序员统计自己的代码行数
  • 基于c语言的贪吃蛇游戏程序设计,用c语言编写贪吃蛇游戏程序,C语言实现简单的贪吃蛇游戏
  • 图的两种遍历算法,图的遍历算法代码c语言,Python算法之图的遍历
  • 留言与评论(共有 条评论)
       
    验证码: