C语言学习笔记

冒泡排序没有查找的步骤,而是不断前后交换,做n次

选择排序是先找到目前最大的元素排到后方

插入排序类似于扑克的整理手牌


fabs()是绝对值函数

for(,,)是个死循环

switch()的括号里可以是变量;case后可以是1+1,a

n=z也是表达式,计算结果是n

%的前后都要是整数,结果的符号与左值相同 /则无要求,当两边都是整形时,结构也是整形

对正数来说,补码就是源码;对负数来说,补码是源码的首位符号码不变,剩下所有位数取反,最后再加一

当变量发生上溢时,会被赋一个表示无穷大的特定值

字符宽度包括整数部分、小数部分和小数点

若要输出对象的实际宽度大于指定宽度,会无视要求全部输出

%20.2d 表示输出一个小数点后有2位的十进制数,打印宽度为20

%010.2f 第一个0表示用0填充以满足字段宽度要求,10表示字段宽度,2表示小数点后有2个数字,f表示打印一个浮点数

(double)1/2的值是0.500000,实际是1.0/2

getchar()有时用来吸收回车字符,返回类型是int

putchar()返回类型是int,返回-1表示输出失败

getche()读取一个字符后无需回车马上输入,有回显

getch()读取一个字符后无需回车马上输入,无回显

gets()在读取字符串时不会遇空格停止,只有按下回车才读取完成,与scanf("%s",a)不同

%d:十进制    %o:八进制    %x:十六进制    %#o:带前缀地打印八进制    %#x:带前缀地打印十六进制

%lf仅用于十进制输入double,输出double用%f

%e用指数计数法打印浮点数;%g会自动选择%f或%e打印浮点数,会去除浮点数后面多余的0

sizeof(a)以字节为单位给出a的大小,返回类型是size_t,对应的是%zd

符号常量尽量大写

短路:逻辑运算时,若左侧已能决定结果,则右侧不会进行运算,例:a=-1,  a>0&&a++>-1  之后a仍是-1

欧几里得算法(求最大公约数) int a,b;  a%b=d  a=b,b=d  当余数为0是,b就是最大公约数

自定义函数若写成int a(),则是告诉编译器我也不知道参数具体情况;若无参数应写成int a(void)

,也是运算符,结果值为右侧的值;但更多情况下只是个标点符号

一个函数中不能放另外一个函数的body,仅能放声明(函数头)

若int a[ ] = { [0] = 1, [2] = 5,6 };则a[0] = 1, a[2] = 5, a[3] = 6,其他值都是0

数组变量其实是const的指针,所以不能被赋值,例:int a[ ],b[ ]; b = a; 就不合法

scanf("%7s",a)限制了最多读取7个字符,且不再遇空格即停止;剩下的部分会自动给下一次scanf

Tab键不是输出4个空格,而是把光标移到固定的下一个预定位置

\n是换行       \r是回车

函数指针:int (*a)()

数组指针:char(*a)[5]   指针a指向一个长度为5的字符数组,*a等同于数组的首地址,**a等同于数组的第一个值,a+1则是把地址后移20(4*5)

两个相邻的字符串会自动串起来

char *s = "hello,world"; s[0] = 'B'就非法。因为这时s的定义其实是const  char *s,被放入一个只读的地方(代码段),无法修改。而且如果有chart *s2 = "hello,world",则s与s2指向一个地方,因为是先在内存中有一个"hello,world",再让指针指向它

所以如果要一个能修改的字符串就要用数组,如果无需修改就用指针

取地址符&带出的结果不一定与int大小相同,所以最好用%p,而不是%x

char *s,这时scanf("%s",s)是非法的

printf("%f",2)会打印出0.000000

const在*之后:指针是const,不能再指向其他变量,int *const q=&a;

const在*之前:指针与变量都可以变,只是无法通过指针修改变量,const int *p=&a;

void f(const int *p)的意义是函数保证不会修改地址p对应的值

const int a[]={1,2,3,4};  //数组本身就是const的指针,这里的意义是让数组的每一位都变成const

*p++ , ++的优先级比*高,意义是先取出p对应的值,再把p移到下一个位置

指针可以比较大小,比较的是值,即所指变量地址的大小

0地址用处:1.函数返回0地址,表示失败、拒绝    2.初始化时指向0,等于未真正初始化,因为0地址不能访问,所以帮助后面排查问题

int *a与char *b大小相同,但不能相互赋值

void *表示不关心所指对象的类型,可以得到int *的值,但此时通过void *访问int对象,编译器就不会在意它是int了

%s输出__func__(预定义宏)会显示当前函数名,如"main"

文本文件(ASCII文件)中,每一个显示的字符都单独占空间用ASCII表示,二进制文件则会依据实际内容决定空间


优先级:

1. ()

2. ! + - ++ --

3. *  /  %

4. + -

5. <<    >>

6. <  >  <=  >=

7. ==   !=

8. ^      9. &     10. |

11. &&    12.||

