c和指针

一、数组

1. 初始化

  • 静态变量仅被初始化一次,当没有显式给出初始值时,编译器会自动将其初始化为0。静态变量在程序运行之前就已经被初始化。
  • 对于自动变量,由于被存放在堆栈中,所以执行六每次执行到其代码所在时都会为其分配不同的内存位置。所以编译器没有办法对其进行初始化,因此在没有给出显式初始值时,编译器不会对齐进行默认初始化。

由于数组进行初始化时,会进行多次幅值操作,所以在程序执行流多次执行到数组初始化语句时会对数组进行重新初始化,因此也会带来很多额外的开销。因此将数组声明成static,会带来更好的执行效率,只初始化一次数组。

  • 下标引用的优先级高于间接访问。

二、字符数组

1. 字符串处理

头文件: <string.h>

字符串处理函数:
  • strcpy:字符串拷贝,以NULL结束
  • strcmp:字符串比较
  • strlen :返回字符串长度(不包含NULL),返回类型为size_t(unsigned int),定义在<stddef.h>
  • strcat:字符串拼接函数
字符串查找函数
  • strchr/strrchr:查找字符串中某个字符第一次或最后一次出现的位置(地址)
  • strstr:查找字符串中另一个字符串第一次出现的位置
  • strpbrk:在一个字符串中查找指定字符串中任意字符第一次出现的位置。
  • strspn/strcpsn:计算一个字符串的起始部分(不)匹配一个指定字符集中任意字符的字符数量。
  • strtok:把一个字符串分割成几个标记。每次当它调用时,都返回一个指向字符串中下一个标记位置的指针。这些标记由一个指定的字符集的一个或多个字符分割。
#include <stdio.h>
#include <string.h>

int main(int agrc, char* argv[])
{
    char token[] = "\t\n";
    char source[] = "cui\ttengju";
    char *t = NULL;

    for (t=strtok(source,token); t!=NULL; t= strtok(NULL,token))
    {
        printf("%s\n", t);
    }

    return 0;
}

2.字符处理函数

头文件:
<ctype.h>

字符检测函数
  • iscntrl
  • isdigit
  • isxdigit
  • isalpha
  • isprint
  • isspace
  • islower
  • isupper
  • isalnum:是否为字母或数字
  • ispunt:是否为标点符号
字符转换函数
  • tolower
  • toupper

三、 结构和联合体

1. 结构

结构可以将不同类型的变量存储在一起。这些不同类型的变量成称为结构体成员。

结构体声明

结构体的声明列出了结构包含的成员列表。不同的结构体声明,即使他们的成员完全相同也是不同的结构体类型。如果希望在不同的位置声明相同结构类型的结构体变量可以使用结构标签,结构标签与成员列表相关联。采用结构标签进行结构体声明,就不用重复声明。

struct tag{
    int a;
    double d;
};  //声明结构体

struct tag A;  //定义结构体变量

typedef同样可以实现上述目标

typedef struct{
    int a;
    double d;
}SIMPLE;

SIMPLE A; //定义结构体变量

结构体中不能包含自身的引用,即不能包含本身。但是可以包含指向自身结构体的指针

结构体的边界对齐

为了提高存取结构体类型的效率,编译器会对结构体成员进行字节对齐处理。
位于<stddef.h>中的offsetof(sturct tag , d)可以获取结构体成员相对结构体起始位置的偏移位置。返回值为size_t(unsigned int)
为了节省内存空间,我们可以在编程时,将对于边界对齐敏感的成员放到结构体开始的位置。可以一定程度节省内存开销。

结构体作为函数参数

由于函数调用,其参数采用传值方式。所以为了提高函数的效应效率,建议当结构体作为函数参数时,尽量采取传址方式
传址方式的一个缺点就是函数中可以通过结构体地址修改原结构体中的成员,为了避免这种情况的发生,可以将形参声明为const

2. 联合体

联合体的声明与结构类似,但它其中的谁有成员共用一块内存。
对于联合体的初始化,必须是联合体的第一个成员类型。如果给出的初始值不是第一个成员的类型,也会被转化成一个成员的数据类型。

四、函数指针

函数指针主要有两种用途:1.转换表(函数指针数组);2.最为函数的参数

double add(double,double);
double sub(double,double);
double mul(double,double);
double div(double,double);

