西邮linux兴趣小组2021-2023纳新面试题

西安邮电大学Liunx兴趣小组2021——2023面试题又长又臭版




2021年面试题


  1. 大小和长度竟然不是一个意思

    • sizeof()和strlen()异同

    • 他们对于不同参数的结果有什么不同

int main(void)
{
    char s[] = "I love linux\0\0\0";
    int a = sizeof(s);
    int b = strlen(s);
    printf("%d %d\n",a,b);
}

嗯嗯,首先关于sizeof和strlen的区别:sizeof返回的结果是对象的大小,所以输出中的a的大小就应该是s的大小(不会有人觉得大小是15吧,注意字符串后面会补‘\0’);
然后是strlen,它返回的是字符串的长度,但是!这个长度统计到’\0‘就结束了,并且不包括‘\0’,切记切记。



2. 箱子的大小和装入物品的顺序有关

  • 两个结构体的大小是否相等呢?
struct test1
{
    int a;
    short b;
    double c;
};

struct test2
{
    short b;
    int a;
    double c;
}
int main(void)
{
    struct test1 t1;
    struct test1 t2;
    printf("sizeof(t1): %d\n", sizeof(t1));
     printf("sizeof(t1): %d\n", sizeof(t2));
}

首先这两个结构体的大小是相等的(题目根本吓不到我)!!!这题考的内容是内存对齐,这两结构体的内存如下图在这里插入图片描述



  1. 哦,又是函数
    • 编写一个用来输出二维数组的函数
//在这补全函数
int main(void)
{
  int arr[10][13];
  for(int i = 0;i < 10;i++)
  {
      for(int j = 0;j < 13;j++)
      {
          arr[i][j] = rand();  //rand()函数用来生成伪随机数
      }
      func(arr);
  }
}

答案:“你真的看不见我吗”!
直接上代码

func(int arr[10][13]) //因为上面把数组的大小已经定义了,所以直接写
{
  for(int i = 0;i < 10;i++)
  {
      for(int j = 0;j < 13;j++)
      {
          printf("%d ",arr[i][j]);
      }
  }
}


  1. 就不能换个变量名吗
  • 谈谈传值和传址的区别
  • 对生命周期的理解
int ver = 123;
void func1(int ver)
{
    ver++;
    printf("ver = %d\n",ver);
}
void func2(int *pr)
{
    *pr = 1234;
    printf("*pr = %d\n",*pr);
    pr = 5678;
    printf("ver = %d\n",ver);
}
int main()
{
    int a = 0;
    int ver = 1025;
    for(int a = 3;a < 4;a++)
    {
        static int a = 5;
        printf("a = %d\n",a);
        a = ver;
        func1(ver);
        int ver = 7;
        printf("ver = %d\n",ver);
        func2(&ver);
    }
    printf("a = %d\tver = %d\n",a ,ver);
}

运行结果如下

a = 5
ver = 1026
ver = 7
*pr = 1234
ver = 123
a = 0 ver = 1025

我们就从结果来看:对于第一个a=5,在for循环里声明的a会把循环条件那的a给“屏蔽”掉,所以第一个输出a的值为5,还要注意的是循环里的a是静态变量,具有文件作用域(也即是它的生命周期和程序一样长,只有在程序结束时才被释放);
然后是第一个ver值,同理a,它输出main函数里声明的ver;而后循环里又声明一个ver且值被赋予7,即第二个ver输出,注意这里并不是对ver重赋值,从中也可以看出局部变量的屏蔽作用也只有在被声明后才行;对于*pr的值是很好理解的,先对指针解引用再赋值;第三个ver的值就不那么对劲了,不是已经屏蔽掉高一级变量了吗?其实这里有个坑,在调用这个函数的时候,如果没有给它传对应参数,它就会默认调用全局变量,举个栗子