13. ?  :

14. = += -= *= /= %=

15. ,


二分查找:

int search(int s[],int n,int k)
{
    int bottom=0,top=n-1,mid;
    while(bottom<=top)
    {
        mid=(top+bottom)/2;
        if(k<s[mid]) top=mid-1;
        else if(k>s[mid]) bottom=mid+1;
        else return mid;
    }
    return -1;
}

判断素数:

int prime(int n)
{
    for(int t=2;i<=(int)sqrt(n);i++)
    {
        if(n%i==0) return 0;
    }
    return 1;
}

八进制字符串转换为十进制整数:

int change(char s[])
{
    int i,n;
    i=n=0;
    s[i]=='0'?i+=1:i;
    for(;s[i]!='\0';i++)
    {
        if(s[i]>='0'&&s[i]<='7')
        n=n*8+s[i]-'0';
    }
    return n;
}

 冒泡排序:

void sort(int a[],int n)
{
    int flag=1;
    int gj;
    for(int i=0;flag&&i<n-1;i++)
    {
        flag=0;
        for(int j=0;j<n-i-1;j++)
        {
            if(a[j]>a[j+1])
            {
                gj=a[j],a[j]=a[j+1];a[j+1]=gj;
                flag=1;   //注意flag
            }
        }
    }
}

字符串函数:

strcat(a,b);          //把b拷贝到a后面,形成一个大字符串,但a必须要有足够的空间,返回值为a
//所以strcpy与strcat都可能会出现没有足够空间的情况,不够安全,不推荐用
//安全版本:strncpy,strncat

strncmp(a[],b[],t);   //只比较前t个字符的大小

char * strchr(const char*s,int c);   //是查找函数,从左往右查找字符c第一次出现的位置
//从右往左查找的版本是strrchr,如果没有找到会返回NULL\
利用strchr查找字符c第二次出现的位置:
char str[]="hello";
char *p=strchr(s,'l');
p=strchr(p+1,'l');

strstr(a[],b[]);      //在字符串中查找字符串。返回指针
strcasestr(a[],b[]);  //不计大小写地查找

enum:枚举

enum 枚举类型名字{名字0,名字1,名字n};
//枚举类型名字通常无用,有用的是大括号里的名字,它们是常量符号,类型是int,值依次为0,1,2...
enum:color{Red,Blue,Yellow};    //color此时与int平等,但使用时前面要加enum
enum color t=Red;   //t=o
scanf("%d",&t);     //enum实际就是int,所以可以用%d
//套路:enum color{A,B,C,number of color};   
//这时number of color就自动棒我们计数前面的元素个数了
enum color{Red=1,Yellow,Green=5};   //也合法,Red=1,Yellow=2,Green=5

结构类型:

struct date{int month;int day;int tear;};   //声明结构类型
struct date today;  //定义一个date类型的变量today
//如果struct声明在一个函数内,则这个自定义结构类型只能在该函数内使用
第二种声明方法: struct {int month;int day;} today1,today2;   
//today1与today2没有类型名,但可以正常使用
第三种声明方法: struct date {int month;int day;} today1,today2;
//声明后立即创建变量

结构变量初始化:
struct date{int month;int day;int tear;} today;
struct date today = {07,31,2014};
struct date thismonth = {.month=7, .year=2014};  // /day默认为0

结构变量辅助:
point_a = (struct point){5,10};  //之后point_a.x=5,point_a.y=10

结构指针:
(*p).month=12  等价于   p->month

typedef与结构类型:
typedef struct{int a,int b} Date;   //之后这个类型可以直接写Date,无需struct关键字
// typedef 旧 新

联合:

union {int i;char c;}elt1,elt2;
//所有空间共享空间,同一时间只有一个成员有效
//union的大小为最大成员的大小
//初始化是对第一个成员做初始化

计算机内存分为系统区与用户区。用户区下有程序区,静态存储区,动态存储区。程序区存放C语言程序编译后的可执行代码;静态存储区存放静态变量,占用固定地址,程序结束后释放;动态存储区存放动态变量,函数结束后释放。

静动态描述的是生存期(时间),内外部描述的是作用域(空间)

静态存储变量分为外部型(extern)和静态性(static)

动态存储变量分为自动型(auto)和寄存器型(register)

局部变量说明:auto(默认),static(局部静态变量,作用域在一个块内,如不初始化则值为0),register

全局(外部)变量说明:extern(默认,在其他文件使用前要先声明),static(外部静态变量,作用域在定义处到文件结束)


全局变量:

全局变量若没有初始化,会自动得到0(NULL)值

全局变量初始化发生在main之前

若全局变量之前const int a =1;则a也可以用来赋值全局变量

全局变量若不在开头定义,则作用域在说明处到文件结束

静态本地变量:

其实就是全局变量,与全局变量位于相同内存区域,而不与本地变量在一起

与全局变量的区别只在作用域仅限在此函数中。生存期也为全局

本地变量前加上static变成静态本地变量

