C语言:练习5

简介: C语言:练习5

题一:喝汽水

喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水,给20元,可以喝多少汽水(编程实现)。

#include <stdio.h>
int main()
{
  int mony = 0;
  int woter = 0;
  scanf("%d", &mony);
  woter = mony;
  int sum = mony;
  while (woter >= 2)
  {
    
    sum = sum + woter / 2;
    woter = (woter / 2) + woter % 2;
  }
  sum = 
  printf("%d\n", sum);
  return 0;
}

题二:调整奇偶位

调整奇数偶数顺序

调整数组使奇数全部都位于偶数前面。

输入一个整数数组,实现一个函数,

来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分,

所有偶数位于数组的后半部分。

#include <stdio.h>
int main()
{
  int arr1[10] = { 0,1,2,3,4,5,6,7,8,9 };
  int arr2[10] = { 0 };
  int i = 0;
  int j = 0;
  for (i = 0; i < 10; i++)
  {
    if (arr1[i] % 2 == 1)
    {
      arr2[j++] = arr1[i];
    }
  }
  for (i = 0; i < 10; i++)
  {
    if (arr1[i] % 2 == 0)
    {
      arr2[j++] = arr1[i];
    }
  }
  for (i = 0; i < 10; i++)
  {
    printf("%d ", arr2[i]);
  }
  return 0;
}

更好的思路:

/*
思路:
1. 给定两个下标left和right,left放在数组的起始位置,right放在数组中最后一个元素的位置
2. 循环进行一下操作
 a. 如果left和right表示的区间[left, right]有效,进行b,否则结束循环
 b. left从前往后找,找到一个偶数后停止
 c. right从后往前找,找到一个奇数后停止
 d. 如果left和right都找到了对应的数据,则交换,继续a,
*/
void swap_arr(int arr[], int sz)
{
  int left = 0;
  int right = sz-1;
  int tmp = 0;
  while(left<right)
  {
     // 从前往后,找到一个偶数,找到后停止
    while((left<right)&&(arr[left]%2==1))
    {
      left++;
    }
     
    // 从后往前找,找一个奇数,找到后停止
    while((left<right)&& (arr[right]%2==0))
    {
      right--;
    }
     
     // 如果偶数和奇数都找到,交换这两个数据的位置
     // 然后继续找,直到两个指针相遇
    if(left<right)
    {
      tmp = arr[left];
      arr[left] = arr[right];
      arr[right] = tmp;
    }
  }
}

题三:实现“X”图案

多组输入,一个整数(2~20),表示输出的行数,也表示组成“X”的反斜线和正斜线的长度。

针对每行输入,输出用“ * ”组成的X形图案。

#include <stdio.h>
int main()
{
  int n = 0;
  int i = 0;
  int j = 0;
  int a = 0;
  
  while (scanf("%d", &n) == 1)
  {
    a = n - 1;
    for (i = 0; i < n; i++)
    {
      for (j = 0; j < n; j++)
      {
        if (i == j)
        {
          printf("*");
        }
        else if (j + i == a)
        {
          printf("*");
        }
        else
        {
          printf(" ");
        }
      }
      printf("\n");
    }
  }
  
  return 0;
}

优解

#include <stdio.h>
int main()
{
  int i = 0;
  int j = 0;
  int n = 0;
  while (scanf("%d", &n) == 1)
  {
    for (i = 0; i < n; i++)
    {
      for (j = 0; j < n; j++)
      {
        if (i + j >= n - 1)
        {
          printf("* ");
        }
        else
        {
          printf(" ");
        }
      }
      printf("\n");
    }
    
  }
  return 0;
}

题四:预测排名

5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果:

A选手说:B第二,我第三;

B选手说:我第二,E第四;

C选手说:我第一,D第二;

D选手说:C最后,我第三;

E选手说:我第四,A第一;

比赛结束后,每位选手都说对了一半,请编程确定比赛的名次。

#include <stdio.h>
int main()
{
  int a = 0;
  int b = 0;
  int c = 0;
  int d = 0;
  int e = 0;
  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("%d %d %d %d %d\n", a, b, c, d, e);
              }
            }
          }
        }
      }
    }
  }
  return 0;
}

题五:查找凶手

日本某地发生了一件谋杀案,警察通过排查确定杀人凶手必为4个嫌疑犯的一个。

以下为4个嫌疑犯的供词:

A说:不是我。

B说:是C。

C说:是D。

D说:C在胡说

已知3个人说了真话,1个人说的是假话。

现在请根据这些信息,写一个程序来确定到底谁是凶手。

#include <stdio.h>
int main()
{
  char kiss = 0;
  for (kiss = 'a';kiss <= 'd'; kiss++)
  {
    if ((kiss != 'a') + (kiss == 'c') + (kiss == 'd') + (kiss != 'd') == 3)
    {
      printf("%c\n", kiss);
    }
  }
  return 0;
}

