C语言开发总结(一)

1.1 c++中的 -> 、::、 .的作用,都分别用在什么地方

->是指针,是一个指针变量访问其所指向地址存放其内部成员的方式;如struct A{int a;int b;}tmp;
struct A *p = new struct A; cout<<p->a<<p->b;其使用是和.类似,不同的是因为其是指针的缘故
::是作用域符号,主要有3个作用
1:作用域符号::的前面一般是类名称,后面一般是该类的成员名称,C++为例避免不同的类有名称相同的成员而采用作用域的方式进行区分
如:A,B表示两个类,在A,B中都有成员member。那么
A::member就表示类A中的成员member
B::member就表示类B中的成员member 
2:全局作用域符号:当全局变量在局部函数中与其中某个变量重名,那么就可以用::来区分如:
char zhou; //全局变量
void sleep()

char zhou; //局部变量
char(局部变量) = char(局部变量) *char(局部变量) ; 
::char(全局变量) =::char(全局变量) *char(局部变量); 

3:::是C++里的“作用域分解运算符”。比如声明了一个类A,类A里声明了一个成员函数voidf(),但没有在类的声明里给出f的定义,那么在类外定义f时,就要写成voidA::f(),表示这个f()函数是类A的成员函数。
.是用来访问类,结构等内部成员的运算符,是同->相同的使用方式

::是C++里的“作用域分解运算符”。比如声明了一个类A,类A里声明了一个成员函数voidf(),但没有在类的声明里给出f的定义,那么在类外定义f时,就要写成voidA::f(),表示这个f()函数是类A的成员函数。例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class  CA {
public :
   int  ca_var;
   int  add( int  a, int  b);
   int  add( int  a);
};
 
//那么在实现这个函数时,必须这样书写:
int  CA::add( int  a, int  b)
{
   return  a + b;
}
 
//另外,双冒号也常常用于在类变量内部作为当前类实例的元素进行表示,比如:
int  CA::add( int  a)
{
   return  a + ::ca_var;
}
 
//表示当前类实例中的变量ca_var。

第一个是指针 第二个是作用域 第三个 是类成员使用
比如: 
struct string 

char name[8]; 
char sex[4]; 
int age; 
char addr[40]; 

struct string *student; 
student->age = 18;/*给数组中age 赋值。 
借用下*/
student->age = 18;//也可以这样*student.age = 18;
相当於".成员"的作用,但定义成指针时则用"->成员"
struct a
{
int num
int age
}
a b;
a * c;
b.num
c->num
这样好懂了吧.

1.2  C语言 字符串前加L的意义 如:L“A”
Unicode或者宽字符都没有改变char数据型态在C中的含义。char继续表示1个字节的储存空间,sizeof (char)继续返回1。理论上,C中1个字节可比8位长,但对我们大多数人来说,1个字节(也就是1个char)是8位宽。
C中的宽字符基于wchar_t数据型态,它在几个表头文件包括WCHAR.H中都有定义,像这样:
typedef unsigned short wchar_t ;
因此,wchar_t数据型态与无符号短整数型态相同,都是16位宽。
要定义包含一个宽字符的变量,可使用下面的语句:
wchar_t c = 'A' ;  
变量c是一个双字节值0x0041,是Unicode表示的字母A。(然而,因为Intel微处理器从最小的字节开始储存多字节数值,该字节实际上是以0x41、0x00的顺序保存在内存中。如果检查Unicode文字的计算机储存应注意这一点。)
您还可定义指向宽字符串的指针:
wchar_t * p = L"Hello!" ;
注意紧接在第一个引号前面的大写字母L(代表「long」)。这将告诉编译器该字符串按宽字符保存-即每个字符占用2个字节。通常,指针变量p要占用4个字节,而字符串变量需要14个字节-每个字符需要2个字节,末尾的0还需要2个字节。
同样,您还可以用下面的语句定义宽字符数组:
static wchar_t a[] = L"Hello!" ;
该字符串也需要14个字节的储存空间,sizeof (a) 将返回14。索引数组a可得到单独的字符。a[1] 的值是宽字符「e」,或者0x0065。
虽然看上去更像一个印刷符号,但第一个引号前面的L非常重要,并且在两个符号之间必须没有空格。只有带有L,编译器才知道您需要将字符串存为每个字符2字节。稍后,当我们看到使用宽字符串而不是变量定义时,您还会遇到第一个引号前面的L。幸运的是,如果忘记了包含L,C编译器通常会给提出警告或错误信息。
您还可在单个字符文字前面使用L前缀,来表示它们应解释为宽字符。如下所示:
wchar_t c = L'A' ;
但通常这是不必要的,C编译器会对该字符进行扩充,使它成为宽字符。

