page contents

从C#转到C语言

本文讲述了从C#转到C语言!具有很好的参考价值,希望对大家有所帮助。一起跟随六星小编过来看看吧,具体如下:

attachments-2022-09-6nBwf16b631e8f1489ce7.png本文讲述了从C#转到C语言!具有很好的参考价值,希望对大家有所帮助。一起跟随六星小编过来看看吧,具体如下:

学一门语言,最好的办法就先系统的看一遍教程,然后多多动手实践,我们拿字符串提取信息的题目开始学习,题目要求如下:

现在我们参考c#的实现,再用C语言来实现一个,因为C语言和C#有很多区别,而我们比较熟悉c#语言,所以我们可以对比着来学习。首先要说的是c和c++ 是两门不同的语言,虽然c++编译器能编译c代码。下面的介绍中也会提到一些c和c++的区别。精通C语言不是特别难,如果要精通c++很难,C++的细节太多了。

c#有using语句用来引入一个命名空间,本文件就可以使用该命名空间下的类了,c语言里没有命名空间的概念,如果要使用C函数库里的函数的话,使用#include语句来把那个头文件包含进来就可以使用了,如下

#include

但c++里就可以使用using来引入命名空间,比如

双击代码全选 1 using namespace std;

类库

.net开发有。net framework,c没有这么强大的类库,但c也有一些标准的函数库,比如stdio.h里定义了输入输出的一些函数,stdlib.h定义了一些内存分配,类型转换等函数,math.h里定义了一下数学相关的函数。

注意不要把c标准函数库和c++标准程序库混淆了,c++标准程序库比c标准函数库强大多了,增强了字符串相关的类,还有一些数据结构,异常处理方面的类。另外还有个c++标准模板库,就是STL,这个大概相当于。NET里System.Collections.Generic下的类,主要是有一些通用的容器的数据结构和用于查询数据的定位器,c语言只能用第一个,c标准函数库,另外两个都不能用。

宏,枚举和常量

c 语言里可以用#define宏和enum类型来定义常量,在程序中没有地方存它的值,在编译的时候就分配好内存了;而用const修饰的变量叫只读变量,需要在内存里开辟一个地方保存它的值,由编译器来标识它不可以修改。在c#里const和readonly关键字定义了编译时常量和运行时常量,这两种常量在使用上也有一些不同,比如a程序集定义了一个const常量,b程序集引用a程序集,a的const常量修改了后,b程序集要重新编译才能使修改生效,而如果a程序集里是用readonly定义的常量,b就不用重新编译。如下,定义了一个常量和3个只读变量

双击代码全选 1234 #define MAX_TOKEN_LEN 20 const e_arg_invalid = -1; const e_token_overfllow = -2; const s_ok = 0;

注意#define语句后面没有分号,关于常量和只读变量的更多的细节上的区别,见下面的链接

C语言程序设计之正确使用const

CLR Via C# 学习笔记- 常量和字段(const readonly)

函数原型定义

在c#里,一个文件里一个函数无论定义在哪里,另一个函数都可以直接使用,但C语言里,一个函数的定义必须在它的使用之前,如果一个函数的定义在较靠后的地方,而上面有个函数要调用这个函数,就需要把被调用的这个函数在文件比较靠上的部分进行原型定义。原型定义就是把这个函数的签名写出来,表示下面会有这么一个函数,一般函数定义写在头文件里。如下就是对字符串状态解析用的5个函数的原型定义。

如何写出专业的C头文件

函数指针

c# 里的委托咱们都十分的熟悉,它指向一个方法链,执行它的话,这一串儿方法都会执行。在c里没有委托的概念,但有函数指针的概念,函数指针可以指向一个函数,调用这个函数指针,真正的方法也会调用(但会访问两次内存,效率比直接调用低),可如下c#代码如何用c来表示呢?

delegate StateParser StateParser(char ch);

StateParser这个委托的参数是char类型,但返回值又是它本身的类型,c语言虽然支持返回函数指针的函数,却不支持这种循环定义,所以我们需要一个无类型的指针void*来定义这个函数指针的返回值,然后再必要的时候进行类型转换,如下。

双击代码全选 1 typedef void* (*fn_parse)(char c);

该语句定义了名为fn_parse的函数指针,它需要一个char类型的参数,并返回void*类型。

本篇帖子的目的是为了学习c语言,其实这个题目用状态机来解,直接用几个状态处理函数之间相互调用就行,不定义StateParser这个委托就行,但现在我们来完全模仿老赵的c#实现。

LINQ

呵呵,C语言当然不会有LINQ了,更不会有string的Aggregate方法了,所以我们要自己实现一个aggregate方法,该方法需要两个参数,第一个参数是fn_parse类型的函数指针,第二个参数是一个字符串,遍历这个字符串,分别用每个字符作为参数去调用parse函数指针,并把其返回值也转换成fn_parse类型,然后用它去处理下一个参数。

代码

双击代码全选 1234567891011 void aggregate(fn_parse parse, const char* input){

  while(*input != ”){

  if(last_error == s_ok){

  parse = (fn_parse)(*parse)(*input);

  input++;

  }else{

  printf(“ocurr an error:%d”, last_error);

  break;

  }

  } }

看下面这句

双击代码全选 1 parse = (fn_parse)(*parse)(*input);

*用在一个指针的前面的时候是表示取值,*parse是取出函数指针parse所指向的函数,前面的(fn_parse)把返回的函数的地址void*转换成fn_parse类型,*input是取出input指针所指向的字符。

LinQ方法之———Aggregate

异常处理

c#里异常处理可以用try语句来实现结构化异常处理,在c里一般用返回码来做异常处理,我们先声明了一个全局变量last_error表示最后一次出现异常的错误码,然后定义了几个只读变量来表示可能的错误码,如下。

双击代码全选 1234 const e_arg_invalid = -1; /* 错误的参数*/const e_token_overfllow = -2;/* 数组溢出 */const s_ok = 0; int last_error = 0;

c 里只支持/**/括住的注释,c++里支持//格式的注释,我们在每调用一次函数之后,要判断last_error是否为s_ok,如果不是,说明函数执行出错了,上面的aggregate里就用了这样的异常处理机制。在函数的定义里,应该在函数的开始把last_error设置为s_ok,出错的时候设置为相应的错误码。

 字符串

c#的字符串很强大,String类型有很多方法,而且。net 3.5又加了一些扩展方法,使用起来非常方面,c里就没这么方便了,c里的字符串是char的数组,并以结束。可以用char[]来表示,因为数组可以用指针表示,所以也可以用char*来表示。然后有一些库函数可以操作字符串,但都比较简单。c++里定义了string类型,以及支持多字节编码的 wchar_t等类型,c/c++里的字符串由于历史原因有很多细节的问题,具体看下面的两个链接。 

输入输出

c#里有Console.Write和Console.Read两个方法进行输入输出,在c里有printf和scanf,这两个函数可以进行格式化输出和输入,常用的%d表示int,%c表示字符,%s表示字符串。

更多相关技术内容咨询欢迎前往并持续关注六星社区了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

  • 发表于 2022-09-12 09:48
  • 阅读 ( 569 )
  • 分类:C/C++开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
轩辕小不懂
轩辕小不懂

2403 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. Pack 1131 文章
  3. 小柒 1046 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章