题六:打印杨辉三角

在屏幕上打印杨辉三角。

1

1 1

1 2 1

1 3 3 1

……

#include <stdio.h>
int main()
{
  int n = 0;
  scanf("%d", &n);
  int i = 0;
  int j = 0;
  int k = 0;
  int arr[50][50] = { 0 };
  for (i = 0; i < n; i++)
  {
    arr[i][0] = 1;
    arr[i][i] = 1;
  }
  for (i = 2; i < n; i++)
  {
    for (j = 1; j < i; j++)
    {
      arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
    }
  }
  for (i = 0; i < n; i++)
  {
    for (k = 0; k < n-i; k++)
    {
      printf(" ");
    }
    for (j = 0; j <= i; j++)
    {
      printf("%d ",arr[i][j]);
    }
    printf("\n");
  }
  return 0;
}

更好的思路:这种方法虽然降低了空间复杂度,但只能保存最后一行的数据,不利于反复查询,两个填法各有各的适用场景。就本题而言,改进后的胜出。

#include <stdio.h>
void yangHuiTriangle(int n)
{
  int data[30] = { 1 };
  int i, j;
  printf("1\n"); //第一行就直接打印了
  for (i = 1; i < n; i++) //从第二行开始
  {
    for (j = i; j > 0; j--) //从后向前填,避免上一行的数据在使用前就被覆盖
    {
      data[j] += data[j - 1]; //公式同上,由于变成了一维,公式也变简单了。
    }
    for (j = 0; j <= i; j++) //这一行填完就直接打印了。
    {
      printf("%d ", data[j]);
    }
    putchar('\n');
  }
}
int main()
{
  int n = 0;
  scanf("%d",&n);
  yangHuiTriangle(n);
  return 0;
}

题七:杨氏矩阵

杨氏矩阵

有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,

请编写程序在这样的矩阵中查找某个数字是否存在。

要求:时间复杂度小于O(N);

#include <stdio.h>
int main()
{
  int n = 0;
  scanf("%d", &n);
  int arr[3][3] = { 1,2,3,4,5,6,7,8,9, };
  int i = 0;
  int j = 0;
  for (i = 0;i < 3;i++)
  {
    if (n < arr[i][2])
    {
      for (j = 0; j < 3; j++)
      {
        if (arr[i][j] == n)
        {
          printf("%d %d", i, j);
        }
        
      }
    }
    else if (n == arr[i][2])
    {
      printf("%d 2",i);
    }
    else
    {
      printf("第%d行没有这个数!\n",i+1);
    }
    
  }
  return 0;
}

更优解:

我们仔细分析,不难发现,对于杨氏矩阵老说,右上角和左下角的元素是有特点的。右上角的元素是一行中最大的,一列中最小的。左下角的元素是一行中最小的,是一列中最大的。所以我们可以从右上角或者左下角开始查找。比如:从右上角开始查找的时候,右上角的元素比我们要查找元素小,我们就可以去掉右上角元素所在的这一行;右上角的元素比我们要查找的元素大,我们就可以去掉右上角元素所在的这一列。然后依然找右上角的元素继续和要查找的元素与比较。这样每一次比较去掉一行或者去掉一列。这个查找效率是高于遍历数组元素的,所以时间复杂度是小于O(N),也满足题目要求。

#include <stdio.h>
int findnum(int a[][3], int x, int y, int f) //第一个参数的类型需要调整
{
  int i = 0, j = y - 1; //从右上角开始遍历
  while (j >= 0 && i < x)
  {
    if (a[i][j] < f) //比我大就向下
    {
      i++;
    }
    else if (a[i][j] > f) //比我小就向左
    {
      j--;
    }
    else
    {
      return 1;
    }
  }
  return 0;
}
int main()
{
  int a[][3] = { {1, 3, 5},
          {3, 5, 7}, 
          {5, 7, 9} }; //一个示例
  if (findnum(a, 3, 3, 2))
  {
    printf("It has been found!\n");
  }
  else
  {
    printf("It hasn't been found!\n");
  }
  return 0;
}

题八:字符串左旋

字符串左旋

实现一个函数,可以左旋字符串中的k个字符。

ABCD左旋一个字符得到BCDA

ABCD左旋两个字符得到CDAB

#include <stdio.h>
#include <string.h>
void Left_Rotatiom(char* arr,int n)
{
  int i = 0;
  int sz = 0;
  sz = strlen(arr);
  n = n % sz;
  int j = 0;
  for (i = 0; i < n; i++)
  {
    char tmp = 0;
    tmp = *(arr);
    for (j = 0; j < sz-1; j++)
    {
      *(arr + j) = *(arr + j + 1);
    }
    *(arr + (sz - 1)) = tmp;
  }
}
int main()
{
  int n = 0;
  char arr[] = { "abcd"};
  scanf("%d", &n);
  Left_Rotatiom(arr,n);
  printf("%s\n",arr);
  return 0;
}