int a = 123;
void func1()
{
    printf("%d",a);
}
void func2(int a)
{
    printf("%d",a);
}
void func3(int *p)
{
    printf("%d",a);
}
int main(void)
{
    int a = 1;
    func1();    //结果为123
    func2(a);   //结果为1
    func3(&a);  //结果为123

}

回到前面,在摆脱掉for循环的块后,a和ver的值就变成main开头声明的值了。那么传值和传址的区别呢?我们知道函数在结束后就会把前面拷贝的数据释放掉,对于传值,最后拷贝变量被释放,所以函数过后其值并不会改变;对于传址,最后释放的是指向变量的地址,而值没被释放,所以函数结束后值会改变。对于生命周期通俗点讲就是变量能活多久



  1. 套娃真好玩
  • 说明下面函数如何求和
unsigned sum(unsigned n)
{
    return n ? sum(n - 1) + n : 0;
}
int main(void)
{
    printf("%u\n", sum(100));
}

其实就是函数的递归啦。我们直接倒过来看,最后一次函数的调用n等于0,然后退到上一层返回的sum(n-1)+n中的sum()就是0,然后加上n即为1,再返回上一层,sum()为1(前一层的结果就是后一层的sum()值),加上n为2等于3,然后重复这个过程就实现了相加啦。



  1. 算不对的算术
void func(void)
{
short a = -2;
unsigned int b = 1;
b += a;
int c = -1;
unsigned short d = c*256;
c <<=4;
int e = 2;
e = ~e | 6;
d = (d & 0xff) + 0x2022;
printf("a=0x%hhx\t\nb=0x%hhx\t\nd=0x%hhx\t\ne=0x%hhx\t\n",a,b,d,e);
printf("a=0x%hhx\t\n",(signed char)c);
}

b+a等于-1,但b是无符号类型,所以会发生下溢,所以b会等于unsigned int最大值端开始减少,d也同理。然后是位运算,请大家自行查看
d
在这里插入图片描述
e
在这里插入图片描述



  1. 指针和数组的恩怨情仇
int main(void)
{
    int a[3][3] = {{1, 2, 3}{4, 5, 6}{7, 8, 9}};
    int(*b)[3] = a;
    ++b;
    b[1][1] = 10;
    int *ptr = (int *)(&a + 1);
    printf("%d %d %d\n",a[2][1],**(a+1),*(ptr-1));
}

首先b是一个指向3个int大小的指针(区别*b[3]),对b加1,实际上实现了3个int的跨越,然后把数组第一排第一列的数赋值为10,最后对二维数组取址,此时它说指向的地址是整个二维数组,所以加1后直接跨过了整个数组,所以ptr指向该数组的下一个地址,那么ptr-1(区别前面数组取址所指的“地址块”大小)后就指向数组最后一个了,至于双重解引用就没什么好说的。



  1. 移形换位之术
  • 使用值或地址调用a,b, c是否正确
  • 找出语法错误
  • const int和int const是否有区别
  • const int和int const是否有区别
int a = 1;
int const b = 2;  //不能变
const int c = 3;  //不能变
void func0(int n)
{
    n += 1;    
    n = a;
}
void func1(int *n)
{
    *n += 1;  
    n = &a;
}
void func2(const int *n)
{
    *n += 1;   //不能变
    n = &a;
}
void func3(int *const n)
{
    *n += 1;  //不能变
    n = &a;   
}
void func4(const int *const n)
{
    *n += 1;  //不能变
    n = &a;   //不能变
}

实际上const int和int const并没有什么区别,但对于指针就不一样了
const int*指向的变量可以改变但指向不能改变
int *const指向可已改变但指向的值不能变
const int *const两者皆不能改变




  1. 听说翻转字母大小不影响英文的阅读
  • 编写转换字母大小写,并返回字符串的函数 convert
char *convert(const char *s);
int main(void)
{
    char *str = "XiyouLinux Group 2022";
    char *temp = convert(str);
    puts(temp);
}

