常见代码试题

指针概念辨析

  • 指针 - 指针得到的是指针和指针值之间的 元素个数
  • 整形指针解引用访问 4个字节
  • 指针可以比较大小
  • 整形指针+1 意味着  向后偏移4个字节
  • 当使用free释放掉一个指针内容后,指针变量的值不会被更改,需要手动置NULL
  • 野指针是指向未分配或者已经释放的内存地址
  • char* p = "hello";中p指向字符串第一个元素地址
  • 数组指针是指针    ;  指针数组是数组
  • int* fun(int a,int b) 与 (int*)fun(int a,int b)相同,都是代表函数声明
  • char* arr[5] = {"hello"};test(arr);与之对应的子函数void test(char* *arr);

数组概念辨析

  • 除了sizeof(arr)和&arr中的数组名,其他地方出现的数组名arr,都是数组首元素的地址
  • 二维数组能省略行,不能省略列

调试常见概念

  • C语言中常见的错误分类包括编译错误连接错误运行时错误
  • Debug被称为调试版本,不做优化;而Release被称为发布版本,不能调试
  • 声明一个指向char类型变量的指针p,p值不可修改,p指向的变量值可以修改,则char*const p

代码识别

1.unsiged char的存储计算(整型提升)

#include 
//unsigned char的存储计算
int main()
{
    unsigned char a = 200;
    unsigned char b = 100;
    unsigned char c = 0;
    c = a + b;
    printf("%d %d",a + b,c);//输出结果为 300 44
    return 0;
    //解析
    //char存放一个字节   1byte = 8bit a,b均为正数,原反补码均相同(在内存中以补码形式存储)
    //a是无符号位unsigned定义的,即1100 1000 而因为200是个整型所以真正的比特位00000000 00000000 00000000 11001000
    //b是无符号位unsigned定义的,即0110 0100 而因为100是个整型所以真正的比特位00000000 00000000 00000000 01100100
    //c = a + b   要发生整型提升?
    //因为两者相加一定会超过8个bit位,必然发生整型提升
    //00000000 00000000 00000000 11001000 - a
    //00000000 00000000 00000000 01100100 - b
    //00000000 00000000 00000001 00101100 - c(unsigned char占8bit)
    //因为c是由unsigned char定义的 要拿出 8个bit
    //00101100 - c 即44
    // 如果没有存到c里边,单单只是 a+b
    //则为  00000000 00000000 00000001 00101100 - a+b
    // 即为300
    
}

2.小端与大端存储的识别

#include 
//在小端模式和大端模式的处理器分别输出多少
int main()
{
    unsigned int a = 0x1234;
    unsigned char b = *(unsigned char*)&a;
    printf("%d",b);//小端52 大端0
    return 0;
    //解析
    //&a取到a的地址,
    //将地址强转为无符号 unsigned char*(指针)类型,*(unsigned char*)&a在对地址解引用得到地址得到内容,即1字节内容
    //小端模式 低->高
    //34 12 00 00
    //得到十六进制34 即52
    //大端模式 低->高
    //00 00 12 34
    //得到十六进制00 即0
}

3.数组存储空间开辟与不同指针指向同一字符

#include 
int main()
{
    char str1[] = "hello";
    char str2[] = "hello";
    char* str3 = "hello";
    char* str4 = "hello";
    if(str1 == str2)
        printf("\n");
    else
        printf("str1 and str2 are not same\n");
    if(str3 == str4)
        printf("\n");
    else
        printf("str3 and str4 not point same local\n");
    return 0;
        //输出结果为: str1 and str2 are same
        //            str3 and str4 point same local
}

常见代码试题_第1张图片

代码试题

1.逆序函数

#include 
#include 
#include 

void reverse(char *arr);

//逆序函数,要将字符数组中元素逆序
//答:先写逻辑,将数组进行赋值后,将指针指向开始,和结尾,当两个指针指向同一个元素时,循环结束
int main()
{
    char arr[255] = {0};
    scanf("%s",arr);
    reverse(arr);
    printf("%s",arr);
    return 0;
}

void reverse(char *arr)
{
    //保证值的有效性
    assert(arr);
    //查找字符串的长度
    int len = strlen(arr);
    //数组的第一个元素地址
    char* left = arr;
    //数组的后边要交换的元素的位置
    //arr指向数组第0个元素
    //len是长度,在数组是以0开始的,所以要len-1
    //arr + len - 1代表数组的最后一个元素地址
    char* right = arr + len - 1;
    while (left <= right)
    {
        int tmp = *left;
        *left = *right;
        *right = tmp;
        left++;
        right--;
    }
}