也可以:

void leftRound(char * src, int time)
{
  int len = strlen(src);
  int pos = time % len; //断开位置的下标
  char tmp[256] = { 0 }; //更准确的话可以选择malloc len + 1个字节的空间来做这个tmp
  
  strcpy(tmp, src + pos); //先将后面的全部拷过来
  strncat(tmp, src, pos); //然后将前面几个接上
  strcpy(src, tmp); //最后拷回去
}

题九:判断是不是旋转所得

写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串。

例如:给定s1 = AABCD和s2 = BCDAA,返回1

给定s1 = abcd和s2 = ACBD,返回0.

AABCD左旋一个字符得到ABCDA

AABCD左旋两个字符得到BCDAA

AABCD右旋一个字符得到DAABC

void * memmove ( void * destination, const void * source, size_t num );

char str[] = "memmove can be very useful......";
  memmove (str+20,str+15,11);

得到:memmove can be very very useful.

#include <stdio.h>
#include <string.h>
int Judge(char* s1, char* s2)
{
  int i = 0;
  int j = 0;
  int sz = 0;
  sz = strlen(s1);
  for (i = 0;i < sz;i++)
  {
    if (*(s1 + i) == *(s2))
    {
      int count = 0;
      for (j = 0; j < (sz / 2); j++)
      {
        if (*(s1 + i + j) == *(s2 + j))
        {
          count++;
        }
        else
        {
          break;
        }
      }
      if (count == sz / 2)
      {
        return 1;
      }
    }
  }
  return 0;
}
int main()
{
  char s1[50] = { "abccde" };
  char s2[] = { "cdeabc" };
  int num = 0;
  int len = strlen(s1);
  memmove(s1 + len, s1, len);
  num = Judge(s1, s2);
  if (num == 1)
  {
    printf("是旋转所得!\n");
  }
  else
  {
    printf("不是旋转所得!\n");
  }
  return 0;
}

更优解:

所以做法很简单,只需要将原字符串再来一遍接在后面,然后找一找待查找的字符串是不是两倍原字符串的子集即可。

int findRound(const char * src, char * find)
{
  char tmp[256] = { 0 }; //用一个辅助空间将原字符串做成两倍原字符串
  strcpy(tmp, src); //先拷贝一遍
  strcat(tmp, src); //再连接一遍
  return strstr(tmp, find) != NULL; //看看找不找得到
}

做错的选择题:

C程序常见的错误分类不包含:( )

A.编译错误

B.链接错误

C.栈溢出

D.运行时错误

栈溢出是运行时错误的一种,因此C程序为将栈溢出单独列出,栈溢出包含在运行时错误中。

下面哪个代码是错误的?( )

#include <stdio.h>
int main()
{
  int *p = NULL;
  int arr[10] = {0};
  return 0;
}

A.p = arr;

B.int (*ptr)[10] = &arr;

C.p = &arr[0];

D.p = &arr;

就数据类型来看,A左右两边都是int *,

B左右两边都是 int (*)[10],

C左右两边都是int *,

D左边是 int *,右边是 int (*)[10],故选D。

经典题目

VS开发环境调试下面的代码,画图解释下面代码的问题

#include <stdio.h>
int main()
{
    int i = 0;
    int arr[] = {1,2,3,4,5,6,7,8,9,10};
    for(i=0; i<=12; i++)
    {
        arr[i] = 0;
        printf("hello bit\n");
    }
    return 0;
}
答案解析:
以下代码有两个问题:1. 数组访问越界   2. 死循环
 以下代码再vs2013下会造成死循环,原因:
 栈内存:
         |CC  CC  CC  CC|
         arr[0]|01  00  00  00|\
         arr[1]|02  00  00  00| \
         arr[2]|03  00  00  00|  \
         arr[3]|04  00  00  00|   \
         arr[4]|05  00  00  00|    \
         arr[5]|06  00  00  00|    /  arr的空间
         arr[6]|07  00  00  00|   /
         arr[7]|08  00  00  00|  /
         arr[8]|09  00  00  00| /
         arr[9]|0A  00  00  00|/
               |CC  CC  CC  CC|
               |CC  CC  CC  CC|
               |00  00  00  00| i的空间
               |CC  CC  CC  CC|
for循环中,i的内容是从0,一直增加到12,而数组只有10个空间,因此会越界
每次访问arr数组i号位置时,都会将该位置内容设置为0,当访问到arr[12]时,也会将该位置内容设置为0,而位     置恰好为i的位置,即a[12]恰巧将i设置为0,因此造成死循环。