废话不多说,上代码

char *convert(const char *s);
int main(void)
{
    char *str = "XiyouLinux Group 2022";
    char *temp = convert(str);
    puts(temp);
    free(temp);  //因为用了分配内存,所以需要释放
}
char *convert(const char *s)
{
    int lenth = strlen(s);
    char *gets =(char *)malloc(sizeof(s));
    strcpy(gets,s);
    for(int i=0;i<lenth;i++)
    {
        if(gets[i]<='Z'&&gets[i]>='A')
        {
            gets[i] += (char)32;
        }
        else if(gets[i]<='z'&&gets[i]>='a')
        {
            gets[i] -= (char)32;
        }
    }
    return gets;
}



  1. 交换礼物的方式
    • 锐评一下下面三个swap
    • do while(0)作用
    • 其他实现swap方法
#define Swap1(a, b, t)\ 
do                  \
{                   \
  t = a;            \     //记得加
  a = b;            \
  b = t;            \
}while (0)          \

#define Swap2(a, b) \
do                  \
{                   \
  int t = a;        \
  a = b;            \
  b = t;            \
}while (0)          \

void Swap3(int a,int b)
{
  int t = a;
  a = b;
  b = t;
}

使用#define调换的数是可以保存的而函数方式不会
主要看看第二问,我们都知道define是对内容的“替换”,在有多行替换的时候就可能出问题,比如这样

#define Swap(a,b) \
        int t = a;\
        a = b;    \
        b = t;    \
int main(void)
{
    int a,b;
    scanf("%d %d",&a,&b);
    if(a>b)
    Swap(a,b);
}

我们本来是想如果a>b才换,可实际上因为if只管一行,就会出大问题,而使用do while(0)就不存在这个问题
其他实现swap方法(乱写的啊)

a = a+b;   
b = a-b;   
a = a-b;


  1. 据说有个东西叫参数
  • argc和argv的含义
  • 在不使用argc的情况下遍历argv
int main(int argc,char *argv[])
{
    printf("argc = %d\n",argc);
    for(int i =0;i < argc;i++)
    printf("%s\n", argv[i]);
}

argc的值为我们在命令行中调用的参数的个数,argv则记录了这些参数,值得一提的是调用文件本身也是一个参数,所以argc的值最少也为一。



  1. 人去楼空
  • 代码是否有误,谈谈静态变量
int *func1(void)
{
    static int n=0;
    n = 1;
    return &n;
}
int *func2(void)
{
    int *p = (int *)malloc(sizeof(int));
    *p = 3;
    return p;
}
int *func3(void)
{
    int n = 4;
    return &n;
}
int main(void)
{
    *func1() = 4;
    *func2() = 5;
    *func3() = 6;
}

关于静态变量不必多说,主要看看程序,如果运行程序,会在func3出问题,原因是局部变量会随此函数一起被释放,其地址指向的内容不明,是不被允许的,相反的静态变量因为储存在静态区,不会和函数一起释放,所以是可以的。



  1. 奇怪的输出
int main(void)
{
    int date[]={0x636c6557, 0x20656d6f, 0x78206f74, 0x756f7969, 0x6e694c20, 0x67207875,0x70756f72,0x32303220,0x00000a31};
    puts((const char *)data);
}

这题的知识点是大小端储存(第一次看到的时候直接懵逼)关于大小端储存是什么,我从万能的网络粘来了:
大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,存储模式类似把数据当作字符串顺序处理。
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,存储模式将地址的高低和数据位权有效地结合起来。

(我们平常用的笔记本是小端储存)



好多好难写(哭)


2022年面试题


  1. 我的计算器坏了?!
  • 210000对应十进制是多少位
    一道简单数学题,设它为k位数,则10k+1>210000>10k
    再取 l g lg lg就可以判断了



1. printf还能这么玩

  • 解释程序输出
