C语言面试准备(基础知识)_c语言面试基础知识-程序员宅基地

技术标签: c语言  C基础  

1.C 语言中static的作用
/*    1.修饰全局变量,限制其作用域,防止在其他文件单元中被引用。
    2.修饰局部变量,限制其生命周期且只被初始化一次,下一次依据上一次的值。
    3.修饰函数,限制函数作用域仅限于本文件,而不能被其他文件调用(被static修饰的函数,内存中只有一份,普通函数每次调用都会维持一份拷贝)
*/
    
2.要对绝对地址0x100000000赋值可以用(unsigned int*)0x10000000 = 1234;那么要让程序跳转到绝对地址
    去执行,应该怎么做?
/*    1.强制转换对应地址为函数指针。
        (void*())0x10000000;    
    2.调用
        *((void *())0x10000000);
*/

3.不用C库函数比较两个字符串的大小,相等返回0,str1大于str2返回1,str1小于str2返回-1
 

int myStrCmp(const char *str1, const char *str2){
    if(NULL == str1 && NULL == str2){
                    return 0;
    }else if(NULL == str1 && NULL != str2){
                    return -1;
    }else if(NULL != str1 && NULL == str2){
                    return 1;
    }
            
    int len1, len2, cmpLen;
    char *p = str1;
    char *q = str2;
    len1 = 0;
    len2 = 0;
    cmpLen = 0;
    while(*p){
        len1++;
        p++;
            }
    while(*q){
        len2++;
        q++;
    }
            
    cmpLen = (len1 < len2)? len1:len2;
    p = str1;
    q = str2;
    while(cmpLen >0){
        if(*p > *q){
            return 1;
        }else if(*p < *q){
            return -1;
        }else{
            p++;
            q++;
            cmpLen--;
        }
    }
            
    if(len1 > len2){
         return 1;
    }else if(len1 < len2){
         return -1;
    }else{
         return 0;
    }
}

  
//chatGPT的答案:
int compare_str(char *str1, char *str2)
{
    int i = 0;
    while(str1[i] != '\0' && str2[i] != '\0')
    {
        if(str1[i] > str2[i])
            return 1;
        else if(str1[i] < str2[i])
            return -1;
        i++;
    }
    if(str1[i] == '\0' && str2[i] == '\0')
        return 0;
    else if(str1[i] == '\0')
        return -1;
    else
        return 1;
}


4.实现一个将字符串逆序的方法,例如原始字符穿"abcd" 逆序后"dcba"

char *reverseStr(char *str){
    assert(NULL != str);

    char *p = str + strlen(sstr)-1;; 
    char *q = str;
    char temp ;

    while(q < p ){
        temp = *p;
        *p = *q;
        *q = temp;
        p--;
        q++;
    }
    p = NULL;
    q = NULL;
    return str;
}

5.以下输出是什么?

#include <stdio.h>
int main(){
    char aChar;
    int  aInt;
    aInt = aChar = -120;//右->左
    printf("%d\n", aInt);
}

-120

6.memcpy和mmmove的区别
    1.memcpy 是memmove的子集
    2.memcpy 比memmove快
    3.若源地址与目标地址出现重合,memcpy可能出现错误,memmove不会

7.memcpy的实现:dest是目标地址,src是源地址,n是操作的字节数

void *myMemcpy(void *dest, void* src, size_t n){
    assert(NULL != dest && NULL != src);
    char *p = (char*)(src+n -1);
    char *q = (char*)(dest+n-1);
    while(n--){
        *q-- = *p--;
    }
    
    return dest;
}

8.memmove的实现:dest是目标地址,src是源地址,n是操作的字节数

void * memmove(void *dest, void *src, size_t n){
    char *d = (char *)dest;
    const char *s = (const char*)src;

    if(s>d){
        while(n--){
            *d++ = *s++;
        }
    }else if(s<d){
        d = d+n-1;
        s = s+n-1;
        while(n--){
            *d-- = *s--;
        }
    }

    return dest;
}

9.说明const的使用意义,若错误注明ERR
    1.const int *p 
    2.int const *p 
    //2同1,表示不能通过指针改变指针指向变量的值
    //如:int i = 10; const int *p = &i; *p = 100这个动作将报错 
    3.int* const p 
    //表示p的指向不能变
    //int i = 10;
    //int j = 100;
    //int * const p = &i;
    //p = &j;此时,若让p再指向j,此处将报错
    4.const int* const p
    //既无法改变指针指向,也无法改变指针只想的值

10.写出 bool,float,指针变量与"零值"的比较
    

bool :if(flag)
         if(!flag)
float:if((x >= 0.000001)&&(x <= 0.000001)) //x == 0.0
ptr  :
    if(NULL == ptr)
    if(NULL != ptr)