2.产生类似2 22 222 2222 ...的前n项和

#include 
//
//答:先写逻辑,由2 变 22 在变 222 中途以 2*10*n + 2 在不断循环演变,要求出和,则用循环将每一项都加起来
int main()
{
    int n = 0;//输出2的个数
    int m = 0;//输出2的个数的几次
    scanf("%d%d",&n,&m);
    int i = 0;
    int sum = 0;
    int ret = 0;//当作第几次乘以10,从零开始
    for (i = 0; i < m;i++) //循环 m 次 即输出2的次数
    {
        //通过ret计算2 22 222 ...
        ret = ret * 10 + n;
        //将上边的计算结果累加到sum中取
        sum = ret + sum;
        printf("%d ",ret);
    }
    printf("\nsum :%d",sum);

}

3.水仙花数详解

//打印水仙花数(自幂数)在10万范围内
//答:先写逻辑,水仙花数是什么?水仙花数是指一个 3 位数,它的每个数位上的数字的 3次幂之和等于它本身。例如:1^3 + 5^3+ 3^3 = 153。
//通过以上定义可知,首先要知道其位数,后要求出每一位的次方(即位数),后求和。通过循环进行遍历每一个数值,得出结论
int main()
{
    int i = 0;
    for (i = 0;i < 100000;i++)
    {
        //1.求出数值的位数
        int n = 1; //一个数的最小位数为  1位数
        int tmp = i; //将主循环的值拿过来,进行比对,找到每个数的位数
        while (tmp=tmp/10) //比如123 123/10=12 12/10=1 1/10=0 这里就是为什么我们将n定义为1的原因
        {
            n++;
        }
        //2.计算i的每一位n次方之和
        tmp = i;
        int sum = 0;
        while (tmp)//计算每一位的当前次方的值的总和
        {
            sum = sum + pow(tmp%10,n); //tmp%10即每一位数值      pow(n,m)即为n的m次方
            tmp = tmp / 10;  //去掉 123 的个位数 ,变为12,在进入循环,以此类推
        }
        //3.比较是不是水仙花数的特征即 i == sum
        if( i == sum)
        {
            printf("%d ",i);
        }
    }
}

4.自定义打印菱形

#include 
//自定义打印菱形
//    *
//   ***
//  *****
//   ***
//    *
//答:先写逻辑,第一行的*与第n行的*的开始位置相差m个位置的空格,每行空格之间差一个*,这是上三角;下三角与前相反
int main()
{
    int line = 0;//定义最长及上半部分的行数
    int i = 0;
    scanf("%d",&line);
    //打印上半部分(包含中间)
    for (i = 0;i < line ;i++)
    {
        //1.打印空格
        int j = 0;
        for (j = 0;j < line- 1 - i ;j++)//line-1代表第一行的空格数 ,后-i代表遍历每行空格数(避免每行空格数量不变,同时将空格数-i个)
        {
            printf(" ");
        }
        //2.打印*
        for (j = 0;j < 2 * i + 1;j++)//i从第一行开始以2i+1的数列递增
        {
            printf("*");
        }
        printf("\n");
    }
    //打印下部分
    for (i = 0; i < line - 1; i++)//line - 1 代表不包含中间最长的一行
    {
        //1.打印空格
        int j = 0;
        for (j = 0; j <= i ; j++)//从0行开始打印,直到等于line行数
        {
            printf(" ");
        }
        //2.打印*
        for (j = 0; j < 2*(line - 1- i) -1 ; j++)//((line -1 )【代表下部分的行数】*2)-1代表这一行的应有*的个数,在其中-1是避免每行的*个数打印出来的相同
        {
            printf("*");
        }
        printf("\n");
    }

}

5.喝汽水

