哈尔滨市建设局网站,临沂网站建设模板,微信公众号网页制作,iis网站架设教程C编程常用技术 第一个C程序函数函数模板 数组字符数组 指针概念数组与指针字符串与指针函数与指针 引用引用作为参数常引用 结构体#xff0c;公用体#xff0c;枚举共用体枚举结构体#xff0c;共用体在内存单元占用字节数的计算 预处理常用宏定义命令do while(0)的妙用条件… C编程常用技术 第一个C程序函数函数模板 数组字符数组 指针概念数组与指针字符串与指针函数与指针 引用引用作为参数常引用 结构体公用体枚举共用体枚举结构体共用体在内存单元占用字节数的计算 预处理常用宏定义命令do while(0)的妙用条件编译extern C块的应用 第一个C程序
#includeiostream第一句不是C语句是一个预处理语句编译器的预处理器把输入输出流的标准头文件包括在本程序中所以不需要在句末加分号
include一个文件就是把这个文件的所有内容都加进来。
#include常用来包含系统提供的头文件编译器会到保存系统标准头文件的位置查找头文件
#include常用于包括程序员自己编号的头文件用这种格式时编译器先查找当前目录是否有指定名称的头文件然后从标准头目录中进行查找
当使用iostream.h时相当于在C中调用库函数使用的是全局命名空间。
不是string.h的升级版
命名空间是为了让大家类名共存而不至于引起冲突而设计的。C标准函数库的所有元素都被声明在一个命名空间中即std。
注意最好不要在头文件中使用命名空间否则容易造成命名冲突。
函数
函数模板
建立一个通用函数函数类型和形参不具体指定用一个虚拟类型代替。
调用时系统根据实参类型来取代虚拟类型。
定义函数模板的一般格式是
templatetypename T例子
#includeiostream
using namspace std;
templatetypename T
T min(T a,T b,T c){if(ab)ab;if(ac)ac;return a;
}
int main(){int a1,b2,c3;coutmin(a,b,c)endl;long long a11000,b12000,c13000;coutmin(a1,b1,c1)endl;return 0;
}比起函数重载只适用于函数个数相同而类型不同的情况。
数组
字符数组
C用’\0’来标识一个字符串的结束。。
strlen与sizeof的区别如下
前者参数必须是字符型指针char *且必须是以’\0’结尾的数组名作为参数传入时已经退化为指针了。功能返回字符串长度。sizeof在编译时就计算好了计算数据空间的字节数。sizeof常用于返回类型和静态分配的对象结构或数组所占的空间返回值跟对象结构数组所存储的内容没有关系。
例子
char a[10]helo;
char *strhello;
sizeof(a);//为10
sizeof(str);//指针所占大小即4。任意类型的指针都占4个字节。
还可以sizeof(函数名),即函数返回类型的空间大小返回类型不能是void。
指针
概念
程序经过编译以后已经将变量名转换为变量的地址对变量值的存取都是通过地址进行的。比如int a4变量这种
数组与指针
C中数组名代表数组第一个元素的地址如下程序定义了两个变量
int *p;
int a[10];若pa等价于pa[0]
数组指针也称行指针是一个指针变量专门指向二维数组的
假设定义int (*p)[n]p1时p要跨过n个整型数据的长度。
例子
int a[3][4];
int (*p)[4];
pa;//将二维数组的首地址赋给p也就是a[0]或a[0][0];
p; //执行后p跨过行a[0][]指向了行a[1][]指针数组。多个指针变量
int *p[n]这是一个整型指针数组它有n个指针类型的数组元素。
这里P1Pa这些操作都是错的因为p是个不可知的表示。
只有p[0],p[1]这些指针变量用来存放变量地址。
可以这样*pa赋值这里 *p表示指针数组第一个元素的值a的首地址的值。
二维数组赋给一指针数组
int *p[3];
int a[3][4];
for(int i0;i3;i)
{p[i]a[i];
}表示数组中第i行j列一个元素
*(p[i]j)
*( *(pi)j)
(*(pi))[j]
其中优先级()[]*
字符串与指针
char *str1abc;//abc是常量被放到程序的常量区不能被修改。string strabc;
char str2[]abc;字符串指针变量存放首地址可以改变指向不同的字符串但是不能改变所指向的字符串常量。
后两者都有单独的连续存储空间。
函数与指针
每一个函数都有一个入口地址该入口地址就是函数指针所指向的地址有了指向函数的指针变量后就可以用该指针变量调用函数了。
函数指针声明方法举例
int func(int a);
int (*f)(int a);//*的括号不能省略
ffunc;(*f)(10)//这样就调用了引用
用于为一个变量起一个别名。
函数执行期间不可以把一个应用再作为其他变量的引用。
引用作为参数
将一般变量作为函数的参数传给形参的是变量的值传递是单向的。
如果在执行函数期间形参的值发生变化并不传回给实参。
因为在调用函数时形参和实参不是同一个存储单元。
使用引用传递函数的参数时在内存中并没有产生实参的副本而是对实参直接操作。
当使用一般变量传递函数的参数时当函数发生调用时需要给形参分配存储单元形参变量是实参变量的副本。
如果传递的是对象还将调用拷贝构造函数。
所以当函数参数较大时用引用效果更好。
使用指针达到同样效果但是还是要给形参分配存储单元
常引用
要提高程序效率又要数据不能被改变就用常引用。
普通引用不能指向常量。
能用const引用就尽量用const引用。
结构体公用体枚举
共用体
用关键字union定义可以定义多种不同的数据类型里面的数据共享一段内存不同时间里保存不同的数据类型的长度的变量以节省空间。
但同一时间只能存储其中一个成员变量的值。
0x意思是十六进制数
可以使用union判断系统是大端还是小端存储。代码如下
#includeiostream
using namespace std;
union TEST{short a;char b[sizeof(short)];
};
int main(){TEST test;test.a0x0102;if(test.b[0]0x01test.b[1]0x02)cout大端endl;else if(test.b[0]0x02test.b[1]0x01)coutsmall endian.endl;return 0;
}小端符合人的感受。高位存高地址。
16进制转2进制即4位0x01即8位二进制也就是一个字节。
几乎所有网络协议都是采用big endian的方式来传输数据的当两台采用不同字节序的主机通信时在发送数据之前都必须经过字节序的转换称为网路字节序后再进行传播。
枚举
实际问题中有些变量的取值被限定在一个有限的范围内。
枚举类型是一种基本类型不是构造类型因为它不能再分解为任何其他基本类型。
声明方式
enum weekday{sun,mou,tue,wed,thu,fri,sat}
//定义变量
enum weekday a,b,c;//或者
enum weekday{sun,mou,tue,wed,thu,fri,sat}a,b,c;
//或者
enum {sun,mou,tue,wed,thu,fri,sat}a,b,c;枚举值是常量不是变量不能在程序中用赋值语句再对它赋值。
错误用法
sun5;
mon2;
sunmon;只能把枚举值赋予枚举变量不能把元素的数值直接赋予枚举变量。
asum;
bmon;//正确//错误
a0;
b1;默认第一个枚举值为0
默认枚举值为前面加1
结构体共用体在内存单元占用字节数的计算
float4字节
union的字节数计算
union A{int a[5];char b;double c;
};
int main(){coutsizeof(A)endl;return 0;
}打印24个字节。
union变量共用内存应以最长的为准但是结果却不是4*520个字节因为还需要以union内最长的变量进行默认对齐。
double8字节要对齐就只能24了。
把int a[5]编程inta[7]那么对齐结果又变成32.
struct字节数计算
struct B
{char a;double b;int c;
};
int main()
{coutsizeof(B)endl;return 0;
}打印出来24
char偏移量0占用1字节然后补齐7字节达到double对齐double占用8字节现在偏移量是16字节int可以直接存储占用4字节。现在总共就是20字节。
但是它还不是结构体内最长的空间类型的字节数的倍数这里就是需要达到double8字节的倍数即24。 混合结构体大小的计算
typedef union{long i;int k[5];char c;
}UPDATE;
struct data{int cat;UPDATE cow;double dog;
}too;UDATE temp;
int main()
{coutsizeof(struct data)sizeof(temp)endl;
}64为机器运行执行结果是4024即64。
同理temp是24字节然后struct就是424836还需要与8对齐那么就是40字节。
预处理
主要4中预处理宏定义文件包含条件编译和布局控制。
常用宏定义命令
#define用来将一个标识符宏名定义为一个字符串替换文本。
在简单宏定义的使用中当替换文本所表示的字符串是一个表达式时需要加上括号否则容易引起误解和误用。
比如
#define N 29
int main()
{int aN*N;coutaendl;return 0;
}因为宏展开是在预处理阶段完成的这个阶段把替换文本只是看作一个字符串并不会有任何的计算发生在展开时是在宏N出现的地方只是简单地使用串29来代替N并不会增添任何的符号。所以该程序展开后的结果是a29*29计算后的结果为29。实际上本意可能是11 *11121
带参数的宏定义的声明格式如下所示
#define 宏 (参数表列) 宏
例#define A(x) x
#define area(x) x*x这样的话可能出现问题
比如调用者
int yarea(22);那么结果就是22*22。为8本意可能是4 *416
初步解决
#define area(x) (x)*(x)但是调用还可能是
int yarea(22)/area(22);那么结果就是(22)*(22)/(22) *(22)结果是16
完整版解决应该是
#define area(x) ((x)*(x))do while(0)的妙用
假设一个宏
#define Foo(x) {\statement one;\statement two;\
}然后假设代码这样写
if(condition)Foo(x);
else...;那么展开就是
if(condition)statement one;statement two;
else...;这样else就没能和if连在一起编译错误了
而这样使用
#define Foo(x) do{\statement one;\statement two;\
}while(0)展开就是
if(condition)do{statement one;statement two;}while(0)
else...;这样就没问题因为do while(0)相当于单个语句。
条件编译
常见形式
#ifdef 标识符程序段1#else程序段2#endif作用当标识符已经被定义过一般是用#define命令定义则对程序段1进行编译否则编译程序段2。else部分也可以没有。
另外形式
#if 表达式程序段1#else程序段2#endif作用当指定的表达式值为真非零时就编译程序段1否则编译程序段2。
这里程序段既可以是语句组也可以是命令行。
extern C块的应用
#ifdef __cplusplusextern C{
#endif....
}
#ifdef __cplusplus
}
#endif__cplusplus是C的预定义宏表示当前开发环境是C
C为了支持重载在编译生成的汇编代码中会对函数名字进行一些处理通常称为函数名字改编如加入函数的参数类型或返回类型等而在C语言中只是简单地函数名字而已如下所示
int func(int a);
int func(double a);C语言无法区分上面两个函数的不同因为C编译器产生的函数名都是_func而C编译器产生的名字则可能是_func_Fi和_func_Fd这样就很好的把函数区分开了。
作用告诉C编译器这段代码要按C标准编译以尽可能地保持C与C的兼容性。