11.以下为Linux64位环境,请计算下列 sizeof()的值
    void Func(char str[100]){
        请计算:
        sizeof(str) = 8;
    }
    
    char str[] = "hello";
    char *p = str;
    int  n = 10;

    sizeof(str) = 6;//字符数组的大小
    sizeof(*p)  = 8;//指针8字节
    sizeof(n)   = 4;//int占4字节

12.const 作用
    1.修饰指针变量,const int *p 或者int const *p 表示不能通过指针p修改指向变量的值
    2.修饰指针变量,int* const p 表示不能修改指针指向
    3.修饰指针变量,const int* const p 指针及其指向的变量均不可修改
    4.修饰函数参数,返回值,甚至是函数体,被const修饰的对象将受到强制保护,防止被意外
      修改,提高程序的健壮性。

13.volatile 关键字的作用,及应用场景
    告诉优化器在用到这个关键字修饰的变量时,必须小心的重新读取这个变量的值,而不是
    使用保存在寄存器里的备份
    EXP:
        多线程应用中被几个任务共享的变量;
        并行设备的寄存器

14.在 C++程序中调用被C语言编译后的函数,为什么要加 extern "C" 声明
    C++支持函数重载,C不支持,函数在被C++编译后在库中的名字与C语言的
    不同,例如:某个函数的原型为void foo(int x, int y)该函数被C编译后
    在库中的名字为_foo, 而C++编译器则会产生像_foo_int_int之类的名字。
    C++提供了【C链接交换指定符号】extern "C" 来解决名字匹配问题

15.简述下面两个for循环的优缺点
    for(i=0; i<N; i++){
        if(condition){
            doSomethint;
        }else{
            doOtherthing;
        }
    }

    if(condition){
        for(i=0; i<N; i++){
            doSomeThing;
        }
    }else{
        for(i=0; i<N; i++){
            doOtherThing;
        }
    }

    //第二个判断一次,执行N次效率高, 第一代码简洁

16.有test函数如下
    

void GetMemory(char *p){
    p = (char*)malloc(100);
}
void Test(void){
    GetMemory(str);
    strcpy(str, "Hello World");
    printf(str);
}


    请问运行test会有什么结果?
    1.调用GetMemory()的时候,传参是str的一个copy副本,所以str并没有被分配内存
    2.申请空间没有释放,内存泄露
    3.strcpy访问了未申请的空间,可能会输出字符串,但是程序崩溃

17. char *GetMemory(void){
    char p[] = "hello world";
    return p;
}

void test(void){
    char *str = NULL;
    str = GetMemory();
    printf(str);
}
请问运行test会有什么样的结果
//在函数GetMemory运行结束后,其申请的栈空间随即消亡,str指向内存中一段未申请的
//空间,可能打印出字符串,程序可能崩溃

18.void GetMemory(char **p, int num){
    *p = (char *)malloc(num);
}

void Test(void){
    char *str = NULL;
    GetMemory(&str, 100);
    strcpy(str, "hello");
    printf(str);
}
//申请空间未释放,内存泄露,其他没问题19.shell 脚本实现输入年份,并输出其是否是闰年(闰年:可以被4整除却不能被100整除,或者可以被400整除的年份)

#!/bin/bash

input(){
    input_var=""
    while [ -z $input_var ]
    do
        read -p "请输入$1" input_var
    done
    echo $input_var
}

year=$(input 年份)

if [ $[ $year%4 ] -eq 0  -a  $[ $year%100] -ne 0 ]  || [ $[ $year%400 ] -eq 0 ]
then
    echo "$year 是闰年"
else
    echo "$year 不是闰年"
fi

20.使用脚本输出以下图形

*
**
***

#!/bin/bash

for((i=1; i<=3; i++))
do
    for((j=0; j<i; j++))
    do
        echo -n "*"
    done
    echo ""
done

21.如何引用一个已经定义的全局变量
    1.可以用引用头文件的方式也可以使用关键字extern
    2.使用关键字extern时,如果把变量写错了,编译不会报错,运行时会报错
      引用头文件,如果写错变量名,编译时就会报错

22.定义一个宏,返回两个参数中的较小的一个
#define  MIN(x,y) (x) < (y)?(x):(y)

23.C 语言中什么样的逻辑是 true
    非空

24.简述C语言的内存分布
    栈
    堆
    全局变量区
    静态存储区
    代码段

25.队列和栈的区别
    1.队列先进先出
    2.栈,先进后出

26.使用宏定义实现swap(x,y),不使用第三方变量交换两个数的值
#define swap(x,y) do{x=x+y; y=x-y; x=x-y}while(0)
或者
#define swap(s,y) do{x^=y; y^=x; x^=y} while(0)
注意宏定义结尾没有分号

27.计算下面的值
#include <stdio.h>
int main(){
    int a,b,c,d;
    a = 10;
    b = a++;
    c = ++a;
    d = 10*a++;
    printf(a,b,c,d);
    return 0;
}

