C/C++中的一些简单技巧

2020-05-06 22:53:01

我一生中参加过相当多的编程课程。其中有几个已经在神圣的C编程语言中出现了。曾经有一段时间,C和C++是我唯一可以说自己精通的语言。

多年来,我在所有这些课程中看到了一个不变的模式-它们教给你所有你应该学习的基础知识,但没有教给你你将需要的东西。例如,您已经学习了使用结构,但没有太多关于如何使用它们来理解您在用C语言编写代码时可能经常遇到的邪恶的疯狂行为。我将向您展示这个巧妙的技巧,它使用了结构,可以真正简化数组的工作。您可以使用宏做一些简单的事情,使动态分配大量的时间变得可读。是的,stdio.h内部就有一些令人惊叹的工具,它们可以使字符串操作变得容易得多。您可以使用此技巧来实现对C代码方式的一些根本更改。

这不是一篇面向专业C程序员的文章。这是为那些希望能够真正使用C的Python和Javascript程序员准备的,因为他们习惯于让自己喜欢的语言做一些有用的事情。

通常,当我们使用struct数据类型时,我们定义的结构如下所示:

我对此没有问题-这是一个经典的方法,每个优秀的C程序员都知道-但是我必须在这里放两次struct关键字吗?我可以推荐一个简单的习惯用法来定义结构吗?它可以将代码的整体感觉改变为更现代、更不过时的东西。

仅此而已。我们没有为该结构命名,但我们将其用作tyecif的一部分,以便为特定数据类型(即该结构)创建一个新名称。现在,宣言应该是这样的:

对于任何更熟悉OOP代码的人来说,这比对C代码更具可读性。

为什么有人要这么做?因为即使对于我们这些只使用Python、Javascript和Java等高级语言工作的人来说,有时我们也只需要使用一小段C(算了吧,没有一小段C-它至少有30行;)如果您遇到这种情况,需要编写C代码,但是真的希望它有面向对象的感觉,那么这是一个保持头脑清醒的简单工具。说到OOP感觉,

看看这个函数,它读取C中的整数数组并计算它们的和:

int sum(int*arr,int length){int sum=0,i;for(i=0;i<;length;i++)sum=sum+arr[i];return sum;}。

一个简单、友好、丑陋得不可调和的功能。为什么,哦,为什么,为什么以伟大的Chthullu的名义,有一个额外的参数来表示数组的长度?从字面上看,没有任何其他编程语言-即使是那个丑陋的灾难Java-也不需要这样。只有在C和C++中-在实际的C++中也不是这样,因为他们使用像std::Vector这样合理的东西-我们必须处理这种不美观的问题。我有一个简单的解决方案来处理这个乱七八糟的问题,它涉及到C:

是的,我正在制作一个结构,用大写的I命名为Int,使用tyecif,并使其包含一个用于动态分配的指针,以及一个用于存储如此动态分配的数组长度的谦虚整数。不完全是火箭科学,是吗?现在我们要做的就是让一些函数初始化结构,有点像构造函数,如果你愿意的话。完成此操作后,我在上面编写的函数将变得更加美观:

int sum(Int Arr){int sum=0,i;for(i=0;i<;Arr.length;i++)sum=sum+Arr.val[i];return sum;}。

那里。疼吗?如果我们没有LENGTH变量的精确值,就会发生这种情况,但是如果我们在分配内存时设置LENGTH变量,这里应该没有什么问题。构造函数简单地如下所示:

int newInt(Int Length){Int A={null,0};A.val=(int*)malloc(sizeof(Int)*length);A.length=length;返回A;}。

只有一件事需要注意-虽然指针val总是通过值传递,但它所指向的东西却不是。在函数内更改Arr.val的成员,后果自负。

该函数中唯一难看的代码是其中包含malloc的那一行。这就是我下一步要做的。

当您想要动态分配任何类型的数组时,请使用它生成的新宏。其实很简单:

//长度为5的整数数组:int*arr=new(int,5);//长度为2的双精度数组:Double*Trouble=new(Double,2);//长度为25的字符串,不含空字符:char*name=new(char,26);

我真的需要解释这个吗?所有的malloc语句彼此都太相似了,不值得一遍又一遍地写。只需使用此单行样板将所有malloc语句替换为一个像样的新语句,就像您在C++或Java中使用的那样。

