C语言 深入学习
浮点数:
sizeof是运算符(而非函数),在编译时执行,不会导致额外的运行时间开销。
三元运算符:是右结合运算。
数据类型:
char:占1个字节
short:占2个字节
int:占4个字节
float:占4个字节
double:占8个字节 一个变量本身定义为常量const时,必须初始化
常量指针:不能通过常量指针修改其指向的值(只是从p的角度来看)。
const int *p;
int const *p;
指针常量:指针其本身就是常量(故定义时须初始化),而且也不能通过这个指针修改其指向:
int * const p = &a; 数组指针(指向一维数组的指针 / 行指针):char (*p)[] —— 打括号就是说,先看括号里面的。故可以这样理解:
举例, 二维数组char a[][], char (*p)[];p = a。
首先确定,char (*p)[]只是将p定义为一个指针(其作用是指向某个数组整体,而不是这个数组中的某个元素);10就是指定了指向的数组的长度
p = a就让p指向了a[]这个数组;于是p++,就让p指向了下一个数组a[];
所以若p = a,那么*p就是获得a[]这个数组。
既然char (*p)[]是指向数组的指针,那么通用的使用就是:把数组的地址给p,即char (*p)[];char s[]="abcd";p=&s;
而二维数组a[][]的数组名a的含义是:a == &a[]; 指针数组(数组元素是数组):char *p[] —— 没有括号,所以可以这样看:这是一个数组,其元素类型是char *p。这里是一个放了10个指针的数组。所以p[]=arrary;是指向数组首元素,而不是整个数组
标准输入输出格式:
当数据的实际位宽大于printf中的指定位宽时,将按照数据的实际位宽输出数据。
//输出
printf("%ld\n", test); /* 以长整型格式输出 */
printf("%f\n", test); //输出单双精度浮点数
printf("%4.2f\n", test); //输出数据共占4位(包括小数点),有2位小数;其他数据类型也是如此(自然有些是没有小数的)
printf("%u", n); //n是unsigned int
printf("%s\n", str); //输出一个字符串
printf("%p\n, p); //输出地址 //输入
/*scanf:返回值为成功接收到的、输入的变量值个数。
如scanf("%d%d%d",i,j,k,a,b)则只能返回3(因为只能接收三个)*/
char *str = (char *)malloc(N * sizeof(char)); scanf("%s", str); //输入一个字符串
scanf("%lf", &test); //输入双精度浮点数
scanf("%d,%d", &a, &b); //输入必须与指定的格式相同。比如这里有",",那么在Console中输入也需要","
随机数:
//#include <stdlib.h>:rand、srand
//#include <time.h>:time
srand();
printf("%d\n", rand()); //rand对应于srand,只要srand的种子不变,rand的随机值也不会变;rand的范围是0 - int
srand(time(NULL)); //srand(unsigned)
printf("%d\n", rand()); //time函数返回当前时间(秒);参数param如果不为BULL,则time会将时间赋给param。故这样一来随机数就会一直改变(真正实现随机)
printf("%d\n", rand() % + ); //生成1-100的随机数:rand() % 100是0-99
指数函数:
pow(x, y) //表示x的y次方 —— math.h
数组:
初始化:
int count[] = {}; //长度为10的数组,全都初始化为0;定义数组时,数组长度只能是常量,不能是变量或含变量的表达式
二维数组:
多维数组在内存中实际上都是一维存储的。例如二维数组,我们只是在逻辑上可以理解为二维的矩阵,但实际上二维数组是一维数组,每个元素还是一维数组,所以整个二维数组都是"一条线"
1、因此int a[3][3]={1...9};int (*p)[3] = a;此时不仅可以*(*p+2),还可以*(*p+8)=*(*(p+2)+2),只要不越二维数组的界(这里是9);
简单点就是:int a[3][3] = {1...9};int *p = &a[0][0];此时可以从头指到尾:头是*p,尾是*(p+8);
2、所以二维数组a有m行n列,则在a[i][j]之前的元素个数为i * n + j —— 因为a[i][j]是第i + 1行,第j + 1列,而前i行都是在a[i][j]之前的
求数组大小:
char s[][] = { "first", "second", "Third" };
char (*p)[] = s;
printf("%d %d\n", sizeof(s) / , sizeof(p)); //3、4:因为p要找"\0",即'\0' —— {"...", "...", "...", "\0"}
//用指针数组
char *p[] = {"How", "are", "you"};
printf("%d\n", sizeof(p) / sizeof(char *));
函数:
函数返回值:
printf("%d\n", func(-)); //main函数 int func(int i)
{
if (i == )
{
return i;
}
else
{
printf("h\n"); //这种情况,会返回printf输出的字符个数(包括转义符):此时return 2
}
}
数组作为函数参数,形参数组与实参数组实际上是同一个数组,即传址调用;数组作为实参,只需要写数组名(无论是几维数组)。
变量的生命周期与作用域:
#include <stdio.h> void Incre(); int main()
{
Incre();
Incre();
return ;
} void Incre()
{
static int x = ; //静态:第二次就输出上次,保存的x的值;此外这还是一个局部var,因此作用域还是Incre
printf("%d\n", ++x);
}
字符串:
字符常量与字符串常量的区别:
- 字符串常量:1、字符串里面包含的字符是连续存储的。2、每个字符串都有结束标记("\0"),这是一个特殊的字符,即ASCII码为0的字符。3、C语言用字符数组(没有字符串变量)来动态存储字符串,例如char s[10] = {'a', 'b', '\0'}是一个字符串,而char s[10] = {'a', 'b'}不是。或者写为char s[] = "abc"(在初始化的情况下可以省略数组大小)。存储多个字符串(用二维数组):char s[][10] = {"星期一", "星期二"}(第一个大小可省略,由字符串的个数,即二维数组中包含数组的个数决定)。
- 字符常量:char s = 'a'。
用指针来访问字符串:
#include <stdio.h> int main()
{
char *p = NULL;
char s[] = "abc";
p = s; //反过来就不行了,因为数组名相当于是一个指针常量
printf("%c\n", *p); //现在只是指向字符串的第一个字符
//printf("%s\n", *p); //这样是不行的,应该是printf("%s\n", p);输出的是这个指针指向字符串的某个字符以及后面剩下的字符,所以p在此时可以用s替代
return ;
}
输入输出字符串:
char s[] = "adjshd";
char s1[] = "casn";char *p = s;
char *p1 = s1;
gets(p); //可以输入空格
puts(p);
scanf("%s", p1);
printf("%s\n", p1);
但是gets是存在安全隐患的(它没有限制输入的大小,即输入可能超出字符数组的大小,此时就可能把输入存到了指定的字符数组之外的地方):
char s2[] = "sdfjhasjd";
char *p2 = s2;
char n = ;
//fgets限制输入的长度
fgets(p2, n, stdin); //最多只能接收n - 1个字符
puts(p2);
getchar函数:
用处1:
#include <stdio.h>
#include <math.h> int main()
{
int n = ;
char c = 'c';
int result = scanf("%d", &n);
if(result != ) //输入与scanf指定的类型不符,则不能接收到。未能成功接收的字符会暂时放在缓冲区
{
c = getchar(); //此时getchar就是将缓冲区的字符一次取走一个,并返回
}
printf("%d %c\n", n, c);
return ;
}
用处2:
#include <stdio.h>
#include <math.h> int main()
{
char c = 'c';
//getchar直接从stdin读取一个字符,putchar从stdout输出
c = getchar();
putchar(c);
return ;
}
字符串处理函数:
//需要#include <string.h> -- 字符串处理函数strcmp、strlen、strcpy、strcat
strcmp(s1, s2); //两个字符串自左向右,逐个字符相比(比较ASCII码),直到出现不同字符或'\0'为止,此时若:s1==s2;return 0;s1 > s2;return 1;否则return -1.
strlen(s1); //返回字符串s1的长度,例如:char s1[10] = "abcde";printf("返回字符串的长度:%d,返回数组的长度%d\n", strlen(s), sizeof(s));
char source[] = "hello kit";char destination[] = "world";
puts(strcpy(destination, source));puts(destination);//source->destinations
char source[] = "hello kit";char destination[] = "world";
puts(strcat(destination, source));puts(destination);//即destination + source
函数库:
字符处理函数#include <ctype.h>:
函数的参数皆为int,返回也为int
int isdigit(int c); //判断是否为数字字符,例如:如果是'3',return 1;是'a',return 0;
int toupper(int c); 实用函数#include <stdlib.h>
double atoi(const char *s);
double atof(const char *s); //例如:
//printf("%6.2f\n", atof("1e2"));输出:100.00——还要算上小数点
//printf("%6.2f\n", atof("y3")); 输出: 0.00;就算是e3也不会当成是科学计数,而是和y3一样
枚举类型:
#include <stdio.h> int main()
{
//定义枚举类型,集合{}中的元素,是枚举元素 —— 供枚举变量进行选择
//枚举元素的值:如果没有指定具体值,编译器会把第一个元素处理成0,后面元素以此+1:因此枚举元素是常量
//当然也可以自定义枚举元素的值:例如指定Tuesday = 100,那么Wednesday也遵循+1的原则,因此Wednesday = 101
enum Date { Monday, Tuesday, Wednesday };
//定义枚举变量
//1、直接在定义类型时,顺便把变量定义了
//enum Date { Monday, Tuesday, Wednesday } date;
//2、或者只定义变量
//enum { Monday, Tuesday, Wednesday } date;
//枚举变量选择具体的枚举值
enum Date date = Tuesday;
date = Wednesday;
printf("%d\n", date);
return ;
}
联合union:
编译器处理union时,一个union所有成员共用同一段内存空间(同一时刻,只有一个成员使用内存空间,存放成员值),因此内存空间的大小=最长的成员大小。具体使用如下:
#include <stdio.h>
int main()
{
union
{
int i[];
int k;
int c;
} t, *s = &t;
//给哪个成员赋值,内存空间就被这个成员使用
s->i[] = ;
s->i[] = ;
printf("%d\n", s->c); s->k=;
printf("%d\n", s->c); s->c = ;
printf("%d\n", s->c);
printf("%d\n", s->i[]);//始终为20
return ;
}
使用联合的一些注意事项:
1、联合不能作为函数参数传递。2、不能整体初始化或者整体赋值,只能对其成员一个一个赋值。3、不能作为函数返回值。
结构体:
#include <stdio.h> typedef struct student
{
int number;
char name[];
char sex;
} S;//此时S是别名
struct
{
int year;
int month;
int day;
} birth;//此时birth是结构体变量 int main()
{
S s;
s.number = ;
birth.year = ;
printf("%d %d\n", birth.year, s.number);
return ;
}
文件操作:
<stdio.h>中的一些变量类型、宏定义:
- 文件结束符:#define EOF (-1)
- 存储文件流信息的类型:typedef struct _iobuf FILE;
- 类型的大小,即sizeof运算符的结果:typedef unsigned int size_t;
打开已存在文件、或新建一个文件:
函数原型:FILE *fopen(const char *filename, const char *mode);//用FILE的指针变量操纵文件
根据打开模式(mode)的不同决定:新建或打开文件
、文本文件:
mode的值:r(打开已有文件,只读)、w(打开文件,只写、覆盖写入,即打开后删除原有内容,重新写入。若文件不存在,则新建)、a(打开文件,只写、追加写入。若文件不存在,则新建)
可读写:r+(打开已有文件,覆盖写入)、w+(新建文件)、a+(打开文件。若文件不存在,则新建。写:追加写入)
、二进制文件mode:形如ab、ab+
=>每次读写都会从文件游标开始读(第一次读,游标在文件开头),游标属于fp指向的 FILE 变量:因此,对于同一个FILE变量,fgetc的调用也会影响到fgets的读取位置
清空缓冲区数据,并关闭文件:
函数原型:int fclose(FILE *fp);
成功关闭,释放掉文件占用的内存,return ;发生错误,return EOF(常量,在stdio.h中定义);
写入文件:
写入一个字符:int fputc(int c, FILE *fp);
如果成功,return 刚写入的c;如果失败,return EOF;
写入一个字符串:int fputs(const char *s, FILE *fp);
如果成功,return 一个非负值;失败,return EOF;
格式化写入文件:
//与fputs同理,函数原型:int fprintf(FILE *fp, const char *formatSting, ...);
//像printf一样,接受可变长参数,如:
fprintf(fp, "%d != %d\n", , );//即写入1 != 2
读取文件:
//与写入同理:int fgetc(FILE *fp)
printf("%c\n", fgetc(fp));
fgetc(fp);//每调用一次,读取文件的游标,就会向后移动一个char
printf("%c\n", fgetc(fp));
//读取字符串:char *fgets(char *buf, int n, FILE *fp);
//读取n - 1个字符。并将读取到的字符串,复制到字符串变量buf中,最后以\0结束 —— buf的长度应不少于n
//返回的字符串与buf的值相等
char str[];
char *buf = str;
printf("%s\n", fgets(buf, , fp));//如果还未读取n个char,就遇到了\n或者EOF,则直接结束本次读取(包含\n)
直接读取一个单词(从游标开始,到遇到的第一个空格为止,认为是一个单词;游标是读到了这个空格的,因此调用下面的函数后,游标指向这个空格之后):
char buff[];
//与fprintf不同:%s作为sourceString(不加修饰),buff作为destString
fscanf(fp, "%s", buff);
fscanf(fp, "%s", buff);
printf("%s\n", buff);//读到第二个单词
检测当前游标是否指向文件结尾(EOF):
int feof(FILE *fp);//文件结束,return 1;否则return 0;
C语言 深入学习的更多相关文章
- C语言课程学习的总结
C语言课程学习的总结 学习C程序这门课一年了,这是我们学的第一门专业课.在大学里,C语言不但是计算机专业的必修课程而且也是非计算机专业学习计算机基础的一门必修课程.所以作为我这个计算机专业的学生来说当 ...
- [转]C语言指针学习经验总结浅谈
指针是C语言的难点和重点,但指针也是C语言的灵魂 . 这篇C语言指针学习经验总结主要是我入职以来学习C指针过程中的点滴记录.文档里面就不重复书上说得很清楚的概念性东西,只把一些说得不清楚或理解起来比较 ...
- C语言(函数)学习之strstr strcasestr
C语言(函数)学习之[strstr]&[strcasestr]一.strstr函数使用[1]函数原型char*strstr(constchar*haystack,constchar*needl ...
- 【Go语言】学习资料
这段时间一直在看Go语言,6月3日Apple发布了swift发现里面竟然也有许多Go语言的影子,截至现在每天都在感觉到Go语言的强大.确实值得一学 今天在这里给园友们推荐一些Go语言的学习资料 网站 ...
- 远离go path,弃用go get,使用go mod 进行go语言的学习
标题说的是go语言的学习,因为我也没做过开发 文章要解决的仅仅是一个问题 当你使用go get 无论如何get不到所需的包的问题 第一步就是下载goland 新手极其推荐goland,因为直接使用gl ...
- Dart语言快速学习上手(新手上路)
Dart语言快速学习上手(新手上路) // 声明返回值 int add(int a, int b) { return a + b; } // 不声明返回值 add2(int a, int b) { r ...
- D02-R语言基础学习
R语言基础学习——D02 20190423内容纲要: 1.前言 2.向量操作 (1)常规操作 (2)不定长向量计算 (3)序列 (4)向量的删除与保留 3.列表详解 (1)列表的索引 (2)列表得元素 ...
- D01-R语言基础学习
R语言基础学习——D01 20190410内容纲要: 1.R的下载与安装 2.R包的安装与使用方法 (1)查看已安装的包 (2)查看是否安装过包 (3)安装包 (4)更新包 3.结果的重用 4.R处理 ...
- C++语言的学习环境
一.Mac C++语言的学习环境 1. 1.1.C语言 :终端->bash-vi/vim文本编辑器->GNU->GCC文件编译器->a.out可执行文件 1.2.C++语言:终 ...
- 获奖感言和C语言的学习心得
获奖感言和C语言的学习心得 自我介绍: 大家好,我的名字叫袁忠,我来自湖南,今年快19岁了,现在是大学一年级,我平时喜欢跑步.打羽毛球,我也喜欢学算法与数学,以及喜欢看一些与计算机有关的书籍,每次我学 ...
随机推荐
- vue之vue-cookies安装和使用说明
vue之vue-cookies安装和使用说明npm官方链接:https://www.npmjs.com/package/vue-cookies 安装,在对应项目根目录下执行:npm install v ...
- web前端利用turf.js生成等值线、等值面
样例如下: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> ...
- POJ 2492 A Bug's Life (并查集)
Background Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes ...
- 关于字符串split一些用法
split方法在大数据开发中的多用于日志解析及字段key值分割,最近需求中碰到一个问题在 无论怎么分割都会出现数组下标越界问题, 由于前台在sdk中多加了几个字段(测试数据很少,大多为空) ,需要我们 ...
- 怎样从外网访问内网Node.js?
本地安装了一个Node.js,只能在局域网内访问,怎样从外网也能访问到本地的Node.js呢?本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Node.js 默认安装的Node.js端口 ...
- priority todo
analyze the work about change to right spindle
- JavaScript笔记 #08# 用Regex辅助生成文章目录 V2.0
索引 简介 测试用例 代码 简介 * 用Regex辅助生成文章目录 2.0 * 1.提高了功能的通用性(假定的文章格式更加普遍,即按照h2h3h4分级) * 2.改善了代码的可读性(稍微牺牲了一点点性 ...
- shell脚本一键安装redis
支持识别离线包和联网安装,自动修改使用后台运行模式,离线安装的方法是,将离线包和脚本放在同一个文件夹, 它会先识别有没有离线包, 有离线包就先安装离线包, 没有离线包就安装进行判断机器是否能联网, 能 ...
- MongoDB入门一
一.环境配置 1.下载MongoDB,找到Bin目录下所有的.exe文件,拷贝到G盘MongoDB(新建)下,在MongoDB下建一个data文件,用于存放数据,创建一个logs文件夹,文件夹下创建一 ...
- 跟阿铭学Linux习题答案
第一章:走进Linux 1.简述它的发展历史,列举几种代表性的发行版 Linux之前是Unix,由于Unix收费昂贵,so,Richard Stallman 发起了开发自由软件的运动,并成立了自由软件 ...