• C及C++每日练习(2)


    1.选择:

    1.使用printf函数打印一个double类型的数据,要求:输出为10进制,输出左对齐30个字符,4位精度。以下哪个选项是正确的?

    A.%-30.4e  B.%4.30e  C.%-30.4f  D.%-4.30

           在上一篇文章中,提到了对于打印字符串时,其打印模板%m.ns中各个字母的含义,对于m,表示输出的字符串的宽度,对于n表示在打印时,打印左起字符串的前n个字符。并且是右对齐,且字符不足时会自动补充空格。当字符串长度>n>m时,m失效,当n>字符串长度时,直接打印到结尾。

          对于本题,则是考察对于数字的打印格式。对于打印十进制的double,采用的格式是%m.nf

    对于题目中的%m.ne,是表示按照指数类型打印。

        对于对齐问题,主要由m控制,表示右对齐打印m个字符。但是题目中要求左对齐,因此需要采用-m的形式。对于n,主要用于控制打印精度,即表示打印到小数点的后n位。

       因此,对于本体题目要求,对应答案C

    2.请找出下面程序中有哪些错误()

    1. int main(){
    2. int i = 10;
    3. int j = 1;
    4. const int *p1;//(1)
    5. int const *p2 = &i; //(2)
    6. p2 = &j;//(3)
    7. int *const p3 = &i;//(4)
    8. *p3 = 20;//(5)
    9. *p2 = 30;//(6)
    10. p3 = &j;//(7)
    11. return 0;
    12. }

     A.1,2,3,4,5,6,7

    B. 1,3,5,6

    C.6,7

    D.3,5

    在正式讲解题目之前,首先需要介绍两个概念,即:指针常量、常量指针

    对于常量指针:表示指针指向的内容是常量内容,因此,指针指向的内容不能被修改,也就是说,不能通过解引用的方式来改变指针指向的内容,但是,可以改变指针本身的指向。

    对于指针常量:表示指针本身就是一个常量,指针的指向不能发生更改,但是可以通过解引用的方式改变空间中内容。

    而对于如何区分指针常量和常量指针,可以通过const*的相对位置来判断。

    例如,对于题目中的(1)const\, \, \, int *p1;因为const*前面,所以表示常量指针,即:p1指向的内容不能通过解引用进行修改,但是p1的指向可以修改。

    对于题目中的(2)int \, \, \, const *p2 =&i表示常量指针,与(1)不同的是,此处进行了对于指针的初始化。

    对于题目中的(3),表示改变指针p2的指向,由于p2是常量指针,故正确。

    对于题目中的(4),此时*const前面,表示指针常量,即指针是一个常量,指针的指向不能被更改,但是指向的内容可以修改。

    对于题目中的(5),表示对指针p3解引用,更改指针指向的内容,由于p3是一个指针常量,因此,可以更改指针指向的内容。正确。

    对于题目中的(6),表示对指针p2解引用,修改指向的内容,由于指针式常量指针,即指针指向的内容是常量,可以修改指针的指向,但是不能更改指针指向的内容,因此错误。

    对于题目中的(7),表示更改p3的指向,由于指针p3是指针常量,因此,指针指向不能被改变,所以错误。

    因此答案选择C

    3.下面叙述错误的是()

    1. char acX[]="abc";
    2. char acY[]={'a','b','c'};
    3. char *szX="abc";
    4. char *szY="abc";

    A.acX与acY的内容可以修改

    B. szX与szY指向同一个地址

    C.acX占用的内存空间比acY占用的大

    D. szX的内容修改后,szY的内容也会被更改

            对于代码的前两行,都是创建一个常量字符串,只不过采取的放肆不同,不过需要注意,在第一行代码中,由于是一个完整的字符串,因此,在字符串的末尾带有字符串的结束标志" role="presentation" style="position: relative;">\0。但是第二行代码中,并不存在这个结束标志,因此,对于C选项,acX的大小大于acY的大小。

           对于A选项,可以通过数组下标进行更改,正确。

           对于B选项,由于两个指针指向的内容相同,因此正确。

           对于D选项,需要注意,题目说的是改变指针szX的内容,也就是修改指针指向的地址,并不是修改其指向的内容。所以错误。

    因此选择D

    4.在头文件及上下文均正常的情况下,下列代码的运行结果是()

    1. int a[] = {1, 2, 3, 4};
    2. int *b = a;
    3. *b += 2;
    4. *(b + 2) = 2;
    5. b++;
    6. printf("%d,%d\n", *b, *(b + 2));

    A.1,3

    B. 1,2

    C.2,4

    D.3,2

    对于上述代码,首秀按创建了一个指针b,指向了数组a的起始地址。随后,对于*b += 2;,需要注意,由于*的结合优先级高于+=,因此,这句代码表示的含义是,解引用,拿到数组中第一个数,随后对这个数+2,因此,此时的数组为:

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

    对于*(b + 2) = 2;,则是表示针对指针的地址进行加2,由于指针的类型为int,因此表示跳过8字节,对跳过后的地址进行解引用,再将这个值修改为2。因此,此时的数组为:

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

    对于b++,表示修改指针b,使得其指向数组中的第二个元素的地址。

    因此,再打印时,指针b指向数组中第二个元素的下标,此时进行打印,打印的值分别为2,4,答案选择C

    5. 用变量a给出下面的定义:一个有10个指针的数组,该指针指向一个函数,该函数有一个整形参数并返回一个整型数()

    A. int *a[10];

    B. int (*a)[10];

    C. int (*a)(int);

    D. int (*a[10])(int);

    本题目涉及到了三个概念:数组指针,指针数组,函数指针,对于数组指针。对于前二者的判断,只需要知道[]的结合优先级大于*即可。

    例如对于选项A,由于结合性问题,因此a首先表示一个数组,数组的容量为10,其中保存了10int*类型的变量,因此表示指针数组。

    对于选项Ba首先表示一个指针,这个指针指向了一个数组,数组可以存储10int类型的变量,因此是数组指针。

    对于选项Ca表示一个指针,外部的括号()是函数指针的标志,因此表示一个函数,参数为一个整型参数。返回值类型为int

    对于选项Da首先表示一个数组,这个数组存储的变量为指针,且指针为函数指针,返回值为整型,参数为一个整型参数,所以答案选择D

    6.在32位cpu上选择缺省对齐的情况下,有如下结构体定义:

    1. struct A
    2. {
    3. unsigned a : 19;
    4. unsigned b : 11;
    5. unsigned c : 4; unsigned d : 29;
    6. char index;
    7. };

    则sizeof(struct A)的值为()

    A.9 B. 12 C.16 D.20

         需要注意,此时的变量是以位断的形式定义的,冒号后面的数组表示这个变量占有多少比特位。

         对于一个unsigned类型的变量,大小为4字节,因此会开辟4字节,即32比特位大小的空间,由于a,b占有的比特位小于32,因此对于二者只会开辟一次4字节大小的空间。

         对于c,由于此时第一次开辟的空间大小不足,因此会在开辟4字节大小的空间。对于d,由于此时的空间再次不足,因此会第三次开辟4字节空间。

       对于index,由于类型不同,因此会再开辟1字节的空间。

       最后,因为存在内存对齐机制,因此总空间大小必须是最大对齐数的整数倍,因此答案选择C

    7.下面代码会输出()

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

    A.4 B. 1 C.2 D.3

    对于数组名,如果于sizeof,&结合,则表示整个数组,其他情况下均表示数组首元素地址。因此,此处的&a+1,表示跳过整个数组长度的内容。即数组最后一个内容的下一个位置。对于ptr-1,由于指针的类型int,因此为指向前四个字节的内容,也就是指向数组的最后一个元素的地址。,因此选择A

    2. 编程:

    2.1 倒置字符串:

    倒置字符串_牛客题霸_牛客网 (nowcoder.com)

           原理较为简单,首先将给定的字符串整体进行逆置,例如对于图中给出的字符串,整体逆置后如下:

                                                          .gnijieb \, \, ekil\, \, I

          对于本题,可采用双指针法进行解决。具体解法如下:

       

         创建两个指针,分别为start,end,在最开始,两个指针均指向字符串的开头。这里由于使用string类创建一个对象s用于存放字符串,因此:start=s.start()=end

         建立循环,循环的条件是start<s.end()

        如果end的位置不指向字符串的结束位置,即:最后一个字符的下一个位置。并且对于*end !=' \, \, ',即不等于空,则让end指向下一个位置。

        如果*end ==' \, \, ',则将start,end两个指针区域内的字符串再次逆置。在逆置后,这里有两种情况,一是end <s.end(),则令start=end+1,再令end = start即可。如果end == s.end(),则表示,已经将整个字符串遍历结束,直接令start =end即可。此时start==s.end(),循环结束,输出字符串即可。对应代码如下:

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. int main()
    6. {
    7. string s1;
    8. getline(cin,s1);
    9. reverse(s1.begin(),s1.end());
    10. auto start = s1.begin();
    11. while(start != s1.end())
    12. {
    13. auto end = start;
    14. while(*end != ' ' && end != s1.end())
    15. {
    16. end++;
    17. }
    18. reverse(start,end);
    19. if(end != s1.end())
    20. {
    21. start = end+1;
    22. }
    23. else {
    24. start = end;
    25. }
    26. }
    27. cout << s1;
    28. return 0;
    29. }

    2.2 排序子序列:


    排序子序列_牛客笔试题_牛客网 (nowcoder.com)

    在给出题解之前,首先解释以下题目中提出的两个概念,即:非递增序列,非递减序列。

    对于非递增序列,可以看作不严格的递增序列,即存在前后相等元素的递增序列,例如:

                                                        1\, \, \, 2\, \, \, 2\, \, \, 3\, \, \, 3\, \, \, 4

    对于非递减序列,可以看作不严格的递减序列,即存在前后相等元素的递减序列,例如:
                                                        5\, \, \, 4\, \, \, 4\, \, \, 3\, \, \, \, 2\, \, \, 2\, \, \, 1\,

          对于本题目的解法,首先利用vector实例化出对象v来接收输入元素,利用变量n接收输入元素数量:

         如果v[i] <v[i+1],则表示数组进入了非递增序列。

         如果v[i] >v[i+1],则表示数组进入了非递减序列

        对于v[i]==v[i+1]的情况,指向下一个元素即可。不做处理

         如果数组进入了上述序列,需要继续判断,如果出现了相反的情况,例如在非递增序列中,出现了v[i] > v[i+1],则表示这部分的数据不再满足非递增性,此时前面的数据构成了一个完成的非递增序列,因此让记录排序子序列数量的变量count++,再令i++,作为另一种序列的首个元素。如果没有出现相反的情况,则表示目前数据依旧满足非递增行,需要检测下一个数据,再令i++即可。

        不过对于条件的判断需要注意,对于下面的情况:1 \, \, \, 2\, \, \, 3\, \, \, 4,因为上面给出的序列是一个递增序列,因此当i==2时,此时v[i]==3,v[i+1]==4,然后令i++,此时i==3,对于v[i+1]会造成越界访问的问题。为了方便的解决这个问题,可以在实例化出对象v后,利用resize函数,扩容N+1数量的空间,并且将这些空间初始化为0。具体代码如下:
     

    1. #include
    2. #include
    3. using namespace std;
    4. int main() {
    5. int n = 0;
    6. cin >> n;
    7. vector<int> v;
    8. v.resize(n+1,0);
    9. for( int i = 0; i < n; i++)
    10. {
    11. cin >> v[i];
    12. }
    13. int count = 0;
    14. int i = 0;
    15. while( i < n)
    16. {
    17. //进入非递减
    18. if( v[i] < v[i+1])
    19. {
    20. while( i < n && v[i] <= v[i+1])
    21. {
    22. i++;
    23. }
    24. count++;
    25. i++;
    26. }
    27. else if( v[i] == v[i+1])
    28. {
    29. i++;
    30. }
    31. else
    32. {
    33. while( i < n && v[i] >= v[i+1])
    34. {
    35. i++;
    36. }
    37. count++;
    38. i++;
    39. }
    40. }
    41. cout << count;
    42. return 0;
    43. }

  • 相关阅读:
    人工智能,现在模型已够?只需应用?
    Oracle-opatchauto自动安装补丁失败导致RAC集群异常问题
    仿真3. 仿真系统的设计思路
    《动手学深度学习 Pytorch版》 10.7 Transformer
    《linux程序设计》第二章笔记
    金蝶云星空套打设计平台导出套打模板和导入套打模板
    LeetCode每日一题——895. 最大频率栈
    【面试八股总结】C++内存管理:内存分区、内存泄漏、new和delete、malloc和free
    ASP NET Core Razor页面教程的笔记
    【计算机网络】运输层:糊涂窗口综合征即解决方法
  • 原文地址:https://blog.csdn.net/2301_76836325/article/details/136465332