计算输出结果
13,10,12,120

28.设有以下说明和定义(64位系统)
typedef union{
    long i;
    int k[5];
    char c;
}Date;

struct data{
    int cat;
    Date cow;
    double dog;
};

Date max;
printf("%d", sizeof(struct data)+sizeof(max));
sizeof(max)->联合体,大小由最大的成员确定,每次申请8字节,大于20(sizeof(int)*5)且是8的整数倍
的最小数字即24
结构体中嵌套联合体的,等于结构体大小+联合体大小,data结构体中,每次申请8字节,由于联合体嵌套在中间,前后各申请一个8字节的空间即 8+24+8 = 40字节

29.unsigned char *p1;
   unsigned char *p2;
   p1 = (unsigned char*)0x81000000;
   p2 = (unsigned long*)0x83000000;
请问
   p1+5 = 0x81000005;
   p2+5 = 0x81000028;

不同类型的指针的步长问题。P2的步长是long,8字节,p2+5 一共移动 8*5 即40字节,按16进制表示就是0x28.

30.使用变量a给出以下定义
    1.一个指向指针的指针,它指向的指针是指向一个整型数
        int  **a;
    2.一个有10个指针的数组,该指针指向一个整型数的
        int * a[10];
    3.一个指向10个整型数组的指针
        int (*a) [10];
    4.一个指向函数的指针,该函数有一个整型参数并返回一个整型值
        int (*a) (int);
    5.一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型值
        int (*a[10])(int);

31.用C语言反转一个单向链表
    

head----->头指针
    struct xxx*    prev = NULL;
    struct xxx* next = NULL;

struct xxx* reverseLink(struct xxx* head){
    if(NULL == head){
        return head;
    }
    while(head != NULL){
        next = head->next;  //记录下一个节点地址
        head->next = prev;  //摘下头节点
        prev = head;        //记录新的头节点
        head = next;        //指向下一个待摘取节点
    }
    return prev;
}

32.用C语言写一个函数,判断一个正整数是否是2的整数次幂

if(!(a&(a-1))){
    printf("是");
}else{
    printf("否")
}

33.解释什么叫死锁及如何避免
    1.死锁:两个及以上的进程在执行时,由于竞争资源或者由于彼此通信
      而造成的一种阻塞现象。若无外力干涉,它们将无法推进下去,这些
      永远相互等待的进程称谓死锁
    2.互斥使用,资源只能被一个进程/线程占用
      不可剥夺, 资源请求者不能强制从资源占有着手中夺取资源,资源只
      能由占用着主动释放。
    3.请求和保持,即当前西苑请求者,在请求其他资源的时候,同时保持
      对原资源的占用
    4.循环等待,即存在一个等待队列,他们相互环形等待

    避免:
    1.打破互斥
    2.改造独占资源为虚拟资源
    3.打破不可抢占条件,当已进程占有已独立资源后,又申请一独立资源无法
      满足,则退出当前资源占用。
    4.检测进程状态

34.下面的进程输出结果是什么

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

&a 类似一个行指针,类似于int (*ptr)[5] = a;
&a+1 将指针从数组的首地址偏移了 sizeof(a)字节,即此时指向了数组a的末尾
由于ptr是int类型的指针,ptr-1向前偏移4个字节,指向了数组的最后一个元素
即5
a+1 指针偏移sizeof(int)字节,指向第二个元素即 2
所以最终结果 2  5

35.内存对齐问题:

计算下列结构体的大小:

union   U1{

long    a;

short  b;

};

struct  S1{

union U1   ua;

int   b : 3;

long   :0;

char   c;

int      d;

char buf[];

}

printf("sizeof(struct  S1)= [%d]\n", sizeof(struct S1));

sizeof(struct   S1)  =  24;

union  占8字节

随后(int  b )再次申请8字节空间,long : 0;强制从下一个8的整数倍开始对其,所以char   c ,  int   d 占用第三个8字节空间,结尾的不定数组不占用空间,共计24字节。(个人见解,欢迎指正)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/int_t/article/details/115443302

智能推荐

Docker 快速上手学习入门教程_docker菜鸟教程-程序员宅基地

文章浏览阅读2.5w次,点赞6次,收藏50次。官方解释是,docker 容器是机器上的沙盒进程,它与主机上的所有其他进程隔离。所以容器只是操作系统中被隔离开来的一个进程,所谓的容器化,其实也只是对操作系统进行欺骗的一种语法糖。_docker菜鸟教程

电脑技巧:Windows系统原版纯净软件必备的两个网站_msdn我告诉你-程序员宅基地