程序的执行结果为( )

int main()
{
  unsigned char a = 200;
  unsigned char b = 100;
  unsigned char c = 0;
  c = a + b;
  printf(“%d %d”, a+b,c);
  return 0;
}

说明:printf在传入参数的时候如果是整形会默认传入四字节,所以a+b的结果是用一个四字节的整数接收的,不会越界。而c已经在c = a + b这一步中丢弃了最高位的1,所以只能是300-256得到的44了。

※由于printf是可变参数的函数,所以后面参数的类型是未知的,所以甭管你传入的是什么类型,printf只会根据类型的不同将用两种不同的长度存储。其中8字节的只有long long、float和double(注意float会处理成double再传入),其他类型都是4字节。所以虽然a + b的类型是char,实际接收时还是用一个四字节整数接收的。另外,读取时,%lld、%llx等整型方式和%f、%lf等浮点型方式读8字节,其他读4字节。

下面代码的结果是( )

int main()
{
  char a[1000] = {0};
  int i=0;
  for(i=0; i<1000; i++)
  {
    a[i] = -1-i;
  }
  printf("%d",strlen(a));
  return 0;
}

a是字符型数组,strlen找的是第一次出现尾零(即值为0)的位置。考虑到a[i]其实是字符型,如果要为0,则需要-1-i的低八位要是全0,也就是问题简化成了“寻找当-1-i的结果第一次出现低八位全部为0的情况时,i的值”(因为字符数组下标为i时第一次出现了尾零,则字符串长度就是i)。只看低八位的话,此时-1相当于255,所以i==255的时候,-1-i(255-255)的低八位全部都是0,也就是当i为255的时候,a[i]第一次为0,所以a[i]的长度就是255了,故选C。

下面代码的执行结果是( )

#include <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 and str2 are same\n");
  else
    printf("str1 and str2 are not same\n");
  if(str3 == str4)
    printf("str3 and str4 are same\n");
  else
    printf("str3 and str4 are not same\n");
  return 0; 
}

str1和str2是两个数组,数组的操作方式是将右边常量字符串的内容拷贝进来,所以他们是两个空间,只是内容相同,所以str1 != str2。而str3和str4是两个指针,编译器在处理的时候,会将相同的常量字符串做成同一个地址,所以,str3和str4指向的是同一个常量字符串,所以str3 == str4,故选C。

设有以下函数void fun(int n,char *s){……},则下面对函数指针的定义和赋值均是正确的是:( )

作业内容

A.void (*pf)(int,char); pf=&fun;

B.void (*pf)(int n,char *s); pf=fun;

C.void *pf(); *pf=fun;

D.void *pf(); pf=fun;

CD前半句压根就不是定义而是声明,A选项参数列表的第二个参数错了。应为char *,B选项正确。需要说明的是,对于函数名来说,前面的&和*都会被忽略,所以fun前面加不加取地址都没区别。只有定义出的函数指针变量(如题面中的pf)加上&后才会变成二级函数指针。

目录
相关文章
|
8月前
|
C语言 数据安全/隐私保护
C语言初阶②(分支语句和循环语句)编程练习
C语言初阶②(分支语句和循环语句)编程练习
66 1
|
8月前
|
算法 C语言 容器
从C语言到C++_18(stack和queue的常用函数+相关练习)力扣(上)
从C语言到C++_18(stack和queue的常用函数+相关练习)力扣
52 0
|
8月前
|
C语言
C语言指针——练习
C语言指针——练习
|
8月前
|
编译器 C语言
C语言进阶⑪(指针上)(知识点和对应练习)回调函数模拟实现qsort。(下)
C语言进阶⑪(指针上)(知识点和对应练习)回调函数模拟实现qsort。
63 0
|
7月前
|
C语言
C语言练习代码第一篇
C语言练习代码第一篇
|
8月前
|
编译器 C语言 C++
从C语言到C++⑥(第二章_类和对象_中篇_续)大练习(日期类)+笔试选择题(下)
从C语言到C++⑥(第二章_类和对象_中篇_续)大练习(日期类)+笔试选择题
62 2
从C语言到C++⑥(第二章_类和对象_中篇_续)大练习(日期类)+笔试选择题(下)
|
8月前
|
存储 前端开发 算法
从C语言到C++_18(stack和queue的常用函数+相关练习)力扣(下)
从C语言到C++_18(stack和queue的常用函数+相关练习)力扣
27 0
|
7月前
|
C语言
|
8月前
|
算法 编译器 C语言
从C语言到C++⑥(第二章_类和对象_中篇_续)大练习(日期类)+笔试选择题(上)
从C语言到C++⑥(第二章_类和对象_中篇_续)大练习(日期类)+笔试选择题
53 3
|
7月前
|
编译器 C语言