LINUXQQ

六月 14, 2009

文件I/O函数(fcntl)

类归于: C语言 — 标签: — admin @ 7:43 下午

fcntl函数:int
fcntl(int filedes, int cmd, …/*int arg */);
返回:若成功则依赖于cmd,若出错为-1。
作用:可以改变已打开的文件的性质
下列三个命令有特定的返回值:F_DUPFD,F_GETFD以及F_GETOWN。第一个返回新的文件描述符,第二个返回相应标志,最后一个返回一个正的进程ID或负的进程组ID。
第三个参数总是一个整数,当然在作为记录锁用时,第三个参数则是指向一个结构的指针。
fcntl函数有五种功能:
(1)复制一个现存的描述符(cmd=F_DUPFD)
(2)获得/设置文件描述符标志(cmd=F_GETFD或F_SETFD)
(3)获得/设置文件状态标志(cmd=F_GETFL或F_SETFL)
(4)获得/设置异步I/O有权(cmd=F_GETOWN或F_SETOWN)
(5)获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW)
F_DUPFD:复制文件描述符filedes,新文件描述符作为函数值返回。它是尚未打开的各描述符中大于或等于第三个参数值中各值的最小值。新描述符与filedes共享同一文件表项。但是新描述符有它自己的一套文件描述符标志,其FD_CLOEXEC文件描述符标志被清除。
F_GETFD:对应于filedes的文件描述符标志作为函数值返回。当前只定义了一个文件描述符标志FD_CLOEXEC。
F_SETFD:对于filedes设置文件描述符标志。新标志值按第三个参数设置。
F_GETFL:对应于filedes的文件状态标志作为函数返回。在说明open函数时,已说明了文件状态标志。
F_SETFL:将文件状态标志设置为第三个参数的值(取整数值),可以更改的几个标志:O_APPEND,O_NONBLOCK,O_SYNC和O_ASYNC。
F_GETOWN:取当前接受SIGIO和SIGURG信号的进程ID或进程组ID。
F_SETOWN:设置接受SIGIO和SIGURG信号的进程ID或进程组ID。正的arg指定一个进程ID,负的arg表示等于arg绝对值的一个进程组ID。
范例:
#include

#include

#include

#include

int
main(int argc, char **argv)
{
int
fd;
int
var;
if(argc!=2)
{
printf(“please
input filename and one arg!\n”);
exit(1);
}

if((var=fcntl(atoi(argv[1]),F_GETFL,0))==-1)
{
printf(“fcntl
file error!\n”);
exit(1);
}
printf(“%d\n”,var);
switch(var
& O_ACCMODE)
{
case
O_RDONLY:printf(“Read only.\n”);
break;
case
O_WRONLY:printf(“Write only.\n”);
break;
case
O_RDWR: printf(“Read Write.\n”);
break;
default:break;
}
exit(0);
}

五月 21, 2009

C 指针和数组地址笔记

类归于: C语言 — 标签: — admin @ 11:44 上午