请注意最后一个示例。我们已经创建了一个字符串。众所周知,使用C中的字符串是一件令人难以置信的痛苦。即使有了string.h库,它们仍然是需要处理的巨大痛苦。所有方法都会四处传递指针。其中一些函数更改了参数中的字符串,这些函数之所以可以这样做,是因为我们必须逐个指针地传递字符串。他们中的一些人没有,因为有问题的程序员当时感觉很好。它真的是一团糟,而string.h一直(至少对我来说)是访问文档的地方。即使这样,也没有简单方法可以将字符串解析为整数或将整数取消解析为字符串,如果您遇到需要的这种情况,您将会很难过。

在C的好的旧stdio.h头中有两个令人难以置信的强大功能,没有人谈论它们。令人怀疑的是,老师们对此保持沉默。如果你在课堂上遇到过他们,一定要让我知道。即使是关于C语言的好书也不会花太多时间颂扬这些坏男孩的优点。我不知道为什么这两个令人惊叹的功能总是默默无闻。

当然,我所说的无名英雄是spintf和sscanf方法。这些都非常有用。他们干些什么?它们所做的正是它们的表亲fprintf和fscanf所做的事情,但是这些函数不是写入和读取文件,而是写入字符串。

是。它们不使用文件指针,而是使用指向字符数组的指针作为第一个参数。然后,它们只需对char数组本身进行写入或读取!

想象一下这意味着什么。这是一条连接两个字符串str1和str2并将它们放入新字符串target中的简单语句:

现在,为什么不用好的老的strcat呢?嗯,原因有三个:

这个更快。它比strcat快大约20%,因为它使用syscall访问存储在target中的字符串,而不是在其上循环。我在MANJARO5.4内核(LINUX)的Manjaro上检查过使用GCC 9.3。

如果您想用空格或逗号连接两个字符串,该怎么办呢?比如,把名字和姓氏写成全名?

最好的部分是您可以在两个字符串之间放置任何东西-逗号、空格、制表符、换行符等等。想要在拍打第二个字符串的末尾之前删除第一个字符串的最后两个字符吗?在他们中间放一双\b。想要用“abcde”替换字符串的前N个字符吗?在他们之间放一个回车。可能性是无限的!。

你有一个整数。你有一根绳子。您希望在字符串末尾追加整数。Python中类似这样的内容:

用C语言做这件事是极其困难的。除非使用spintf。然后就会变得极其简单。请注意此代码:

请再次注意,连接的对象根本不需要是字符串!这就是我们的下一个大把戏:

是的,解析。在字符串S中有一个整数,就像我们在字符串S中写一个数字一样,换句话说,是逐位写入数字。您的工作是将其放入整数变量n中,该变量应该包含二进制格式的整数,就像整数在RAM中的存在方式一样。

就像Javascript中的parseInt或Python中的int一样简单。与Java中的Integer.parseInt一样简单(好吧,很奇怪,但很简单)。就像C#中的int.parse一样简单。C和C++的噩梦。

输入sscanf。注意这个词的用法。它类似于fscanf,但是它从字符串中读取变量,而不是从文件中读取。开始:

将现有整数n转换为字符串并将其存储在字符串变量S中同样容易,只需打印到S,而不是从它进行扫描:

现在,有一件重要的事情需要注意:您将要求stdio使用这两个函数。如果将它们放在头文件中,则需要确保在stdio.h头文件之后调用头文件。

这就是目前的情况。在我的下一篇文章中,我将讨论如何实现拆分和联接函数。然后我将使用C++,因为std::Vector类在存储字符串列表方面比直接数组要好得多,我们的拆分函数将实现该列表,而我们的联接函数将读取为参数。

然而,有了后两个函数,就有可能做出比单纯的技巧和习惯用法强大得令人难以置信的东西。当然,我说的是变量变量数据类型。

这将需要C++提供的一些有趣的抽象。在我的下一篇文章中,我将写关于实现动态类型变量数据类型,并使用它来生成无数类型变量的向量。

祝您今天过得愉快。请发表评论。我想知道我是否做错了什么,或者这些技术是否已经被其他程序员发现并以他们的名字命名(我不打算抄袭!)。或者是否有更大的简化可用。