//喝汽水,两个空瓶换一瓶汽水,假设你买了20瓶,求你最后喝了几瓶
//答:先写逻辑,每次被2整除+被2取余,得到你的能换的汽水数,在此过程中,去找店主换汽水,循环往复
#include 
int main()
{
    int water = 0;//没喝的的水
    int empty = 0;//空瓶子
    int total = 0;//喝了多少汽水
    int i = 0;
    int j = 0;
    scanf("%d",&water);
    //买来的汽水全部喝掉
    total = water;
    empty =  water;
    //换汽水
    while (empty>=2) //只有瓶子大于等于两个瓶子时,才可以换
    {
        total += empty / 2;//empty / 2 代表能换多少汽水 + total = 一共喝了多少汽水
        i = empty / 2;//换汽水后喝后的空瓶数
        j = empty % 2;//加上一个‘单’,除不尽时可能还剩一瓶子
        empty = i + j;
    }
    printf("TOTAL : %d",total);//输入20时 输出 TOTAL : 39
    return  0;
}

6.存储一串数组,将其数字排列,奇数在前,偶数在后

#include 


void bubble_sort(int *arr, int sz);

void move(int *arr, int sz);

int main()
{
    int arr[10] = {5,3,2,1,6,7,8,9,10,0};
    int sz = sizeof (arr) / sizeof(arr[0]);
    bubble_sort(arr,sz);
    return 0;
}

void move(int *arr, int sz) {
    int left = 0;
    int right = sz - 1;

    //循环条件
    while (left < right) {
        //找奇数
        while ((*(arr + left) % 2 == 1) && (left < right)) {
            left++;
        }
        //找偶数
        while ((*(arr + right) % 2 == 0) && (left < right)) {
            right--;
        }
        //交换奇偶
        if (left < right) {
            int tmp = *(arr + left);
            *(arr + left) = *(arr + right);
            *(arr + right) = tmp;
        }
    }
    int i = 0;
    for (i = 0; i < sz ; i++)
    {
        printf("%d ",*(arr + i));
    }
    printf("\n");
}

void bubble_sort(int *arr, int sz)
{

    int i = 0;
    //外层循环,我比到数字的位置从0开始
    for (i = 0;i < sz - 1; i++)
    {
        //内层循环,即我得数组跟谁比
        int j = 0;
        //sz - 1代表整个数组得下角标 在-i的目的是在比较完这次后,这个数字我就不用比了
        for (j = 0;j < sz - 1 - i;j++)
        {
            //这是升序排列
            if(*(arr + j)>*(arr + j + 1))
            {
                int tmp = *(arr + j);
                *(arr + j) = *(arr + j + 1);
                *(arr + j + 1) = tmp;
            }

        }
    }

    for (i = 0; i < sz ; i++)
    {
        printf("%d ",*(arr + i));
    }
    printf("\n");
    //将其奇偶排序
    move(arr,sz);
}

7.杨辉三角(不理想版)

#include 
//打印杨辉三角
//     1
//    1 1
//   1 2 1
//  1 3 3 1
//  ........
//思路:先写逻辑,根据杨辉三角的特性,我可以将其变形
//1
//1 1
//1 2 1
//1 3 3 1
//得到如上这幅图
//也就是说我们可以先打印二维数组,将他的第一列和对角线全部赋值为1,而中间需要计算的元素,即每2个元素相加的出下一列中间的元素
int main()
{
    //存放数字的二维数组
    int arr[10][10] = {0};
    int i = 0;//控制行
    int j = 0;//控制列
    for (i = 0; i < 10;i++)
    {
        for (j = 0;j <= i;j++)//保证数组它是一个下三角,草稿纸上画下就出来了
        {
            //第一列为1
            if(j == 0)
            {
                arr[i][j] = 1;
            }
            //对角线为1,比如三行三列为1,但数组表示为[2][2]
            if(j == i)
            {
                arr[i][j] = 1;
            }
            //计算数值(不包括第一列和第二行)
            if(i > 1 && j > 0)//比如:2行 1列 = 1行 0列 + 1行 1列
            {
                arr[i][j] = arr[i-1][j-1] + arr[i-1][j];
            }
        }
    }
    for (i = 0;i < 10;i++)
    {
        for (j = 0; j <= i; ++j)
        {
            printf("%d ",arr[i][j]);
        }
        printf("\n");
    }

}

8.猜凶手

#include 
//猜凶手 , 已知3人说了真话,1个人说了假话
//A说:不是我
//B说:是C
//C说:是D
//D说:C再胡说
//答:先写逻辑,用已知条件,逐个判断进行假设,排除每个嫌疑
int main()
{
    int killer = 0;
    //从a开始判断
    for (killer = 'a';killer <= 'd';killer++)
    {
        //满足条件即为凶手
        if(((killer != 'a') + (killer == 'c') + (killer == 'd') + (killer != 'd')) == 3)
        {
            printf("murderer is %c",killer);
        }
    }
}