#include<stdio.h>
 int main()
    {
      int a[5]={1,2,3,4,5];
      int *ptr=(int *)(&a+1)
      printf(“%d,%d\n”,*(a+1),*(prt-1);
}
~
一定很绕吧,我也糊涂了 琢磨了一早上

C语言里面规定a是数组的首地址是代表整个数组 但&a+1不等价于&a[0]+1, &a是首地址 &a+1就是取a 的地址在加1直接指向下一个内存区域  也就是指向到了ptr[0]的地址是地址上面    然后在把&a+1 的地址复制给ptr指针 这时候ptr变指向了a[5] ,ptr-1=a[4]          最后结果2,5

四月 15, 2009

C语言笔记 指针类型转换

类归于: C语言 — 标签: — admin @ 11:08 上午

我们初始化一个指针或给一个指针赋值时,赋值号的左边是一个指针,赋
值号的右边是一个指针表达式。在我们前面所举的例子中,绝大多数情况下,指
针的类型和指针表达式的类型是一样的,指针所指向的类型和指针表达式所指向
的类型是一样的。
例十四:
1。 float f=12.3;
2。 float *fptr=&f;
3。 int *p;
在上面的例子中,假如我们想让指针p指向实数f,应该怎么搞?是用下面的
语句吗?
p=&f;
不对。因为指针p的类型是int*,它指向的类型是int。表达式&f的结果是一
个指针,指针的类型是float*,它指向的类型是float。两者不一致,直接赋值的
方法是不行的。至少在我的MSVC++6.0上,对指针的赋值语句要求赋值号两边的类
型一致,所指向的类型也一致,其它的编译器上我没试过,大家可以试试。为了
实现我们的目的,需要进行“强制类型转换”:
p=(int*)&f;
如果有一个指针p,我们需要把它的类型和所指向的类型改为TYEP*和TYPE,
那么语法格式是:
(TYPE*)p;
这样强制类型转换的结果是一个新指针,该新指针的类型是TYPE*,它指向的
类型是TYPE,它指向的地址就是原指针指向的地址。而原来的指针p的一切属性都
没有被修改。一个函数如果使用了指针作为形参,那么在函数调用语句的实参和形参的结
合过程中,也会发生指针类型的转换。
例十五:
void fun(char*);
int a=125,b;
fun((char*)&a);


void fun(char*s)
{
char c;
c=*(s+3);*(s+3)=*(s+0);*(s+0)=c;
c=*(s+2);*(s+2)=*(s+1);*(s+1)=c;
}
}
注意这是一个32位程序,故int类型占了四个字节,char类型占一个字节。函
数fun的作用是把一个整数的四个字节的顺序来个颠倒。注意到了吗?在函数调用
语句中,实参&a的结果是一个指针,它的类型是int *,它指向的类型是int。形
参这个指针的类型是char*,它指向的类型是char。这样,在实参和形参的结合过
程中,我们必须进行一次从int*类型到char*类型的转换。结合这个例子,我们可
以这样来想象编译器进行转换的过程:编译器先构造一个临时指针 char*temp,
然后执行temp=(char*)&a,最后再把temp的值传递给s。所以最后的结果是:s的
类型是char*,它指向的类型是char,它指向的地址就是a的首地址。

我们已经知道,指针的值就是指针指向的地址,在32位程序中,指针的值其
实是一个32位整数。那可不可以把一个整数当作指针的值直接赋给指针呢?就象
下面的语句:
unsigned int a;
TYPE *ptr;//TYPE是int,char或结构类型等等类型。


a=20345686;
ptr=20345686;//我们的目的是要使指针ptr指向地址20345686(十进制

ptr=a;//我们的目的是要使指针ptr指向地址20345686(十进制)
编译一下吧。结果发现后面两条语句全是错的。那么我们的目的就不能达到
了吗?不,还有办法:
unsigned int a;
TYPE *ptr;//TYPE是int,char或结构类型等等类型。


a=某个数,这个数必须代表一个合法的地址;
ptr=(TYPE*)a;//呵呵,这就可以了。
严格说来这里的(TYPE*)和指针类型转换中的(TYPE*)还不一样。这里的(TYP
E*)的意思是把无符号整数a的值当作一个地址来看待。
上面强调了a的值必须代表一个合法的地址,否则的话,在你使用ptr的时候
,就会出现非法操作错误。

想想能不能反过来,把指针指向的地址即指针的值当作一个整数取出来。完
全可以。下面的例子演示了把一个指针的值当作一个整数取出来,然后再把这个
整数当作一个地址赋给一个指针:
例十六:
int a=123,b;
int *ptr=&a;
char *str;
b=(int)ptr;//把指针ptr的值当作一个整数取出来。
str=(char*)b;//把这个整数的值当作一个地址赋给指针str。

