C/C++:对任意长字符中的整数求和

 题目:(来自于鱼C-小甲鱼的C++快速入门课)C/C++:对任意长字符中的整数求和_第1张图片

C语言:

1.简单使用getchar()实现

#include 
//题目:用户输入任意长字符,回车停止输入,求和。 

int main()
{
	char c1;
	int sum = 0, num = 0; 
	while((c1 = getchar()) != '\n')
	{
		if(c1 != ' ')
		{
			num = num * 10 + c1 - '0';//因为数字被转成字符型了,1的ASCII码是49 
		}else if(c1 == ' ')
		{
			sum += num;
			num = 0;
		}
	}
	printf("结果为:%d",sum+num);
	//因为如果最后一个输入的不是空格,那么最后一个数字将为被加进sum中
	//但如果是空格的话,也没关系,因为在else if条件语句里已经被加进sum里且num被初始化为0了,也不会对结果产生影响 
}

        2.本来想用strtok()和动态数组实现,但是发现行不通呀。↓所以是错误做法(但还是贴贴

#include 
#include 
#include 

char * getStr();

int main()
{
	char *str = getStr();
	const char delim[] = " ";
	char *token = NULL;
	int sum = 0;
	token = strtok(str,delim);
	while(!token)
	{
		printf("%s ",token);
		token = strtok(NULL,delim);
        //参数为NULL,表示函数继续以上次调用所保存的this指针的位置开始分解
	}
    return 0;
}

char * getStr()
{
	char c; 
	int n = 0, k = 100;//字符串当前长度为0,空间长度为100 
	char *str = (char *)malloc(100),*temp = NULL;
	if(!str)//malloc之后要立即判断是否申请内存失效 
	{
		printf("malloc fail\n");
		exit(-1);//退出程序 
	}
	while((c = getchar()) != '\n')
	{
		if(k <= n)
		{
			k*=2;
			temp = (char *)realloc(str,k);
			if(!temp)
			{
				printf("realloc fail!\n");
				free(str);
				exit(-1);
			}else{
				str = temp;//因为要控制s1[n++]=c,所以写多一条赋值 
			}
		}
		str[n++] = c;
	}
	str[n] = '\0';// \0是字符串结束符
	return str; 
}

原因:

1.strtok()的第一个参数不能是字符串常量,程序会因为strtok函数试图修改源字符串的值,而抛出异常。

像  char *test="a,b";  就是字符串字面量,一般存储在常量区内。相同的字符串字面量其实在常量区里只存一个,有相同的地址。

比如

char *a = "abc";  char *b = "abc";  其指向的地址相同,且常量区的内容不能改变。

而 char a[] = "a,b"; 实际上是定义一个字符数组,并用字符串字面量来初始化。两者有本质的不同

而动态数组是靠指针实现的,而在C里不定长应该只能靠动态数组实现(也许),因此当自定义的getStr()返回指针时,是没办法作为第一个参数实现strtok()的。然后于是又在思考如何将这个动态数组赋值给一个新的静态数组,但是好像没法弄(?静态数组之间倒是可以用memcpy()直接赋值。【好像也可以干脆写个结构体,内含动态数组和length记录数组长度,就可以直接整个大小为length的静态数组然后一一赋值————但是对于这道题来讲,做法就有点太麻烦了有空再写

(希望以后能对内存这块有更多了解!!看看能不能再具体改进!!

另:strtok()对原字符串的修改以及关于函数的返回也很有意思。详情可看参考链接1。

标答:

#include 
#include 

int main()
{
	int i = 0;
	int sum = 0;
	char ch;
	printf("请输入一串整数和任意数目的空格:");
	while(scanf("%d",&i) == 1)
	{
		sum += i;
		while((ch=getchar()) == ' ')//屏蔽空格
			;
		if(ch == '\n')
		{
			break;
		} 
		ungetc(ch,stdin);//将ch中存储的字符退回到stdin输入流中
	}
	printf("结果是:%d",sum);
	return 0;

}

 注:这一句ungetc(ch,stdin);的意义在于,在内嵌的while语句里已经用了getchar()提取了一个字符并赋值给了ch。假设没有这一行代码,如果当输入序列为:22      34,首先22会被加进sum里,而后屏蔽掉之间的空格,直到读取到随后的第一个数字3,此时ch为3,跳出while循环,它当然也不是回车,于是跳回到外层while语句里,第一个3就被丢失了。这时scanf得到的i会变成4。

参考资料与部分转载:

关于函数strtok和strtok_r的使用要点和实现原理 - 周人假的 - 博客园

strtok用指针当入参会出段错误的问题? - 知乎


C++:

法一:不太ok的做法

#include 
using namespace std;
int main()
{
    int i,sum = 0;
    cout << "输入一串整数和任意数目的空格:";
    while(cin >> i)
    {
        sum += i;
        cout << sum << endl;
        //没必要写下面那段,因为cin也读不到空格
        // if(cin.peek() == ' ')
        // {
        //     cin.get();
        // }
		if(cin.peek() == '\n')
        {
            break;
        }
    }
    cout << "结果是:" << sum << endl;
    return 0;
}

1. cin 是C++的标准输入流对象,istream类的对象,用于读取标准输入的对象。cout是ostream类的对象。在键盘输入字符的过程中,这些字符会放在键盘缓冲区(shell缓冲区)里,当我们敲下回车时,键盘输入的数据才会放在标准输入缓冲区里,且回车键也会作为换行符存储到缓冲区并作为一个字符来计算。cin读取数据也是从缓冲区获取数据,当缓冲区为空时,cin的成员函数会阻塞等待数据的到来,一旦缓冲区中有数据,就触发cin的成员函数去读取数据。

>> 最初定义的是右移,当但是出现在 cin >>中的时候这个符号被重载了,变成了一个流操作,在用户通过键盘输入信息的时候,所有内容都会存储在输入缓冲区,cin >> 就会直接从输入缓冲区中直接读取按照你所提供的要求的类型的数据。

2. .peek():取得输入流中的第一个字符进行其他操作如比较,但是不影响输入流中的数据。相当于【看】,和它的单词本义【窥探】类似。

3. .get():从输入流中读取一个字符,输入流的数据会被取走。

这个程序还有一点要注意的就是,如果输入序列是以多个空格+回车结尾,将会卡死在while的条件语句里。因为cin是默认跳过空格的,空格只会终止cin的读入操作,终止后又进行while判断(即判断输入流是否有效)而如果是文件输入,它会自动读到文件尾。ctrl+z是文件尾的标识。

法二:

#include 
#include 

using namespace std;

int main()
{
	string line;
	int sum = 0,num = 0;
	getline(cin, line);
	cout << line.length() << endl; 
	for(int i = 0; i < line.length(); i++)
	{
		if(line[i] != ' ')
		{
			num = num*10 + line[i] - '0'; //记得减'0'呀!!
		}
		if(line[i] == ' ')
		{
			sum += num;
			num = 0;
		}
	}
	cout << "The sum is " << sum + num << endl; 
    //务必记得加上num 不然以数字结尾的串的最后一个数字将无法加进最终结果

	return 0;
}

注:

1.length()函数求出的字符串长度不包含字符串末尾结束符’\0’;

size()、length()是string类的方法,只有string类的对象才可以用该方法,字符串数组不可用,而strlen、strcpy等源于C语言的字符串处理函数库,需要include,同时也只有字符串数组才可以用。而且与strlen()不同的是,size()和length()是调用,例如:s.size()、s1.length()

2.stringstream()可以实现数据类型间的转换,但是如果字符串转数字的话就按以上操作即可,友人提醒说比用函数还快。而且使用stringstream()要记得清空,否则重复使用的话会得到意料之外的结果。而且clear()仅仅清空标志位,并没有释放内存,因此还要用到stringstream.str("")来清空stringstream。


另:第一次用vscode来写c++。中途也碰到了很多问题。例如环境的配置,调试时vscode 出现Unable to start debugging.Program path is missing or invalid.(原因:文件路径中出现中文),还有出现中文乱码(原因:vscode中新建的的.cpp文件默认是UTF-8的编码,于是调试时会弹出系统cmd终端来运行.exe文件,而cmd终端默认是GBK编码。因此要更改文件编码。),运行后没输出(于是俺下了个coderunner又支棱了

配置环境时的资料参考:

用VScode写C++运行之后没有输出该怎么办? - 知乎

【vscode调试配置、输出中文乱码解决】关于VSCode的C++原生断点调试debug和运行的配置和中文乱码的问题(非code runnner)_MYMarcoreus的博客-CSDN博客

你可能感兴趣的:(c++,c语言,c++,蓝桥杯)