int main(void)
{
    if((3 + 2 < 2)>(3 + 2 > 2))
    printf("Welcome to Xiyou Linux Group\n");
    else
    printf("%d\n",printf("Xiyou Linux Group - 2%d", printf("")));
}

首先是判断,先是判断2>2,不满足表达式值为0,再进行加法后判断,肯定是不满足的啦,所有执行else,然后是printf的嵌套,printf的返回值为它输出内容的长度,对于嵌套是由内往外执行的,就ok了。



  1. 你好你好你好呀
  • 尝试解释程序输出
  • 谈谈对sizeof和strlen的理解
int main(void)
{
    char p0[] = "Hello Linux";
    char *p1 = "Hello Linux";
    char p2[11] = "Hello Linux";
    printf("p0 == p1: %d, strcmp(p0, p2): %d\n", p0 == p1,strcmp(p0,p2));
    printf("sizeof(p0): %zu, sizeof(p1): %zu, sizeof(*p2): %zu\n",sizeof(p0), sizeof(p1), sizeof(*p2));
    printf("strlen(p0): %zu, strlen(p1): %zu\n",strlen(p0), strlen(p1));
}

字符串的比对就是从左到右按asc码比对字符,只有一一对应才相等,否则第一个不等字符谁编码大则对应字符串就大。strcmp是包含在string.h头文件的函数,用于比对字符串大小,相等返回0,若第一个参数小于第二个,则返回负数(asc码之差),反之返回正数。p0和p1都是代表了地址,而两者的地址肯定不相同,故p0 == p1等于0,p2因数组大小没有’\0’,所以p0比p2返回-72,p0大小为12('\0’别漏),p2指向字符串第一个字符的地址,解引用后大小为1,p1是指针为8。



  1. 换个变量名不行吗*
int a = 3;
void test()
{
    int a = 1;
    a += 1;
    {
        int a = a + 1;
        printf("a = %d\n", a);
    }
    printf("a = %d\n", a);
}
int main(void)
{
    test();
    printf("a = %d\n", a);
}

第一个打印a会有‘a’ is used uninitialized的警告,a的值不能确定,视不同情况而定。



  1. 内存对不齐
  • union和struct各自特点和他们的内存分配
typedef union
{
    long l;
    int i[5];
    char c;
}UNION;
typedef struct
{
    int like;
    UNION coin;
    double collect;
}STRUCT;
int main(void)
{
    printf("sizeof(UNION) = %zu\n",sizeof(UNION));
    printf("sizeof(struct) = %zu\n",sizeof(struct));
}

union共用一块内存其内存大小1为最大成员值,union和struct都要内存对齐
如下图

在这里插入图片描述在这里插入图片描述



  1. Bitwize
  • 用yong纸笔写出推导结果
  • 对位运算的理解
int main(void)
{
    unsigned char a = 4|7;
    a<<=3;
    unsigned char b = 5&7;
    unsigned char c = 6^7;
    c = ~c;
    unsigned short d = (a ^ c)<< 3;
    signed char e = -63;
    e <<= 2;
    printf("a: %d, b: %d, c :%d, d: %d\n",a,b,c, (char)d);
    printf("e: %#x\n", e);
}

其实就是基本的位运算,只是要注意d转char类型只保留8位,因为char只有8位
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述



  1. 英译汉
    const作用
  • char *const p;
  • char const *p;
  • const char *p;
    int const* 是指向 const int 的指针
    int *const 是指向 int 的 const 指针
    const int const* 是指向 const int 的 const 指针



  1. 英译汉
  • 含有10个指向int的指针的数组
  • 指向含有10个int数组的指针
  • 含有3个指向函数的指针的数组,被指向的函数有1个int参数并返回int
int *p[10];
int (*p)[10];
int (*p[3])(int);


  1. 混乱中建立秩序
  • 谈谈排序算法
  • 排序算法的思想,稳定性,时间复杂度,空间复杂度
    冒泡
void BubbleSort(int array[], int n)
{
    int i, j, k;
    for(i=0; i<n-1; i++)
        for(j=0; j<n-1-i; j++)
        {
            if(array[j]>array[j+1])
            {
                k=array[j];
                array[j]=array[j+1];
                array[j+1]=k;
            }
        }
}



  1. 手脑并用
  • 实现ConvertAndMerge:输入两个字符并拼接,并翻转新字符串字母的大小写
  • 提示:你需要为字符串分配内存
char *ConvertAndMerge(/*补全签名*/);
int main(void)
{
    char words[2][20] = {"Welcome to Xiyou",{"Linux Group 2022"}}
    printf("%s\n",word[0]);
    printf("%s\n",word[1]);
    ConvertAndMerge(word);
    printf("str = %s\n",str);
    free(str);
}

代码如下

char *ConvertAndMerge(char s[2][20])
{
    char *gets =(char *)malloc(sizeof(s));
    sprintf(gets,"%s%s",s[0],s[1]);
    int lenth = strlen(gets);
    for(int i=0;i<lenth;i++)
    {
        if(gets[i]<='Z'&&gets[i]>='A')
        {
            gets[i] += (char)32;
        }
        else if(gets[i]<='z'&&gets[i]>='a')
        {
            gets[i] -= (char)32;
        }
    }
    return gets;
}


  1. 给你我的指针,访问我的心声
  • 程序输出有些奇怪,请尝试解释一下程序输出
int main(int argc, char **argv)
{
    int arr[5][5];
    int a = 0;
    for(int i = 0;i < 5;i++)
    {
        int *temp = *(arr + i);
        for(int j = 0;i < 5;j++)
        {
            *temp = a++;
        }
    }
    for(int i = 0;i < 5;i++)
    {
        for(int j = 0;j < 5;j++)
        {
            printf("%d\t",arr[i][j]);
        }
    }
}

先看结果

0       1       2       3       4       25      26      27      28      29      45      46      47      48      49      60      61      62      63      6470       71      72      73      74

为啥呢?第一次循环temp指到arr[0],然后循环从arr[0][0]的值由0到24,最后a=25,然后第二次循环temp指到arr[1],再开始循环,从arr[1][0]开始赋值,由25到44,此时a=45,循环依次进行就得到了输出。



  1. 奇怪的参数
  • 你了解argc和argv
  • 直接运行argc为什么值是1
  • 程序会死循环吗
int main(int argc,char **argv)
{
    printf("argc = %d\n", argc);

    while(1)
    {
    argc++;
    if(argc < 0)
        {
            printf("%s\n", char( *)argv[0])
            break;
        }
    }
}

前两问直接粘贴:argc的值为我们在命令行中调用的参数的个数,argv则记录了这些参数,值得一提的是调用文件本身也是一个参数,所以argc的值最少也为一。
关于循环,并不会出现死循环,我们知道数据的存储有溢出的情况,argc一直增加到上界,发生上溢然后从下界开始向上增到0结束循环



  1. 奇怪的字符
  • 程序的输出有点奇怪,解释一下输出
int main(int argc,char**argv)
{
    int data1[2][3] = {{0x636c6557,0x20656d6f,0x58206f74},{0x756f7969,0x6e694c20,0x00000000}}
    
    int data2[] = {{0x47207875,0x70756f72,0x32303220,0x00000a32}};
    char *a = (char *)data1;
    char *b = (char *)data2;
    char buf[1024];
    strcpy(buf, a);
    strcpy(buf, b);
    printf("%s\n", buf);
}

大小端储存请参考2021年面试题



  1. 小试牛刀
  • 请谈谈对#define的理解
  • 解释程序输出
#define SWAP(a, b, t) t = a;a = b; b = t
#define SQUARE(a) a * a
#define SWAPWHEN(a, b, t, cond) if(cond) SWAP(a, b, t)
int main()
{
    int tmp;
    int x = 1;
    int y = 2;
    int z = 3;
    int w = 3;
    SWAP(x, y, tmp);
    printf("x = %d, y = %d, tmp = %d\n", x, y, tmp);
    if(x > y) SWAP(x, y, tmp);
    printf("x = %d, y = %d, tmp = %d\n", x, y, tmp);
    SWAPWHEN(x, y, tmp, SQUARE(1 + 2 + z++ + ++w) == 100);
    printf("x = %d, y = %d, tmp = %d\n", x, y, tmp);
    printf("z = %d, w = %d, tmp = %d\n", z, w, tmp);
}

结果如下

x = 2, y = 1, tmp = 1
x = 1, y = 2, tmp = 2
x = 2, y = 2, tmp = 2
z = 5, w = 5, tmp = 2

我们主要看看第三个输出的SQUARE,进行代替后就成了

1 + 2 + z++ + ++w * 1 + 2 + z++ + ++w == 100

然后是SWAPWHEN,if语句只包含了一条语句即:

if(rand) t=a

其余的a = b;b = t都不属于if的语块内。




写不完,根本写不完(悲)


2023面试题



  1. 鼠鼠我呀,要被祸害了
  • 有1000瓶水,其中一瓶有毒,小白鼠只尝一点带水的毒,24小时后就会准时死亡,
    至少需要多少只小白鼠才能在24小时内鉴别出哪瓶水有毒?

我们使用译码器法,将1000瓶水用二进制编号,再将这1000瓶水按某一位是否为1分为10组(1000按二进制编号有10位,所以分10组)如第一组都是二进制编号第一位为1的水瓶的水,然后让10只小鼠喝下,若老鼠死亡,那么毒水的编号这一位就为1,反之为0,就可以找出来啦。



  1. 先预测一下~
  • 按照函数要求输出自己的姓名试试~
char *welcome()
{
    //请返回自己的姓名
}
int main(void)
{
    char *a = welcome();
    printf("Hi, 我相信 %s 可以面试成功!\n", a);
    return 0;
}
char *welcome()
{
    char *name="翠花";
    return name;
}
int main(void)
{
    char *a = welcome();
    printf("Hi, 我相信 %s 可以面试成功!\n", a);
    return 0;
}

最后函数释放的是地址,而字符串内容在常量区,没有被释放。(友情提示,还可以分配内存来实现)



  1. 欢迎来到Linux兴趣小组
  • 有趣的输出,为什么会变成这样子呢~
int main(void)
{
    char *ptr0 = "Welcome to Xiyou Linux!";
    char ptr1[] = "Welcome to Xiyou Linux!";
    if(*ptr0 == *ptr1)
    {
        printf("%d\n",printf("Hello, Linux Group - 2%d", printf("")));
    }
    int diff = ptr0 - ptr1;
    printf("Pointer Difference: %d\n", diff);
}

printf的嵌套已经不想多说,只是注意ptr0和ptr1虽然相等,但地址不同



  1. 一切都翻倍了吗?
  • 请解释一下程序的输出
  • 请谈谈对sizeof和strlen
  • 什么是sprintf(),它的返回值是什么
int main(void)
{
    char arr[] = {'L', 'i', 'n', 'u', 'x', '\0', '!'},str[20];
    short num = 520;
    int num2 = 1314;
    printf("%zu\t%zu\t%zu\n",sizeof(*&arr), sizeof(arr + 0),sizeof(num = num2 + 4));
    printf("%d\n",sprintf(str,"0x%x",num) == num);
    printf("%zu\t%zu\n", strlen(&str[0] + 1), strlen(arr + 0));
}

结果如下:

7       8       2
0
4       5

对数组名取址再解引用,结果还是数组本身,大小就为数组大小,和对数组名取大小一样,但数组名加0可不是这么回事,此时它代表的是地址,所以为8。然后还需注意sizeof是运算符,不是函数,所以sizeof里执行内容不会被保留,所以到最后num的值都是520,因为num是short类型,所以值为2。sprintf的返回值和它兄弟printf一样,都是打印长度。最后我们知道数组名也代表着数组的首地址,那么对数组首元素取址,就等价于数组名本身,再加1,地址右移1个,故长度为4,arr+0同理。



  1. 奇怪的输出
  • 程序的输出结果是什么样的,请解释一下结果
int main(void)
{
    char a = 64 & 127;
    char b = 64 ^ 127;
    char c = -64 >> 6;
    char ch = a + b - c;
    printf("a = %d b = %d c = %d\n",a, b, c);
    printf("ch = %d\n", ch);
}

运算如下:

在这里插入图片描述



  1. 乍一看就不想看的函数
  • 这个func()函数的功能是什么,怎么实现的?
int func(int a, int b)
{
    if(!a) return b;
    return func((a & b) << 1, a^b);
}
int main(void)
{
    int a = 4, b = 9, c = -7;
    printf("%d\n", func(a, func(b, c)));
}

我们知道&只有在都为1的情况下才为1,那么我们就可以用这个特性来表示进位,此时只需把结果右移一位就可以达到效果,^是在两个不相等的情况下才为1,否则为0,我们可以借此来表示不进位的位情况,然后是通过函数的递归实现进位与不进位的相加(这里不怎么好想,相当于进位结果和不进位结果又做为参数值进行“进位与不进位运算“),直到最后不产生进位,即a等于0,b值就是最开始参数的值的相加。



  1. 自定义过滤
  • 请实现filter()函数:过滤满足条件的数组元素
  • 提示:使用函数指针作为参数,并且你需要为它分配内存
typedef int (*Predicate)(int);
int *filter(int *array,int lenth, Predicate predicate, int *resultLenth);
int isPositive(int num){return num > 0;}
int main(void)
{
    int array[] = {-3, -2, -1, 0, 1, 2, 3, 4, 5, 6};
    int lenth = sizeof(array) / sizeof(array[0]);
    int resultLenth;
    int *filteredNumbers = filter(array, lenth, isPositive, &resultLenth);
    for(int i = 0; i < resultLenth; i++)
    {
        printf("%d ",filteredNumbers[i]);
    }
        printf("\n");
        free(filteredNumbers);
        return 0;
    
}

代码如下:

int *filter(int *array,int lenth, Predicate predicate, int *resultLenth)
{
    int *getarray=(int *)malloc(sizeof(int)*lenth);
    int k = 0;
    for(int i = 0;i < lenth;i++)
    {
        if(isPositive(array[i]))
        {
            getarray[k] = array[i];
            k++;
        }
    }
    *resultLenth = k;
     return getarray;
}


  1. 静……态……
  • 如何理解关键字static?
  • static和变量结合后有什么作用
  • static和函数结合后有什么作用
  • static和指针结合后有什么作用
  • static如何影响内存分配


    我们从两方面去认识static的作用,一个是生命周期,一个是可见性。对于static修饰的内容,其生命周期都和程序相同,这样就延长了生命周期;然后是可见性上,static修饰后,我们就只能在本文件使用,即为内部链接,在其他文件上是无法调用的。(静态变量默认初始化为 0)。



  1. 救命! 指针!
  • 数组指针是什么? 指针数组是什么? 函数指针ne? 用自己的话说出来更好o,下面数据类型的含义又是什么呢?
int (*p)[10];
const int *p[10];
int (*f1(int))(int *, int)

数组指针的本质是指针,它指向了某块“数组大小”的地址,如上的数组指针指向了一块10int大小的地址;
指针数组的本质数组,只是这个数组的元素是指针,如上的指针数组是有10个int的指针;
函数指针顾名思义,就是指向函数的指针,它包括了函数的返回值和参数,如上函数指针指向了一个返回值为int,参数为int
和int的函数。



  1. 咋不循环了
  • 程序直接运行,输出内容是什么意思
int main(int argc,char *argv[])
{
    printf("[%d]\n",argc);
    while(argc)
    {
        ++argc;
    }
    int i = -1, j = argc, k = 1;
    i++ && j++ || k++;
    printf("i = %d, j = %d, k = %d\n",i, j, k);
    return EXIT_SUCCESS;
}

main的参数请参考前文,对于循环,并不是循环没有进行,而是argc发生了上溢再从负值增为0。然后是逻辑表达式那行是完全执行的,从后面的输出也可以看出,需要注意的是&&优先级高于||。
最后提下EXIT_SUCCESS,它包含在stdlib.h头文件中的一个符号常量,表示一个程序的成功执行。



  1. 到底是不是TWO
#define CAL(a) a * a * a
#define MAGIC_CAL(a , b) CAL(a) + CAL(b)
int main(void)
{
    int nums = 1;
    if(16 / CAL(2) == 2)
    {
        printf("I'm TWO(丿>ω<)丿\n");
    }
    else
    {
        int nums = MAGIC_CAL(++nums, 2);
    }
    printf("%d\n", nums);
}

因为define是代换,所以if判断变成

16 / 2 * 2 * 2 == 2  //显然不成立

然后是关于

++nums * ++nums * ++nums

它的执行和具体环境有关,从而也造成在不同编译器下结果可能存在差异。



  1. 克隆困境
  • 试运行一下程序,为什么会出现这样的结果?
  • 直接将s2赋值给s1会出现哪些问题,应该如何解决?请写出相应代码
struct Student
{
    char *name;
    int age;
};
void initializeStudent(struct Student *student, const char *name, int age)
{
    student->name = (char *)malloc(strlen(name) + 1);
strcpy(student->name, name);
student->age = age;
}
int main(void)
{
    struct Student s1, s2;
    initializeStudent(&s1, "Tom", 18);
    initializeStudent(&s2, "Jerry", 28);
    s1 = s2;
    printf("s1 的姓名: %s 年龄:%d\n",s1.name, s1.age);
    printf("s2 的姓名: %s 年龄:%d\n",s2.name, s2.age);
    free(s1.name);
    free(s2.name);
    return 0;
}

程序出现的问题在最后的释放上,当我们将s2赋值给s1时,name指针都指向了同一块内存,然后我们第一次释放了这块内存,即第一个free,此时产生了一个问题,既然两个name指针都指向同一块内存,可我们已经释放了这块内存了,那么第二次释放的时候释放什么呢?问题就在这里,那么我们的解决方法就是给两个name指针都开辟一块空间,实现深拷贝。

 s1 = s2;
    s1.name =(char*)malloc(strlen(s1.name)+1);
    strcpy(s1.name,s2.name); 


  1. 你好,我是内存
  • 作为一名合格的从C-Coder,一定对内存很敏感吧~来尝试理解这个程序吧!
struct structure
{
    int foo;
    union
    {
        int integer;
        char string[11];
        void *pointer;
    }node;
    short bar;
    long long baz;
    int array[7];
}
int main(void)
{
    int arr[] = {0x590ff23c, 0x2fbc5a4d,0x636c6557, 0x20656d6f, 0x58206f74, 0x20545055,0x6577202c, 0x6d6f636c, 0x6f742065, 0x79695820, 0x4c20756f, 0x78756e69, 0x6f724720, 0x5b207075, 0x33323032, 0x7825005d, 0x636c6557, 0x64fd6d1d};
    printf("%s\n", ((struct structure *)arr)->node.string);
}

不能说一模一样,只能说完全相同,画个内存情况:
在这里插入图片描述

加上地址

0x7fffffffe110 0x7fffffffe118 0x7fffffffe128 0x7fffffffe130 0x7fffffffe138


阿弥陀佛,善哉,善哉
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值