好了,现在我们已经知道了,可以把指针的值当作一个整数取出来,也可以
把一个整数值当作地址赋给一个指针。

 

其他相关资料:

#pragma src

#i nclude <reg51.H>
f(){}
f1(){}
f2(){}

main()
{
    {
        int x;
        int *px;

        //下面这些表示虽然很烦,但是生成的代码却及其简洁:

        //将 xdata 型指针 0×4000 赋给 px
        px=(int xdata *)0×4000;

        //表示从 xdata 0×4000处取一个 char 给x
        x=*((char xdata *)0×4000);

        // 表示从 code 0×4000处取一个 word 作为 xdata 型的指针 给
px
        px=*((int xdata * xdata *)0×4000);

        //表示从 code 0×4000处取一个 word 作为 xdata 型的指针,
        //再把这个指针指向的char数据赋给x
        x=**((char xdata * code *)0×4000);

        //表示把函数f()入口地址当作xdata型指针,再把指向的xdata
        //中的int型数据作为code型指针,把指向的code字节
        //赋给x(晕,这样有意义吗?)
        x=**(int code * xdata *)f;

        //把f()入口地址处的ROM中两个code型字节,
        //赋给堆栈指针SP指向的字节(想干什么?编操作系统?)
        *(unsigned int idata *)SP=*(unsigned int code *)&f;

        //表示把f()入口地址处的ROM中两个code型字节,
        //作为一个xdata指针寻址,
        //把指向的数据作为pdata指针寻址,
        //再把把指向的数据作为idata指针寻址,
        //把该地址处的一个字节赋给x (我靠,累死了)
        x= ****(unsigned int data * idata * pdata * xdata * code
*)&f;
       
        //总之,一个括号里面外面的”*”一样多就表示指向的是数据。
    }

    {
        //数组函数
        code void (*ArrFn[])(void) =
        {    &f1,
            &f2,
        };
        //可以像引用数组一样调用函数啦:
        (*ArrFn[0])();
        (*ArrFn[1])();
    }

    {
        //这样将使函数调用0000H处:
        void (*reset) (void);
        reset=0×0;
        (*reset)();
        reset();

        //或者直接这样,仅仅生成一条指令LCALL 1234H
        ((void (code *)(void))0×1234)();
    }

    {
        //这样可以调用RETI指令:
        #define  INT_NUM  30    //空闲中断号
        ((void (code *)(void))(INT_NUM*8+3))();
        //当然需要在外面声明   int_rpt()interrupt INT_NUM {}
    }
    {
        //这样调用RETI指令太变态:
        code unsigned char ret_i=0×32;
        ((void (code *)(void))(&ret_i))();
    }
}
int_rpt()interrupt INT_NUM {}

 

字节对齐

类归于: C语言 — 标签: — admin @ 12:47 上午

VC字节对齐全攻略

VC中下面几个结构体大小分别是多少呢
struct MyStruct
{
    double m4;
    char m1;
    int  m3;
};

struct MyStruct {
    char m1;
    double m4;
    int m3;
};

#pragma pack(push)//保存对齐状态
#pragma pack(16)  //设置为16字节对齐
struct test
{
   char m1;
   int m3; 
   double m4;    
};
#pragma pack(pop)//恢复对齐状态
如果你的答案不是16,24和16,相信下面的内容对你很有帮助。

