[C程序设计语言]第四部分

[C程序设计语言]第四部分
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4256069.html

结构体

struct point {
    intx;
    inty;
} x, y;
 
关键字struct后面的个运算符的优先级最高:结构运算符“.”和“->”、用于函数调用的“()”以及用于下标“[]”:++p->len相当于++(p->len),可以使用括号改变其运算结合顺序,如(++p)->len,但(p++)->len则还是先对len执行操作,然后再将p加上1,这里的括号其实可以省略,因为这是由于 p++ 的特性决定的(先使用再加1); *p->str读取的是指针str所指向的对象的值;
 
*p->str++先读取指针str指向的对象的值,然后再将str加上1(与*s++相同):
struct point {
    char * str;
    inty;
}/* *p */;
int main(int argc, char * argv[]) {
    //这里的结构指针变量不能在外层结构体声明时在后面定义,
    //否则运行时会出问题,不知道原因是什么,但书上好像也
    //是这么定义的
    struct point *p;
    p->str = "abcd";
    printf("%c\n", *p->str++);//a
    printf("%s", p->str);//bcd
    return 0;
}
 
(*p->str)++将指针str指向的对象的值加1;
*p++->str先读取指针str指向的对象的值,然后再将p加1;
 
结构数组:
struct point {
    char * str;
    inty;
} keytab[] = { { "auto", 0 }, { "break", 1 } };
如果初值是简单变量或字符串,并且其中的任何值都不为空,则内层的花括号可以省略。通常情况下,如果初值存在并且方括号[]中没有数值,编译程序将计算数组keytab中的基数。
 
结构指针:
struct point {
    char * str;
    inty;
};
int main(int argc, char * argv[]) {
    struct point keytab1 = { "auto1", 1 };
    struct point keytab2[] = { { "auto2", 2 }, { "break", 1 } };
 
    struct point *p1 = &keytab1;//可以指向一个结构体变量
    printf("%s\n", p1->str);//auto1
    printf("%c\n", *p1->str);//a
    printf("%s\n", p1->str + 1);//uto1 注,这里是先取地址,再将地址加1
   
    struct point *p2 = keytab2;//也可以指向一个结构体数组对象
    printf("%s\n", (p2 + 1)->str);//break
 
    return 0;
}

sizeof

C语言提供了一个编译进一元运算符sizeof,它可以用来计算任一对象的长度,表达式:
sizeof 对象
以及
sizeof(类型名)
将返回一个无符号整数,它等于指定对象或类型占用的存储空间字节数。其中对象可以是变量、数组或结构;类型可以是基本类型,如int、double,也可以是派生类型,如果结构类型或指针类型。针对以下结构体:
struct point {
    char * str;
    inty;
} keytab[] = { { "auto", 0 }, { "break", 1 } };
结构对象与结构类型长度计算如下:
    printf("%d\n", sizeof keytab);//16
    //因为结构体中每个成员的长度是按最长成员来计算的,所以不是5,而是8
    printf("%d", sizeof (struct point));//8
 
注,sizeof可以用在 #define 语句中,但不能用在条件编译语句 #if 中。

类型定义(typedef)

typedef int Length;将Length定义为与int具有同等意义的名字。类型Length可用于类型声明、类型转换等,它和类型int完全相同:
Length len,maxlen;
Length *lengths[];
类似地,声明
typedef char * String;
将String定义为与char*或字符指针同义,此后便可以在类型声明和类型转换中使用String,例如:
String p;
int strcmp(String,String);
p=(String)malloc(100);
 
也可定义结构体:
typedef structtnode {
    char * str;
    inty;
} Treenode;
typedef struct tnode * Treeptr;
 
定义函数指针:
typedef int (*PFI)(char *,char *);
该语名定义了类型PFI是“一个指向函数的指针,该函数具有两个char * 类型的参数,返回值类型为int”,定义后,可以这样使用:
PFI strcmp,numcmp;

联合体(union)

一个联合体变量可以合法地保存多种数据类型中任何一种类型的对象(同一时刻只能保存某一种),读取的类型必须是最近一次存入的类型:

可变参数

可以使用<stdarg.h>中的一组宏定义来操纵可参数。
 