所在函数结束时,静态本地变量继续存在,值不变

静态本地变量的初始化仅在第一次进入此函数才发生,非首次进入静态本地变量会保持上次结束时的值

本地变量在离开函数后值不变,只是无法再找到,地址也会被其他新变量占据


 函数以能否被其他文件调用分为外部函数与内部函数

外部函数(默认,extern)     内部函数(static)


一个全局变量如果也想在其他文件使用,就要在对应.h文件加上一句声明:extern int a;再把这个.h文件#include在其他文件中


#开头的是编译预处理指令

#define用来定义一个宏,例:  #define PI 3.14159

宏可以互相嵌套,""双引号内部的宏不会被替换

预定义宏:__LINE__  __FILE__  __ DATE__  __TIME__  __STDC__等

宏可以带参数,例:#define cube(x)  ((x)*(x)),但一定要尽可能加括号!


把函数原型写入头文件,若想要在其他.c文件使用此函数,则需要在两个.c文件头都#include这个头文件

所谓的头文件里全是声明

#include 后用" "会让编译器优先.c文件所在目录寻找文件,< >会让编译器优先在指定目录寻找

#include实际只是把对应文件的内容放在此文件中

stdio.h里只有printf函数的原型,真正的代码在其他地方


标准头文件结构:

#ifndef _LIST_HEAD_
#define _LIST_HEAD_


#endif

格式化输入输出:

输出:  %[flags][width][.prec][hil] type
flags    含义
-        左对齐
+        如果是正数,就强制输出+   
//+与-可以放在一起,两者顺序无所谓,意义为两者叠加
(space)  正数留空
0        用0填充

width或prec  含义
number       最小字符数
*            下一个字符是字符数 // %*d,6,123等价于%6d,123
.number      小数点后的位数
.*           下一个参数是小数点后的位数

hil(类型修饰)  含义
hh            单个字节
h             short
l             long
ll            long long
L             long double

.type  含义
i/d    int
u      unsigned int
o      八进制
x      十六进制
X      字母大写的十六进制
f/F    float,6
e/E    指数
g      float
G      float
a/A    十六进制浮点
c      char
s      字符串
p      指针
n      读入/输出的个数
// printf("123%n",&a);  这样a就得到3的值
// printf的返回值是输出的字符数,\n也算
输入:
%[flag]type
flag   含义
*      跳过  // %*d 意为跳过这个整数
number 最大字符数
hh     char
h      short
l      long,double
ll     long long
L      long double

type   含义
d      int
i      整数,可能是八进制、十六进制
u      unsigned int
o      八进制
x      十六进制
a,e,f,g  float
c      char
s      字符串
[...]  所允许的字符
p      指针
//scanf的返回值是读入的项目数

按位运算:

&(按位与)  偏向0

|(按位或)  偏向1

~(按位取反)

^(按位异或)  相同为0,不相同为1 // x^y^y=x


移位运算:

i<<y  将i以二进制形式左移j位,右侧补0。小于int的类型,移位以int的方式做,结果是int

x<<=n等价于x *= 2的n次方

对于>>来说,当对象是unsigned时,左侧填0,;当对象是signed时,左侧填原来最高位的数(保持符号不变)


main函数的真实参数:

main(int argc,char *argv[ ])

参数值在操作系统命令行上获得,一般形式:C:\>可执行文件名 参数一 参数二 ...

argc的值是命令行中参数个数(包括可执行文件名)

C:\> E24 BASIC B C    则argc得到4,argv(字符串指针的数组)是:

argv[0]指向E24\0   argv[1]指向BASIC\0 ...


文件输入输出:

>文件名  将输出结果写到该文件中

<文件名 从该文件中得到输入内容

<文件a  >文件b 从文件a输入,输出到文件b

FILE *a=fopen("文件名","r");  //a是一个文件指针,如果打开失败,函数会返回NULL
if(a) //a不为NULL
{
    int num;
    fscanf(a,"%d",&num); 
    printf("%d\n",num);
    fclose(a);
}

fopen函数的第二个参数:
"r"     打开只读
"r+"    打开读写,从文件头开始
"w"     打开只写,若不存在该文件则新建它,如果存在则先清空
"w+"    打开读写,若不存在该文件则新建它,如果存在则先清空
"a"     打开追加,若不存在该文件则新建它,如果存在则从文件尾开始
"..x"   只新建,如果文件已存在则不能打开
//以上只针对文本文件(ASCII文件)

二进制读写:
fread(要被读的文件指针,内存大小,有几个这样的内存,文件指针)
fwrite(要被写的文件指针,内存大小,有几个这样的内存,文件指针)
//二者返回值是成功读/写的字节数
//第二三个参数解释:一般使用这两个函数的都是结构体数组
//第二个参数是单个结构的大小,第三个参数是有几个结构

位段:

struct a{int a1:3;int a2=2;};
//成员a1占3bit,成员a2占2bit
//但是该结构的总长度仍然为8(4*2)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值