1、 sizeof应用在结构上的情况
请看下面的结构:
struct MyStruct
{
double dda1;
char dda;
int type
};
对结构MyStruct采用sizeof会出现什么结果呢?sizeof(MyStruct)为多少呢?也许你
会这样求:
sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13
但是当在VC中测试上面结构的大小时,你会发现sizeof(MyStruct)为16。你知道为什
么在VC中会得出这样一个结果吗?
其实,这是VC对变量存储的一个特殊处理。为了提高CPU的存储速度,VC对一些变量的
起始地址做了“对齐”处理。在默认情况下,VC规定各成员变量存放的起始地址相对于结
构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的
对齐方式(vc6.0,32位系统)。
类型      对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)
Char      偏移量必须为sizeof(char)即1的倍数
Short     偏移量必须为sizeof(short)即2的倍数
int   偏移量必须为sizeof(int)即4的倍数
float 偏移量必须为sizeof(float)即4的倍数
double 偏移量必须为sizeof(double)即8的倍数
各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对
齐方式调整位置,空缺的字节VC会自动填充。同时VC为了确保结构的大小为结构的字节边
界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员
变量申请空间后,还会根据需要自动填充空缺的字节。
下面用前面的例子来说明VC到底怎么样来存放结构的。
struct MyStruct
{
double dda1;
char dda;
int type
};
为上面的结构分配空间的时候,VC根据成员变量出现的顺序和对齐方式,先为第一个
成员dda1分配空间,其起始地址跟结构的起始地址相同(刚好偏移量0刚好为sizeof(doub
le)的倍数),该成员变量占用sizeof(double)=8个字节;接下来为第二个成员dda分配空
间,这时下一个可以分配的地址对于结构的起始地址的偏移量为8,是sizeof(char)的倍数
,所以把dda存放在偏移量为8的地方满足对齐方式,该成员变量占用 sizeof(char)=1个字
节;接下来为第三个成员type分配空间,这时下一个可以分配的地址对于结构的起始地址
的偏移量为9,不是sizeof (int)=4的倍数,为了满足对齐方式对偏移量的约束问题,VC自
动填充3个字节(这三个字节没有放什么东西),这时下一个可以分配的地址对于结构的起
始地址的偏移量为12,刚好是sizeof(int)=4的倍数,所以把type存放在偏移量为12的地方
,该成员变量占用sizeof(int)=4个字节;这时整个结构的成员变量已经都分配了空间,总
的占用的空间大小为:8+1+3+4=16,刚好为结构的字节边界数(即结构中占用最大空间的
类型所占用的字节数sizeof(double)=8)的倍数,所以没有空缺的字节需要填充。所以整
个结构的大小为:sizeof(MyStruct)=8+1+ 3+4=16,其中有3个字节是VC自动填充的,没有
放任何有意义的东西。
下面再举个例子,交换一下上面的MyStruct的成员变量的位置,使它变成下面的情况

struct MyStruct
{
char dda;
double dda1;
int type
};
这个结构占用的空间为多大呢?在VC6.0环境下,可以得到sizeof(MyStruc)为24。结
合上面提到的分配空间的一些原则,分析下VC怎么样为上面的结构分配空间的。(简单说
明)
struct MyStruct
{
char dda;//偏移量为0,满足对齐方式,dda占用1个字节;
double dda1;//下一个可用的地址的偏移量为1,不是sizeof(double)=8
//的倍数,需要补足7个字节才能使偏移量变为8(满足对齐
//方式),因此VC自动填充7个字节,dda1存放在偏移量为8
//的地址上,它占用8个字节。
int type;//下一个可用的地址的偏移量为16,是sizeof(int)=4的倍
//数,满足int的对齐方式,所以不需要VC自动填充,type存
//放在偏移量为16的地址上,它占用4个字节。
};//所有成员变量都分配了空间,空间总的大小为1+7+8+4=20,不是结构
//的节边界数(即结构中占用最大空间的类型所占用的字节数sizeof
//(double)=8)的倍数,所以需要填充4个字节,以满足结构的大小为
//sizeof(double)=8的倍数。
所以该结构总的大小为:sizeof(MyStruc)为1+7+8+4+4=24。其中总的有7+4=11个字节
是VC自动填充的,没有放任何有意义的东西。
VC对结构的存储的特殊处理确实提高CPU存储变量的速度,但是有时候也带来了一些麻
烦,我们也屏蔽掉变量默认的对齐方式,自己可以设定变量的对齐方式。
VC 中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存
放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏
移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移
量为n的倍数,不用满足默认的对齐方式。结构的总大小也有个约束条件,分下面两种情况
:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的
变量占用的空间数的倍数;