VA_LIST的用法:     
(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针
(2)然后用VA_START宏初始化变量刚定义的VA_LIST变量,这个宏的第二个参数是第一个可变参数的前一个参数,是一个固定的参数。
(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型。
(4)最后用VA_END宏结束可变参数的获取。然后你就可以在函数里使用第二个参数了。如果函数有多个可变参数的,依次调用VA_ARG获取各个参数。
 
#include<stdio.h>
#include<stdarg.h>
/*求和*/
int sum(int first, ...) {
    int sum = 0, i = first;
    va_list marker;//定义一具VA_LIST型的变量,这个变量是指向参数的指针
    /*first一般表示可变参数列表中的前面最近第一个有名参数,如果前面有多个有
     * 名参数,即使这里指定为前面最近第二个有名参数,但可变参数列表还是从最
     * 后一个有名参数后面算起,对无名可变参数列表没有影响,但编译时会出警告,
     * 另外,参数列表中至少要有一个命名参数,如果连一个命名参数也没有,就无法使用可变参数*/
    va_start( marker, first ); /* 用VA_START宏初始化变量刚定义的VA_LIST变量,
                            这个宏的第二个参数是第一个可变参数的前一个参数,
                            是一个固定的参数。*/
 
    while (i != -1) {
       sum += i;
       i = va_arg( marker, int);//VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型。
    }
    va_end( marker ); /* VA_END宏结束可变参数的获取     */
    return sum;
}
 
main(void) {
    /* Call with 3 integers (-1 is used as terminator). */
    printf("sum is: %d\n", sum(2, 3, 4, -1));//9
    /* Call with 4 integers. */
    printf("sum is: %d\n", sum(5, 7, 9, 11, -1));//32
    /* Call with just -1 terminator. */
    printf("sum is: %d\n", sum(-1));//0
}
 

字符串操作函数

在头文件<string.h>中定义。在下面的各个函数中,s与t为char*类型,c与n为int类型。
strcat(s, t)                       将t指向的字符串连接到s指向的字符串的末尾
strncat(s, t, n)               将t指向的字符串中前n个字符连接到s指向的字符申的末尾
strcmp(s, t)                    根据s指向的字符串小于(s<t)、等于(s==t)或大于(s>t) t指向的字符串的不同情况,分别返回负整数、0、或正整数
strncmp(s, t, n)            同strcmp相同,但只在前n个字符中比较
strcpy(s, t)                      将t指向的字符串复制到s指向的位置
strncpy (s, t, n)            将t指向的字符串中前n个字符复制到s指向的位置
strlen(s)                          返回s指向的字符串的长度
strchr(s, c)                      在s指向的字符串中查找c,若找到,则返回指向它第一次出现的位置的指针,否则返回NULL
strrchr(s, c)                             在s指向的字符串中查找c,若找到,则返回指向它最后一次出现的位置的指针,否则返回NULL

字符测试和转换函数

头文件<ctype.h>中定义了一些用于字符侧试和转换的函数.在下面各个函数中,c是一个可表示为unsigned char类型或EOF的int对象。该函数的返回值类型为int。
isalpha(c)                                 若c是字母,则返回一个非0值,否则返回0
isupper(c)                               若c是大写字母,则返回一个非0值,否则返回0
islower(c)                                若c是小写字母,则返回一个非0值,否则返回0
isdigit(c)                                   若c是数字,则返回一个非0值,否则返回0
isalnum(c)                             若 isalpha(c)或isdigit(c),则返回一个非0值,否则返回0
isspace(c)                                         若c是空格、横向制表符(\t)、换行符(\n)、回车符(\r),换页(\f)符或纵向制表符(\v),则返回一个非0值,否则返回0
toupper(c)                                       返回c的大写形式
tolower(c)                              返回c的小写形式

数学函数

头文件<math.h>中声明了20多个数学函数。下面介绍一些常用的数学函数,每个函数带有一个或两个double类型的参数,并返回一个double类型的值。
exp (x)                                         指数函数ex
log (x)                                          x的自然对数(以e为底),其中,x>0
1og10(x)                                  x的常用对数(以10为底),其中,x>0
pow(x, y)                                             计算xy的值
sqrt(x)                                         x的平方根(x>=0)
fabs(x)                                                x的绝对值

随机函数

函数rand()生成介于0和RAND_MAX之间的伪随机整数序列。其中RAND_MAX是在头文件<stdlib.h>中定的符号常量。下面是一种生成大于等于0但小于1的随机浮点数的方法
    #define frand() ((double) rand() / (RAND_MAX+1.0))
(如果所用的函数库中已经提供了一个生成浮点随机数的函数,那么它可能比上面这个函数具有更好的统计学特性)
    函数srand(unsigned)设置rand函数的种子数。

存储管理函数(malloc/ calloc)

函数malloc和calloc用于动态地分配存储块。函数malloc的声明如下:
    void *malloc(size_t n)
当分配成功时,它返回一个指针,设指针指向。
 
    根据请求的对象类型,ma11oc或calloc函数返回的指针满足正确的对齐要求。下面的例子进行了类型转换:
    int *ip;
ip=(int *) calloc(n, sizeof(int))
 
    free(p)函数释放p指向的存储空间,其中,p是此前通过调用malloc或calloc函数得到的指针。存储空间的释放顺序没有什么限制,但是,如果释放一个不是通过调用malloc或callloc函数得到的指针所指向的存储空间,将是一个很严重的错误。
    使用己经释放的存储空间同样是错误的。下面所示的代码是一个很典型的错误代码段,它通过一个循环释放列表中的节点:
    for (p=head; p !=NULL; p=p->next)
        free(p);
正确的处理方法是,在释放节点之前先将一切必要的信息保存起来,如下所示
  for (p=head; p!=NULL; p=9){
        q= p->next;
        free(p);
  }
 
 

上一篇:maven管理多模块系统


下一篇:Android计时器实现