1.3 ##、#、#@在C中的作用(VC)

先来段程序:

  
  
  1. #include <stdio.h>

  2. #define f(a,b) a##b

  3. #define g(a)   #a

  4. #define h(a)   g(a)

  5. #define p(a)   #@a

  6. int main(int argc, char* argv[])

  7. {

  8.    printf("%s\n", g(f(1,2)));

  9.    printf("%s\n", h(f(1,2)));

  10.    printf("%c, %d\n", p(1), p(1));

  11. return 0;

  12. }

输出结果

看上去有点奇怪。

##是连接操作符(我也不知道中文是啥,google到的是token-pasting operator),可以将操作符两端的标识符级联起来。

#是字符串化操作符(stringizing operator),可以将操作符后的标识符转化成字符串。

#@是字符化操作符(charizing),可以将操作符后的数据转化成字符。

来分析程序。

  
  
  1. printf("%s\n", g(f(1,2)));

g(f(1,2)),即#f(1,2),被转化成了字符串,于是g(f(1,2))就变成了"f(1,2)"。

  
  
  1. printf("%s\n", h(f(1,2)));  

h(f(1,2)),这里需要注意一下,#跟##不一样,如果宏定义的替换部分恰好跟其他的宏定义名字一样的话,会进行展开,即调用h(a)会先对g(a)进行展开。详见http://c-faq.com/ansi/stringize.html。如此一来,h(f(1,2))会先对f(1,2)进行运算,变成12,再运行h(12),变成"12"。

  
  
  1. printf("%c, %d\n", p(1), p(1));  

p(1),1被转化成字符,为了验证,输出它的ASCII码。

#,##, #@都仅适用于宏定义,在程序中无法单独使用。

有一道经典的C语言问题,关于宏定义中#和##符号的使用和宏定义展开问题
 
程序如下:

#include <stdio.h>
#define f(a,b) a##b
#define g(a)  #a
#define h(a) g(a)
 
int main()
{
        printf("%s\n", h(f(1,2)));
        printf("%s\n", g(f(1,2)));
        return 0;
}

答案:第一行:12  第二行:f(1,2)

说明:

1、关于符号#和##

两个符号都只能用于预处理宏扩展。不能在普通的源码中使用它们,只能在宏定义中使用。

简单的说,#是把宏参数变为一个字符串,##是把两个宏参数连接在一起。

关于这两个符号的具体意义和用法可以参见两篇文章:

#和##在宏替换中的作用 http://www.linuxidc.com/Linux/2014-06/102921.htm

C/C++ 宏中"#"和"##"的用法 http://www.linuxidc.com/Linux/2014-06/102924.htm

还有GCC帮助文档上的解释:

3.4 Stringification

3.5 Concatenation

2、关于宏展开

预处理过程的几个步骤:

1)字符集转换(如三联字符)

2)断行链接/

3)注释处理,/* comment */,被替换成空格

4)执行预处理命令,如#inlcude、#define、#pragma、#error等

5)转义字符替换

6)相邻字符串拼接

7)将预处理记号替换为词法记号

第4)步即如何展开宏函数的规则:在展开当前宏函数时,如果形参有#或##则不进行宏参数的展开,否则先展开宏参数,再展开当前宏。

宏替换顺序英文描述如下:

A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token, is replaced by the corresponding argument after all macros contained therein have been expanded.

3、总结

综合以上,对于这道题来说,第一行h(f(1,2)),由于h(a)非#或者##所以先展开其参数f(1,2),即12,所以变成h(12),然后再宏替换为g(12),再次替换为12。

第二行g(f(1,2)),宏g(a)带有#,所以里面的f(1,2)不展开,所以变成f(1,2)

类似的这种问题在《你必须知道的495个C语言问题》中出现过,在121页的“预处理功能”的问题11.19,有兴趣的朋友可以看一看。

C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码 http://www.linuxidc.com/Linux/2014-05/101227.htm

读C++ Primer 之构造函数陷阱 http://www.linuxidc.com/Linux/2011-08/40176.htm

读C++ Primer 之智能指针 http://www.linuxidc.com/Linux/2011-08/40177.htm

读C++ Primer 之句柄类 http://www.linuxidc.com/Linux/2011-08/40175.htm

C++11 获取系统时间库函数 time since epoch http://www.linuxidc.com/Linux/2014-03/97446.htm

C++11中正则表达式测试 http://www.linuxidc.com/Linux/2012-08/69086.htm

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值