否则必须为n的倍数。下面举例说明其用法。
#pragma pack(push) //保存对齐状态
#pragma pack(4)//设定为4字节对齐
struct test
{
char m1;
double m4;
int m3;
};
#pragma pack(pop)//恢复对齐状态

以上结构的大小为16,下面分析其存储情况,首先为m1分配空间,其偏移量为0,满足
我们自己设定的对齐方式(4字节对齐),m1占用1个字节。接着开始为 m4分配空间,这时
其偏移量为1,需要补足3个字节,这样使偏移量满足为n=4的倍数(因为sizeof(double)大
于n),m4占用8个字节。接着为m3分配空间,这时其偏移量为12,满足为4的倍数,m3占用
4个字节。这时已经为所有成员变量分配了空间,共分配了16个字节,满足为n的倍数。如
果把上面的#pragma pack(4)改为#pragma pack(16),那么我们可以得到结构的大小为24。
(请读者自己分析)

2、 sizeof用法总结

在VC中,sizeof有着许多的用法,而且很容易引起一些错误。下面根据sizeof后面的
参数对sizeof的用法做个总结。
A.参数为数据类型或者为一般变量。例如sizeof(int),sizeof(long)等等。这种情
况要注意的是不同系统系统或者不同编译器得到的结果可能是不同的。例如int类型在16位
系统中占2个字节,在32位系统中占4个字节。
B. 参数为数组或指针。下面举例说明.
int a[50]; //sizeof(a)=4*50=200; 求数组所占的空间大小
int *a=new int[50];// sizeof(a)=4; a为一个指针,sizeof(a)是求指针
//的大小,在32位系统中,当然是占4个字节。
C.参数为结构或类。Sizeof应用在类和结构的处理情况是相同的。但有两点需要注
意,第一、结构或者类中的静态成员不对结构或者类的大小产生影响,因为静态变量的存
储位置与结构或者类的实例地址无关。
第二、没有成员变量的结构或类的大小为1,因为必须保证结构或类的每一
个实例在内存中都有唯一的地址。
下面举例说明,
Class Test{int a;static double c};//sizeof(Test)=4.
Test *s;//sizeof(s)=4,s为一个指针。
Class test1{ };//sizeof(test1)=1;
D. 参数为其他。下面举例说明。
int func(char s[5]);
{
cout< //数的参数在传递的时候系统处理为一个指针,所
//以sizeof(s)实际上为求指针的大小。
return 1;
}
sizeof(func(“1234”))=4//因为func的返回类型为int,所以相当于
//求sizeof(int).
以上为sizeof的基本用法,在实际的使用中要注意分析VC的分配变量的分配策略,这
样的话可以避免一些错误

三月 31, 2009

sizeof() 字节对齐

类归于: C语言 — 标签: — admin @ 10:04 上午

 书上写的话太死,初学者有点难明白,举个例子

strunt A

{

int a;

char b;

}

sizeof A

你会认为4+1=5 5字节 答案错了

让宽度为4的基本数据类型(int等)都位于能被 4整除的地址

char 填3字节 能被4整除不就OK?

九月 19, 2008

C 各类数值型数据之间的混合运算

类归于: C语言 — 标签: — admin @ 10:34 上午

各类数值型数据之间的混合运算
变量的数据类型是可以转换的。转换的方法有两种,一种是自动转换,一种是强制转换。自动转换发生在不同数据类型的量混合运算时,由编译系统自动完成。自动转换遵循以下规则:
1) 若参与运算量的类型不同,则先转换成同一类型,然后进行运算。
2) 转换按数据长度增加的方向进行,以保证精度不降低。如int型和long型运算时,先把int量转成long型后再进行运算。
3) 所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算。
4) char型和short型参与运算时,必须先转换成int型。
5) 在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换为左边量的类型。如果右边量的数据类型长度左边长时,将丢失一部分数据,这样会降低精度,丢失的部分按四舍五入向前舍入。
下图表示了类型自动转换的规则。

