2022 年1月1日 课堂总结

本文探讨了C++中字符数组、常量指针与栈内存的管理,介绍了左移符的用法,重点讲解了`push_back`在vector和string中的应用,以及`assert`函数在错误检测中的角色。通过实例解析了如何使用`assert`进行参数验证和空指针检查。
摘要由CSDN通过智能技术生成

一 .  函 数

1 . c h a r

char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char *str5 = "abc";
const char *str6 = "abc";
char *str7 = "abc";
char *str8 = "abc";
cout << (str1 == str2) << endl; 
cout << (str3 == str4) << endl;
cout << (str5 == str6) << endl;
cout << (str7 == str8) << endl;

char str1[] = "abc":

      这里的"abc"是一个常量,首先会在常量存储区里存储"abc"这个常量,然后会因为"abc"被赋值给str1[],所以在栈中开辟一段内存,内存大小为4个节点(char数组后会自动加一个'\0'),然后又有一个"abc"被保存在栈中。 同理,str2[]中的"abc"也是保存在栈中,地址不同。到此,有三个"abc"被保存起来,一个在常量存储区,另外两个在栈中。此外,插一句,c++内存被分为5个区,分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。

const char str3[] = "abc":

      对于这种被const修饰起来的变量,一般也是被保存在常量存储区,但是,但是对于const数组来讲,系统不确定符号表是否有足够的空间来存放const数组,所以还是为const数组分配内存的。所以str3指向的是栈上的"abc"。同理,str4[]也是保存在栈中,地址不同。

const char *str5 = "abc":

      因为"abc"在常量存储区中保存有一份(即使没保存,这样的操作也会新建一份),这里str5定义的时候,嘿,我见过这个,str5就可以开心的直接指向"abc"所在的常量区的地址。

      同理str6,str7,str8。与const没有半毛钱关系,const只是使得str5和str6无法指向新的字符串常量(也就是新的地址)。


2 . 左 移 符 “<<”


  3 . p u s h _ b a c k 的 用 法

C++中vector头文件中有push_back这一函数,作用是在vector尾部加入一个数据。string中也有这个函数,作用是在字符串结尾插入一个字符。

#include <bits/stdc++.h>

using  namespace  std;

int  main(){

    vector<int> vi;

    vi.push_back(1);

    cout << vi.back() << endl;

    vi.push_back(2);

    cout << vi.back() << endl;

    return  0;

}

4 . a s s e r t 函 数

assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。

请看下面的程序清单badptr.c:

#include <stdio.h>

#include <assert.h>

#include <stdlib.h>

int main( void )

{

    FILE *fp;

    fp = fopen( "test.txt", "w" );//以可写的方式打开一个文件,如果不存在就创建一个同名文件

    assert( fp );              //所以这里不会出错

    fclose( fp );

    fp = fopen( "noexitfile.txt", "r" );//以只读的方式打开一个文件,如果不存在就打开文件失败

    assert( fp );              //所以这里出错

    fclose( fp );              //程序永远都执行不到这里来

    return 0;

}



[root@localhost error_process]# gcc badptr.c

[root@localhost error_process]# ./a.out

a.out: badptr.c:14: main: Assertion `fp' failed.

  使用assert()的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。在调试结束后,可以通过在包含#include <assert.h>的语句之前插入 #define NDEBUG 来禁用assert调用,

示例代码如下:

#include <stdio.h>

#define NDEBUG

#include <assert.h>

用法总结与注意事项:

  1)在函数开始处检验传入参数的合法性如

int resetBufferSize(int nNewSize)

{

  //功能:改变缓冲区大小,

  //参数:nNewSize 缓冲区新长度

  //返回值:缓冲区当前长度 

  //说明:保持原信息内容不变   nNewSize<=0表示清除缓冲区

  assert(nNewSize >= 0);

  assert(nNewSize <= MAX_BUFFER_SIZE);

  ...

}

  2)每个assert只检验一个条件,因为同时检验多个条件时,如果断言失败,无法直观的判断是哪个条件失败,如:

  不好:

assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize);

  好

assert(nOffset >= 0);

assert(nOffset+nSize <= m_nInfomationSize);

  3)不能使用改变环境的语句,因为assert只在DEBUG个生效,如果这么做,会使用程序在真正运行时遇到问题,如:

  错误:

assert(i++ < 100);

  这是因为如果出错,比如在执行之前i=100,那么这条语句就不会执行,那么i++这条命令就没有执行。

  正确

assert(i < 100);

i++;

  4)assert和后面的语句应空一行,以形成逻辑和视觉上的一致感。

  5)有的地方,assert不能代替条件过滤。

以下是使用断言的几个原则:   

  (1)使用断言捕捉不应该发生的非法情况。不要混淆非法情况与错误情况之间的区别,后者是必然存在的并且是一定要作出处理的。   

  (2)使用断言对函数的参数进行确认。   

  (3)在编写函数时,要进行反复的考查,并且自问:“我打算做哪些假定?”一旦确定了的假定,就要使用断言对假定进行检查。   

  (4)一般教科书都鼓励程序员们进行防错性的程序设计,但要记住这种编程风格会隐瞒错误。当进行防错性编程时,如果“不可能发生”的事情的确发生了,则要使用断言进行报警。  

  ASSERT ()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式,如果表达式为FALSE (0), 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。这个宏通常原来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。 

ASSERT只有在Debug版本中才有效,如果编译为Release版本则被忽略。 

比较好的在程序中使用assert的地方:

(1)空指针检查。例如,针对一个函数的参数进行空指针检查。你可以这样使用:assert (pointer != NULL);,产生的错误会像这样:Assertion ‘pointer != ((void *)0)' failed。这样,当出现空指针时,你的程序就会退出,并很好的给出错误信息。

(2)检查函数参数的值。例如,如果一个函数只能在它的一个参数foo为正值的时候被调用,你可以在函数开始时这样写:assert (foo > 0);,这将帮助你检测函数的错误使用,这也给源代码阅读者很清晰的印象,那就是在这里对函数的参数值有限制。

二 . 题 目

1 . 1 8 B

Problem - 81B - Codeforces

思路:

         首先先删除所有的空格

         然后在合适的位置添加

 代码:

        

//81-B
#include<bits/stdc++.h>
using namespace std;
#define y1 fndjifhwdn
#define y2 vfsdkofsjd
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
typedef long long 11;
typedef long double ld;
typedef pair<int,int>pi;
int n,tk,ff;
int main()
{
	#ifdef home
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    #endif
    gets(s);
    n=strlen(s);
    int tk=0;
    for(int i=0;i<n;i++)
    {
    	if(s[i]==' ')
    	{
    		continue;
		}
		if(s[i]==',')
		{
			if(tk>0 && a[tk-1]!=" ")
			{
				a[tk++]=" ";
			}
			a[tk]="...";
			tk++;
			i+=2;
			continue
		}
		ff=i;
		while(s[ff]>='0'&&s[ff]<='9')
		{
			ff++;
		}
		if(ff>i)
		{
			if(tk>0&&a[tk-1][0]>=0&&a[tk-1][0]<='9')
			{
				a[tk++]=' ';
			}
			for(int j=i;j<ff;j++)
			{
				a[tk]+=s[j];
				tk++;
				i=ff-1;
				continue;
			}
			a[tk++]=s[i];
			a[tk++]=" ";
		}
	}
		if(tk>0&&a[tk-1]==" ")tk--;
		for(int i=0;i<tk;i++)
			cout<<a[i];
		cout<<endl;
	return 0;
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值