double (*oper_func[])(double,double); //函数指针数字

double ret = oper_func[0](a,b);  //引用,转换表的实现
  1. 对函数指针进行间接访问之前需要对齐进行初始化。
  2. 对函数进行初始化之前,其初始值的函数原型必须已经声明,否者编译器无法检测函数指针与初始值的类型一致性。
  3. 对函数指针的初始化可以采取赋值操作。例如:
int f(int);
int (*pf)(int) = f;  //函数名总是被编译器转换成函数函数指针

//或者
int (*pf)(int) = &f;
  1. 对函数的使用我们可以采取2种方式,例如:
1. int ret = pf(25);
2. int ret = (*pf)(25);

五、字符串常量

当一个字符串常量出现在表达式中时,它的值是一个指针常量。编译器会把这些指定的字符的一份拷贝存储在内存的某个位置,并存储一个指向第一个字符的指针。

printf("%c\n",*("xyz"+1));  //结果'y'
printf("%c\n",*("xyz"));  //结果为'x'

printf("%c\n","xyz[2]");  //结果为'z'

六、文件流操作

/*打开特定的文件,并把一个流与该文件相关联*/
FILE *fopen(char const *name, char const *mode); //成功返回指向FILE结构的指针;失败返回NULL

始终检查fopen函数的返回值。任何可能错误的操作都要进行检测


类型 读取 写入 追加
文本 r w a
二进制 rb wb ab
  1. 如果一个文件用于读取,则它之前必须已经存在。
  2. 如果一个文件用于写入,当它不存在时将被创建;当它已经存在时,之前存在的内容将被删除。
  3. 如果一个文件用于追加写入,当它不存在时将被创建;当它已经存在时将会在其原内容之后追加新的内容。

如果mode的值为"a+",那么打开该文件,是为了更新该文件的内容,且允许读写操作。如果在向其写入数据之前,已经从该文件中读取了一部分数据,此时需要程序员使用函数fflush或文件定位函数重新定位文件指针的位置,然后进行写入操作。读取操作亦如此。

/*关闭文件流*/
int fclose(FILE *f); //对于输出流,关闭文件流之前会刷新缓冲区。函数执行成功返回0,否者返回EOF

字符I/O

1. 字符输入
int fgetc(FILE *stream);
int getc(FILE *stream); //fgetc,getc缺省状态下,作用于stdin
int getchar(void);  //只作用于stdin。每个函数从流中读取下一个字符,并将其作为函数的返回值。如果流中不存在更多的字符,返回EOF。之所以返回值定义为int,正式因为EOF的实际值比一个字符要多几位,EOF被定义为整型。
2. 字符输出
int fputc(int character, FILE *stream); 
int putc(int character, FILE *stream);
int putchar(int character); //只作用于stdout。打印之前会将整型参数裁剪为unsigned char。当写入到未打开的stream,返回EOF。

fgetcfputc都是函数,而getc/putc/getchar/putchar都是通过#define指令定义的宏。宏在执行效率上稍高,但是函数在程序长度方面更胜一筹。

3. 字符的撤销
int ungetc(int character, FILE* stream); //把一个先前读入的字符返回到流中,这样它可以在以后被重新腐乳。
4. 字符串的处理
char *fets(char *buffer,int buffer_size, FILE *stream);//最多读取buffer_size-1个字符,但流中的字符并不会丢失,下一次fgets会从下一个字符开始读取。任何情况下,buffer都是以'\0'结尾。如果在未读取任何字符之前,流已经到达文件尾,那么fets返回NULL,否者返回buffer。
char *gets(char *buffer); //只作用于stdin。读入字符串时,并不会在缓存区中存储结尾的换行符。


char *fputs(char const *buffer, FILE *stream);//写入过程中出现错误返回EOF,否者返回非负数。
char *puts(char const *buffer); //只作用于stdout。会在输出字符串之后再添加一个换行符。

由于gets函数并没有指定缓存区的长度,所以难免会出现缓存区溢出的问题,所以不建议使用该函数。


5. 格式化字符串处理

格式化输入

int fscanf(FILE *stream, char const *format, ...); //从输入流中读取字符并根据format字符串将其转换。当格式化字符串到达末尾或读取的字符不在匹配格式化字符串指定的类型时,输入结束。函数返回被转换的输入值的数目,如果没有输入值被转换,则返回EOF。