七、条件运算符
条件运算符(?:)是C语言中唯一的一个三目运算符,它是对第一个表达式作真/假检测,然后根据结果返回两外两个表达式中的一个。
<表达式1>?<表达式2>:<表达式3>
在运算中,首先对第一个表达式进行检验,如果为真,则返回表达式2的值;如果为假,则返回表达式3的值。
例如:
a=(b>0)?b:-b;
当b>0时,a=b;当b不大于0时,a=-b;这就是条件表达式。其实上面的意思就是把b的绝对值赋值给a。

逻辑运算符
逻辑运算符是根据表达式的值来返回真值或是假值。其实在C语言中没有所谓的真值和假值,只是认为非0为真值,0为假值。
符号 功能
&& 逻辑与
|| 逻辑或
! 逻辑非
例如:
5!3;
0||-2&&5;
!4;

当表达式进行&&运算时,只要有一个为假,总的表达式就为假,只有当所有都为真时,总的式子才为真。当表达式进行||运算时,只要有一个为真,总的值就为真,只有当所有的都为假时,总的式子才为假。逻辑非(!)运算是把相应的变量数据转换为相应的真/假值。若原先为假,则逻辑非以后为真,若原先为真,则逻辑非以后为假。
还有一点很重要,当一个逻辑表达式的后一部分的取值不会影响整个表达式的值时,后一部分就不会进行运算了。例如:
a=2,b=1;
a||b-1;
因为a=2,为真值,所以不管b-1是不是真值,总的表达式一定为真值,这时后面的表达式就不会再计算了。

七、条件运算符
条件运算符(?:)是C语言中唯一的一个三目运算符,它是对第一个表达式作真/假检测,然后根据结果返回两外两个表达式中的一个。
<表达式1>?<表达式2>:<表达式3>
在运算中,首先对第一个表达式进行检验,如果为真,则返回表达式2的值;如果为假,则返回表达式3的值。
例如:
a=(b>0)?b:-b;
当b>0时,a=b;当b不大于0时,a=-b;这就是条件表达式。其实上面的意思就是把b的绝对值赋值给

九、优先级和结合性
从上面的逗号运算符那个例子可以看出,这些运算符计算时都有一定的顺序,就好象先要算乘除后算加减一样。优先级和结合性是运算符两个重要的特性,结合性又称为计算顺序,它决定组成表达式的各个部分是否参与计算以及什么时候计算。
下面是C语言中所使用的运算符的优先级和结合性:
优先级 运算符 结合性
(最高) () [] -> . 自左向右
! ~ ++ — + – * & sizeof 自右向左
* / % 自左向右
+ – 自左向右
<< >> 自左向右
< <= > >= 自左向右
== != 自左向右
& 自左向右
^ 自左向右
| 自左向右
&& 自左向右
|| 自左向右
?: 自右向左
= += -= *= /= %= &= ^= |= <<= >>= 自右向左
(最低) , 自左向右

3.1.1 转义字符
转义字符是一种特殊的字符常量。转义字符以反斜线”\”开头,后跟一个或几个字符。转义字符具有特定的含义,不同于字符原有的意义,故称“转义”字符。例如,在前面各例题printf函数的格式串中用到的“\n”就是一个转义字符,其意义是“回车换行”。转义字符主要用来表示那些用一般字符不便于表示的控制代码。
常用的转义字符及其含义
转义字符 转义字符的意义 ASCII代码
\n 回车换行 10
\t 横向跳到下一制表位置 9
\b 退格 8
\r 回车 13
\f 走纸换页 12
\\ 反斜线符”\” 92
\’ 单引号符 39
\” 双引号符 34
\a 鸣铃 7
\ddd 1~3位八进制数所代表的字符
\xhh 1~2位十六进制数所代表的字符
广义地讲,C语言字符集中的任何一个字符均可用转义字符来表示。表中的\ddd和\xhh正是为此而提出的。ddd和hh分别为八进制和十六进制的ASCII代码。如\101表示字母”A” ,\102表示字母”B”,\134表示反斜线,\XOA表示换行等。