9.猜名次

#include
//猜名次
//5位运动员参加了10米跳水比赛,根据以下比赛结果
//A选手说:B第二,我第三
//B选手说:我第二,E第四
//C选手说:我第一,D第二
//D选手说:C最后,我第三
//E选手说:我第四,A第一
//比赛结束后,每位选手都说答对了一半,请变成确定比赛名次
//答:先写逻辑,可以采用枚举暴力法,从全部选手所说的第一个条件,依次遍历每个选手另一个条件,直到条件满足,
//我们可以将答对赋值为1,答错赋值为0,最终结果为5;以及再加上附加条件即遍历到某个排列组合的乘积为1*2*3*4*5=120
//最终确定比赛名次
int main()
{
    int a = 1;//A选手
    int b = 1;//B选手
    int c = 1;//C选手
    int d = 1;//D选手
    int e = 1;//E选手
    for (a = 1; a <= 5;a++)
    {
        for (b = 1;b <= 5;b++)
        {
            for (c = 1;c <= 5;c++)
            {
                for (d = 1;d <= 5;d++)
                {
                    for (e = 1;e <= 5;e++)
                    {
                        if(
                            ((b==2)+(a==3)==1)&&
                            ((b==2)+(e==4)==1)&&
                            ((c==1)+(d==2)==1)&&
                            ((c==5)+(d==3)==1)&&
                            ((e==4)+(a==1)==1)
                            )
                        {
                            if(a*b*c*d*e==120){
                                printf("a=%d b=%d c=%d d=%d e=%d",a,b,c,d,e);
                            }
                        }
                    }
                }
            }
        }
    }
    return 0;
}

10.左旋字符串

#include 
#include 
#include 

void left_bl_move(char *arr, int n);

void left_fz_move(char *arr, int n);

void reverse(char *left, char *right);


//实现一个函数,可以左旋字符串中的k个字符
//例如:旋转一个ABCD左旋得到BCDA
//左旋转两个字符得到CDAB
//答:方法一:先写逻辑,暴力求解法,将传进来的值存放进一个临时变量,将后边的每一项向前移
//   方法二:先写逻辑,三步翻转法,翻转2个字符
//                abcdef
//                ba fedc 将逆序
//                cdefab  再逆序
int main()
{
    char arr[] = "abcdef";
    int n = 0;
    scanf("%d",&n);
    left_bl_move(arr,n);//暴力求解法
    left_fz_move(arr,n);//三步翻转法
}


void left_fz_move(char *arr, int n)
{
    assert(arr);//检查值是否有效
    int len = strlen(arr);
    reverse(arr,arr+n-1);//abcdef -> ba cdef
    reverse(arr+n,arr+len-1);//ba cdef -> ba fedc
    reverse(arr,arr+len-1);//ba fedc ->cdefab
    int i = 0;
    printf("\n");
    printf("%s",arr);

}

void reverse(char *left, char *right)
{

    while (left < right)
    {
        char tmp = *left;
        *left = *right;
        *left = tmp;
        left++;
        right--;
    }
}

void left_bl_move(char *arr, int n)
{
    assert(arr);//检查值是否有效
    int i = 0;
    int len = strlen(arr);
    for (i = 0;i < n;i++)
    {
        //将要替换i个值拿出来
        char tmp = *arr;
        //将这个值后变得值往前移
        int j = 0;
        for (j = 0;j < len-1;j++)//len-1最右边元素位置
        {
            //将后边元素向前移动n个位置
            *(arr + j) = *(arr + j + 1);
        }
        //将tmp移过去
        *(arr + len -1) = tmp;
    }
    printf("%s",arr);
}

11.判断目标字符串是否由原字符串左旋得来

#include 
#include 
#include 

int is_left_move(char *arr1, char *arr2);
void left_move(char *arr, int n);

int is_left_move1(char *arr1, char *arr2);