文章浏览阅读5.7k次,点赞3次,收藏14次。该如何避免的,今天小编给大家推荐两个下载Windows系统官方软件的资源网站,可以杜绝软件捆绑等行为。该站提供了丰富的Windows官方技术资源,比较重要的有MSDN技术资源文档库、官方工具和资源、应用程序、开发人员工具(Visual Studio 、SQLServer等等)、系统镜像、设计人员工具等。总的来说,这两个都是非常优秀的Windows系统镜像资源站,提供了丰富的Windows系统镜像资源,并且保证了资源的纯净和安全性,有需要的朋友可以去了解一下。这个非常实用的资源网站的创建者是国内的一个网友。_msdn我告诉你

vue2封装对话框el-dialog组件_<el-dialog 封装成组件 vue2-程序员宅基地

文章浏览阅读1.2k次。vue2封装对话框el-dialog组件_

MFC 文本框换行_c++ mfc同一框内输入二行怎么换行-程序员宅基地

文章浏览阅读4.7k次,点赞5次,收藏6次。MFC 文本框换行 标签: it mfc 文本框1.将Multiline属性设置为True2.换行是使用"\r\n" (宽字符串为L"\r\n")3.如果需要编辑并且按Enter键换行,还要将 Want Return 设置为 True4.如果需要垂直滚动条的话将Vertical Scroll属性设置为True,需要水平滚动条的话将Horizontal Scroll属性设_c++ mfc同一框内输入二行怎么换行

redis-desktop-manager无法连接redis-server的解决方法_redis-server doesn't support auth command or ismis-程序员宅基地

文章浏览阅读832次。检查Linux是否是否开启所需端口,默认为6379,若未打开,将其开启:以root用户执行iptables -I INPUT -p tcp --dport 6379 -j ACCEPT如果还是未能解决,修改redis.conf,修改主机地址:bind 192.168.85.**;然后使用该配置文件,重新启动Redis服务./redis-server redis.conf..._redis-server doesn't support auth command or ismisconfigured. try

实验四 数据选择器及其应用-程序员宅基地

文章浏览阅读4.9k次。济大数电实验报告_数据选择器及其应用

随便推点

灰色预测模型matlab_MATLAB实战|基于灰色预测河南省社会消费品零售总额预测-程序员宅基地

文章浏览阅读236次。1研究内容消费在生产中占据十分重要的地位,是生产的最终目的和动力,是保持省内经济稳定快速发展的核心要素。预测河南省社会消费品零售总额,是进行宏观经济调控和消费体制改变创新的基础,是河南省内人民对美好的全面和谐社会的追求的要求,保持河南省经济稳定和可持续发展具有重要意义。本文建立灰色预测模型,利用MATLAB软件,预测出2019年~2023年河南省社会消费品零售总额预测值分别为21881...._灰色预测模型用什么软件

log4qt-程序员宅基地

文章浏览阅读1.2k次。12.4-在Qt中使用Log4Qt输出Log文件,看这一篇就足够了一、为啥要使用第三方Log库,而不用平台自带的Log库二、Log4j系列库的功能介绍与基本概念三、Log4Qt库的基本介绍四、将Log4qt组装成为一个单独模块五、使用配置文件的方式配置Log4Qt六、使用代码的方式配置Log4Qt七、在Qt工程中引入Log4Qt库模块的方法八、获取示例中的源代码一、为啥要使用第三方Log库,而不用平台自带的Log库首先要说明的是,在平时开发和调试中开发平台自带的“打印输出”已经足够了。但_log4qt

100种思维模型之全局观思维模型-67_计算机中对于全局观的-程序员宅基地

文章浏览阅读786次。全局观思维模型,一个教我们由点到线,由线到面,再由面到体,不断的放大格局去思考问题的思维模型。_计算机中对于全局观的

线程间控制之CountDownLatch和CyclicBarrier使用介绍_countdownluach于cyclicbarrier的用法-程序员宅基地

文章浏览阅读330次。一、CountDownLatch介绍CountDownLatch采用减法计算;是一个同步辅助工具类和CyclicBarrier类功能类似,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。二、CountDownLatch俩种应用场景: 场景一:所有线程在等待开始信号(startSignal.await()),主流程发出开始信号通知,既执行startSignal.countDown()方法后;所有线程才开始执行;每个线程执行完发出做完信号,既执行do..._countdownluach于cyclicbarrier的用法

自动化监控系统Prometheus&Grafana_-自动化监控系统prometheus&grafana实战-程序员宅基地

文章浏览阅读508次。Prometheus 算是一个全能型选手,原生支持容器监控,当然监控传统应用也不是吃干饭的,所以就是容器和非容器他都支持,所有的监控系统都具备这个流程,_-自动化监控系统prometheus&grafana实战

React 组件封装之 Search 搜索_react search-程序员宅基地

文章浏览阅读4.7k次。输入关键字,可以通过键盘的搜索按钮完成搜索功能。_react search