例中四次输出了a,b的值,但由于格式控制串不同,输出的结果也不相同。第四行的输出语句格式控制串中,两格式串%d 之间加了一个空格(非格式字符),所以输出的a,b值之间有一个空格。第五行的printf语句格式控制串中加入的是非格式字符逗号, 因此输出
的a,b值之间加了一个逗号。第六行的格式串要求按字符型输出 a,b值。第七行中为了提示输出结果又增加了非格式字符串。
1. 格式字符串
在Turbo C中格式字符串的一般形式为:
[标志][输出最小宽度][.精度][长度]类型
其中方括号[]中的项为可选项。
各项的意义介绍如下:
1) 类型:类型字符用以表示输出数据的类型,其格式符和意义如下表所示:
格式字符 意 义
d 以十进制形式输出带符号整数(正数不输出符号)
o 以八进制形式输出无符号整数(不输出前缀0)
x,X 以十六进制形式输出无符号整数(不输出前缀Ox)
u 以十进制形式输出无符号整数
f 以小数形式输出单、双精度实数
e,E 以指数形式输出单、双精度实数
g,G 以%f或%e中较短的输出宽度输出单、双精度实数
c 输出单个字符
s 输出字符串
2) 标志:标志字符为-、+、#、空格四种,其意义下表所示:
标 志 意 义
- 结果左对齐,右边填空格
+ 输出符号(正号或负号)
空格 输出值为正时冠以空格,为负时冠以负号
# 对c,s,d,u类无影响;对o类,在输出时加前缀o;对x类,在输出时加前缀0x;对e,g,f 类当结果有小数时才给出小数点

类型说明符 数的范围 字节数
int -32768~32767 即-215~(215-1) 2
unsigned int 0~65535 即0~(216-1) 2
short int -32768~32767 即-215~(215-1) 2
unsigned short int 0~65535 即0~(216-1) 2
long int -2147483648~2147483647即-231~(231-1) 4
unsigned long 0~4294967295 即0~(232-1) 4

Turbo C中单精度型占4个字节(32位)内存空间,其数值范围为3.4E-38~3.4E+38,只能提供七位有效数字。双精度型占8 个字节(64位)内存空间,其数值范围为1.7E-308~1.7E+308,可提供16位有效数字。
类型说明符 比特数(字节数) 有效数字 数的范围
float 32(4) 6~7 10-37~1038
double 64(8) 15~16 10-307~10308
long double 128(16) 18~19 10-4931~104932

3.1.1 字符串处理函数
C语言提供了丰富的字符串处理函数, 大致可分为字符串的输入、输出、合并、修改、比较、转换、复制、搜索几类。 使用这些函数可大大减轻编程的负担。用于输入输出的字符串函数,在使用前应包含头文件”stdio.h”,使用其它字符串函数则应包含头文件”string.h”。
下面介绍几个最常用的字符串函数。
1. 字符串输出函数 puts
格式: puts (字符数组名)
功能:把字符数组中的字符串输出到显示器。 即在屏幕上显示该字符串。
【例7.12】
#include”stdio.h”
main()
{
char c[]=”BASIC\ndBASE”;
puts(c);
}

从程序中可以看出puts函数中可以使用转义字符,因此输出结果成为两行。puts函数完全可以由printf函数取代。当需要按一定格式输出时,通常使用printf函数。
2. 字符串输入函数gets
格式: gets (字符数组名)
功能:从标准输入设备键盘上输入一个字符串。
本函数得到一个函数值,即为该字符数组的首地址。
【例7.13】
#include”stdio.h”
main()
{
char st[15];
printf(“input string:\n”);
gets(st);
puts(st);
}