//后两者与fscanf唯一的不同就是输入源的不同。
int scanf(char const *format,...); //输入源为stdin
int sscanf(char const *string, char const *format, ...); //输入源为给定的字符串。

格式化输出

int fprintf(FILE *stream,char const *format,...);
int printf(char const *format,...);
int sprintf(char *buffer,char const *format);//sprintf可以将它的结果作为一个NULL结尾的字符串存储在指定的buffer缓存区中,而不是写入到流中。
6. 二进制I/O
size_t fread(void *buffer, size_t size,size_t count,FILE *stream); //用于读取二进制数据

size_t fwrite(void *buffer, size_t size,size_t count,FILE *stream); //用于写入二进制数据

//buffer是一个指向保存数据的内存位置的指针;size是缓冲区中每个元素的字节数;count是读取或写入的元素数;stream是数据读取或写入的流。函数的返回值时实际读取或写入的元素的个数。
7. 刷新或定位文件指针
int fflush(FILE *stream); //迫使一个输出流的缓存区内的数据进行物理写入,无论缓存区是否已经写满。

当我们需要将缓存区的数据立即进行物理写入时,可以使用fflush

long ftell(FILE *stream); //返回流的当前位置,也就是下一次操作流的开始位置相对于文件起始位置的偏移量。

int fseek(FILE *stream, long offset, int from); //设置下一次流操作的位置

|form|说明|
|-|-|-|
|SEEK_SET|从流的起始位置offset个字节,offset必须是一个非负值|
|SEET_CUR|从流的当前位置起offset个字节,offset的值可正可负|
|SEET_END|从流的尾部位置起offset个字节,offset的值可正可负。如果是正值,定位到文件尾的后面|

int feof(FILE *stream); //如果流当前处于文件尾,该函数返回真。

七、标准库函数

1. 整型函数

随机数<stdlib.h>:

  • int rand(void); 产生一个介于0 ~ RAND_MAX之间的伪随机数。
  • void srand(unsigned int seed); 为了避免每次运行获取相同的随机数,我们可以调用srand函数初始化随机说发生器。一个常用的技巧即使使用时间作为随机数差生的seed
    例如:
srand((unsigned int)time(0)); //以时间为种子初始化随机数发生器
rand(); //产生随机数

字符串转换<stdlib.h>
忽略前导空白字符

int atoi(char const *string);
long atol(char const *string);//基数为10

long strtol(char const *string, char **unused, int base);
unsigned long strtoul(char const *string, char **unused, int base);// unused保存不能被转换的第一个字符的指针的地址

//如果这些函数中不含有合法的数值,函数将返回0;

//字符串到浮点数的转换
double atof(char const *string);
double strtod(char const *string, char **unused);

例:

#include <stdio.h>
#include <stdlib.h>

int main(int argc,char **argv)
{
    char name[10] ="  32cui";
    char *unused = NULL ;
    long res = strtol(name,&unused,10);
    puts(unused);
    return EXIT_SUCCESS;
}
执行结果

浮点型函数<math.h>

  • double sqrt(double x);
  • double exp(double x );
  • double log(double x); 以e为底
  • double log10(double x);
  • double pow(double x,double y); 幂函数
  • double ceil(double x); 返回不小于参数的最小整数
  • double floor(double x); 返回不大于其参数的最大整数
  • double fmod(double x,double y); 返回余数,该函数的商被限定为整数

日期和时间函数<time.h>

clock_t clock(void); //函数返回从程序开始执行到目前为止处理器所消耗的时间(近似值);返回值为处理器时钟的滴答次数,可以通过乘以CLOCKS_PER_SEC将其转换为秒。

time_t time(time_t *returned_value); //返回当前日期和时间(从1970/1/1至今流逝的秒数),失败返回-1。

//time_t处理
char *ctime(time_t const *time_vlalue); //处理time_t变量,将其时间进行格式化返回。
double difftime(time_t time1, time_t time2); //计算两者的差值,并将其转换为秒。

//time_t --> tm结构
struct tm *gmtime(time_t const *time_value);  //转化为世界协调时间/UTC/格林尼日标准时间
struct tm *localtime(time_t const *time_value); //转换为当地时间

//tm结构 ——> time_t
time_t mktime(struct tm *tm_ptr);
tm结构字段
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容