//
//写一个函数,判断字符串是否为另外一个字符串旋转之后的字符串
//例如:S1 = AABCD和 S2 = BCDAA。返回1  给定s1 = abcd和s2=acbd,返回0
//答:先写逻辑,方法一:暴力法,定义两个字符串,将一个字符串左旋(遍历)与目标字符串进行比较(strcmp)
//           方法二:将主串复制两次,将目标串依次与主串左到右比较
int main()
{
    //定义两个字符串,不能用char*进行赋值(不可修改)
    char arr1[] = "abcdef";
    char arr2[] = "cdefab";
    //左旋判断
    // 方法一
    int ret = is_left_move(arr1,arr2);
    if(ret == 1)
        printf("YES");
    else
        printf("NO");
    // 方法二
    //int ret1 = is_left_move1(arr1,arr2);
//    if(ret1 == 1)
//        printf("YES");
//    else
//        printf("NO");
    return 0;
}

int is_left_move1(char *arr1, char *arr2) {
    //判断两个字符串长度是否相同
    int len1 = strlen(arr1);
    int len2 = strlen(arr2);
    if(len1 != len2)
        return 0;
    //将主串复制两层strncat()函数   strncat(*destination,*src,size_t n);
    //注意:在destination==src时,即目标串与主串进行拼接时,不能用strcat(*destination,*src);
    strncat(arr1,arr1,6);
    //abcdefabcdef
    //  cdefab
    //找到相应首元素的相对位置
    char* ret = strstr(arr1,arr1);
    if(ret == NULL)
    {
        return 0;
    }
    else
        return 1;
}

int is_left_move(char *arr1, char *arr2) {
    int i = 0;
    int len = strlen(arr1);
    for (i = 0;i < len;i++)
    {
        //将源字符串进行左旋1个位置
        left_move(arr1, 1);
        //比较两个字符串,是否相同,相同返回0 不同:arr1 < arr2 返回值小于0
        int ret = strcmp(arr1, arr2);
        if (ret == 0)
            return 1;
    }
    return 0;
}
void left_move(char *arr, int n)
{
    assert(arr);//检查值是否有效
    int i = 0;
    int len = strlen(arr);
    for (i = 0;i < n;i++)
    {
        //将要替换i个值拿出来
        char tmp = *arr;
        //将这个值后变得值往前移
        int j = 0;
        for (j = 0;j < len-1;j++)//len-1最右边元素位置
        {
            //将后边元素向前移动n个位置
            *(arr + j) = *(arr + j + 1);
        }
        //将tmp移过去
        *(arr + len -1) = tmp;
    }
}

12.杨氏矩阵

#include 

int query(int arr[][3], int n, int* row, int* col,int* row_r);

//杨氏矩阵
//有一个数字矩阵,矩阵每行从左向右递增,矩阵从上到下递增,
//请编写程序在这样的矩阵中查找某个数字是否存在
//要求:时间复杂度小于O(n)
//答:先写逻辑,比如:123
//                456
//                789
//如上矩阵,我们假设要查找7这个数字
//根据题目条件,可以从右上角往左下角查
//3比7小,列--,行++  ===》第一行第三列
//5比7小,列--,行++  ===》第二行第二列
//7与7等,查到数值,返回行列  ===》第三行第三列
int main()
{
    int arr[][3] = {{1,2,3},{4,5,6},{7,8,9}};
    //行数计算
    int row = 0;
    int row_r = sizeof(arr) / sizeof(arr[0]);
    //列数计算
    int col = sizeof(arr[0]) / sizeof(arr[0][0]) - 1;
    int n = 0;
    //输入所要查找的数值
    scanf("%d",&n);
    //做查询(传参:数组,查值,数组行数地址,数组列数地址,行数地址)
    int ret = query(arr,n,&row,&col,&row_r);
    if(ret == 1)
    {
        printf("%d %d\n", row, col);
        printf("YES");
    }
    else
    {
        printf("NO");
    }
}

int query(int arr[][3], int n, int* row, int* col,int* row_r)
{
    //数组行数<行数,且列数>=0时,循环执行
    while (*row < *row_r&&*col >= 0){
        //当右上角数值小于n时,行++,列--
        if (arr[*row][*col] < n) {
            (*col)--;
            (*row)++;
        }
        //当被查元素在统一行时,列--
        else if (arr[*row][*col] > n) {
            (*col)--;
        }
        //查找到元素
        else if(arr[*row][*col] == n){
            return 1;
        }
            //没找到
        else{
            return 0;
        }
    }
}

你可能感兴趣的:(常见代码试题)