可以看出当输入的字符串中含有空格时,输出仍为全部字符串。说明gets函数并不以空格作为字符串输入结束的标志,而只以回车作为输入结束。这是与scanf函数不同的。
3. 字符串连接函数strcat
格式: strcat (字符数组名1,字符数组名2)
功能:把字符数组2中的字符串连接到字符数组1 中字符串的后面,并删去字符串1后的串标志“\0”。本函数返回值是字符数组1的首地址。
【例7.14】
#include”string.h”
main()
{
static char st1[30]=”My name is “;
int st2[10];
printf(“input your name:\n”);
gets(st2);
strcat(st1,st2);
puts(st1);
}

本程序把初始化赋值的字符数组与动态赋值的字符串连接起来。要注意的是,字符数组1应定义足够的长度,否则不能全部装入被连接的字符串。
4. 字符串拷贝函数strcpy
格式: strcpy (字符数组名1,字符数组名2)
功能:把字符数组2中的字符串拷贝到字符数组1中。串结束标志“\0”也一同拷贝。字符数名2,也可以是一个字符串常量。这时相当于把一个字符串赋予一个字符数组。
【例7.15】
#include”string.h”
main()
{
char st1[15],st2[]=”C Language”;
strcpy(st1,st2);
puts(st1);printf(“\n”);
}

本函数要求字符数组1应有足够的长度,否则不能全部装入所拷
贝的字符串。
5. 字符串比较函数strcmp
格式: strcmp(字符数组名1,字符数组名2)
功能:按照ASCII码顺序比较两个数组中的字符串,并由函数返回值返回比较结果。
字符串1=字符串2,返回值=0;
字符串2〉字符串2,返回值〉0;
字符串1〈字符串2,返回值〈0。
本函数也可用于比较两个字符串常量,或比较数组和字符串常量。
【例7.16】
#include”string.h”
main()
{ int k;
static char st1[15],st2[]=”C Language”;
printf(“input a string:\n”);
gets(st1);
k=strcmp(st1,st2);
if(k==0) printf(“st1=st2\n”);
if(k>0) printf(“st1>st2\n”);
if(k<0) printf("st1 }

本程序中把输入的字符串和数组st2中的串比较,比较结果返回到k中,根据k值再输出结果提示串。当输入为dbase时,由ASCII 码可知“dBASE”大于“C Language”故k〉0,输出结果“st1>st2”。
6. 测字符串长度函数strlen
格式: strlen(字符数组名)
功能:测字符串的实际长度(不含字符串结束标志‘\0’) 并作为函数返回值。
【例7.17】
#include”string.h”
main()
{ int k;
static char st[]=”C language”;
k=strlen(st);
printf(“The lenth of the string is %d\n”,k);
}

另外, 要补充说明一下, 果你编写一个程序输出打印a和*a,你可发现它们的值是相同的,这是为什么呢? 我们可这样来理解:
首先,为了说明问题,我们把二维数组人为地看成由三个数组元素a[0],a[1],a[2]组成,将a[0],a[1],a[2]看成是数组名它们又分别是由4个元素组成的一维数组。因此,a表示数组第0行的地址, 而*a即为a[0], 它是数组名, 当然还是地址,它就是数组第0 行第0 列元素的地址。

从前面的分析可得出*(p+i)+j是二维数组i行j 列的元素的地址,而*(*(p+i)+j)则是i行j列元素的值

& 运算的规则是当两个位都为1时,结果为1,否则为0;
| 运算的规则是当两个位都为0时,结果为0,否则为1;
^ 运算的规则是当两个位相同时,结果为0,否则为1;
~ 运算的规则是当为1时结果为0,当为0时,结果为1。

WordPress 所驱动