我是靠谱客的博主 怕黑高山,最近开发中收集的这篇文章主要介绍C语言基础学习笔记C语言基础学习笔记,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

C语言基础学习笔记

第一部分

循环后面的笔记

计算机程序描写的是步骤:数数几位数的程序实现

int x=rand()%100;
思路:人数 从左往右 三位数逆序:反复/10 计数
int x;
int n=0;
scanf("%d",&x);
n++;
x/=10;
while(x>0){
    n++;
    x/=10;
}
printf("/dn",n);
n++ 
while (x>0){
    x/=10; --循环体 死循环避免
    n++;
}

先判断条件是否满足,满足执行循环体,
边界测试条件 0 1 10 …

printf("x=%d,n=%d",x,n);  //调试输出
printf("heren"); // 提交前注释掉
---------------

do-while循环

数位数的算法
先做事情再判断条件

do{
    <循环体语句>
}while(条件语句)
//数位数
#include <stdio.h>
int main()
{
    int x;
    int n=0;
    scanf("%d",&x);
    do{
        x/=10;
        n++;
    }while(x>0);//while结尾要用;
    printf("%d",n);
    return 0;
}

for 循环

eg:阶乘 n!=1x2x3x4x…xn
两种写法: while循环和for循环

int n;
scanf("%d",&n);
int fact=1;
int i=1;
while(i<=n){
    fact*=i;
    i++;
}
printf("%d!=%dn",n,fact);
写法2int n;
scanf("%d",&n);
int fact=1;
int i=1;
for(i=1;i<n;i++){
    fact*=i;
}
printf("%d!=%dn",n,fact);
初始条件 循环条件 循环每轮做的事情
int i=1;
int fact=1;
for(i=2;i<=n;i++)
{
    fact*=1;
}
printf("")

循环次数

for(i=0; i<n; i++)
  • 循环次数为n
  • for==while循环
// for循环
for(初始动作;条件;每轮的动作){
    ...
}

for中的每一个表达式都是可以省略的

for (;条件;)==while(条件)
tips for loops:
·如果有固定次数 for
·如果必须执行一次 do-while
·others while
for ( int i=10; i> 1; i /=2 ) {
    printf("%d ", i++);
}
// 输出结果:10 5 3 2

第二部分 数据类型及条件语句

bool类型

#include<stdbool.h> 头文件

逻辑运算

! 非
&&|| 或
表达区间的表达式
x>4 &&x<6  (4,6)
c>='A'&& c<='Z' 判断字母是否是大写字母
!age<20 单目运算符高于双目运算符 
!>&&>|| 

运算符的优先级

优先级    运算符             结合性
1        ()                从左到右
2+ - ++ --         从右到左(单目的+-3        * / %             从左到右
4        + -                从左到右
5        < <= > >=       从左到右

短路
逻辑运算是自左向右进行的
对于&& 左边是false时就不做右边了
对于|| 左边是true就不做右边了

eg: 
int a=-1;
if(a>0 && a++>1){
    printf("OKn");
}
printf("%dn",a);
// result:-1 
  • conclude: 不要把赋值,包括复合赋值组合进表达式

条件运算符

  • 优先级高于赋值运算符,但低于其他运算符
m<n?x:a+5
a++>=1 &&b-->2?a:b
//问号前面是条件 冒号前面是条件满足的值 冒号后面是条件不满足的值

嵌套条件表达式

条件运算符自右向左结合的

  • 逗号运算 所有运算符中最低的
    • 逗号连接两个表达式,并以其右边的表达式的值作为它的结果
    • 逗号两边的表达式会先计算,逗号的组合关系是自左向右的,故左边的表达式会先计算,右边的表达式的值留下来作为逗号运算的结果
// for中使用逗号
for(i=0,j=10; i<10; i++,j--)

4.2级联和嵌套的判断

嵌套的if-else语句
eg:3个数中 a b c找最大的

// 分段函数计算 
if 
else if
else--对应最后一个if

int f 
if(x<0){
    f=-1;
} else if(x==0){
    f=0;
}else{
    f=2*x;
}
printf("%d",f); // 单一出口

4.3多路分支

switch-case
switch(type=控制表达式 只能是int类型的结果){
    case 1=常量 可以是常数,也可以是常数计算的表达式21+1:
        p;
        break;--break分割 case1: case2: p;break;

    case 2:
        p;
        break;

    ...
    default:
        p;
        break;
}
分支-06.成绩转换 写题目
循环的例子
int x;
int ret=0;

x=128;
while(x>1){
    x/=2;
    ret++;
}

4.4 do-while

// 算平均数
// 直到读到-1 循环结束 正整数相加
do{
    scanf("%d",&number);
    if(number!=-1){
        sum=sum+number;
        count++;
    }
}while(number!=-1) // 条件满足进行循环 number==-1 结束循环
// for循环是条件不满足结束循环 i<n i==n结束循环
// replace code:
scanf("%d",&number);
while(number!=-1){
    sum+=number;
    count++;
    scanf("%d",&number);
}
// 猜数游戏--二分法
// 分析 使用循环 文字描述核心程序 重点是循环的条件 以及循环结束的条件
/*
number:存放随机数
count:计次数
a:用户输入数据
compare 输出“大”,“小”
再次输入a 直到猜中然后结束
rand()随机数函数
*/
#include <stdio.h>
#include<stdlib.h>
#include <time.h>
int main()
{
    srand(time(0));
    int number=rand()%100+1;
    int count=0;
    int a=0;
    ...
    do{
        p
        s
        count++;
        if(...){
            ...
        }else if(){
            ...
        }

    }while(a!=number); 循环结束为成立的条件 
    --适合使用do-while循环
}
// 整数的分解->数的逆序
// I位数 分解
/*
number%10 得到个位数
number/10 去掉个位数
number/10 %10 得到10位数
*/

第三部分 循环

5.1循环控制

判断素数代码如下:

#include <stdio.h>

int main()
{
    int x;
    scanf("%d",&x);
    int i;
    int isPrime=1; //x是素数
    for(i=2;i<x;i++){
        if(x%i==0){
         isPrime=0;
        }
    }
}
// break:跳出循环
// continue:跳过循环

5.2嵌套循环

输出100以内的素数
凑硬币 三重循环
接力break exit=0;
goto语句 goto out 最内层到最外层

5.3 循环应用

求和 f(n)=1+1/2+1/3+1/4…代码如下:

#include <stdio.h>
int main()
{
    int n;
    int i;
    double sum=0.0;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        sum+=1.0/i;
    }
    printf("f(%d)=%fn",n,sum);
    return 0;
}

求和:f(n)=1-1/2+1/3-1/4+1/5-…代码如下:

#include <stdio.h>
int main()
{
    int n;
    int i;
    double sum=0.0;
    int sign=1;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        sum+=sign*1.0/i;
        sign=-sign;
    }
    printf("f(%d)=%fn",n,sum);
    return 0;
}

求最大公约数 --两种算法 一、枚举 二、辗转相除法

int a,b;
int min;
scanf("%d%d",&a,&b);
if(a<b){
    min=a;
}else{
    min=b;
}
int ret=0;
int i;
for(i=1;i<min;i++){
    if(a%i==0){
        if(b%i==0){
            ret=i;
        }
    }
}
printf("%d和%d的最大公约数是%d.n",a,b,ret);

辗转相除法

1、如果b=0,计算结束,a就是最大公约数
2、否则,计算a/b的余数,让a=b,而b等于那个余数
3、return step 1
—good habit 先敲框架,再敲内容

整数分解
正序整数分解

  • 输入一个非负整数,正序输出它的每一位数字
  • 输入:13425
  • 输出:1 3 4 2 5

review
先逆序,在分解 适用于末尾无0的数字

第四部分 数组及函数

6.1数组

1、定义数组

int number[100];

2、对数组中的元素赋值

while(x!=-1){
    number[cnt]=x;
    sum+=x;
    cnt++;
    scanf("%d",&x);
}

tips:使用数组中的元素 遍历数组,数据与列表的区别
定义数组
数组:

元素具有相同的数据类型
一旦创建,不能改变大小

int a[10] :a[0]...a[9]

数组的单元:下标从0开始
有效的下标范围
数组越界 指针出错
[0,数组下标-1]
统计数字出现次数
数组初始化

magic number
const int number=10;--数组的大小
int count[number];--定义数组
for(i=0;i<number;i++){
    count[i]=0;
}--初始化数组
count[x]++ 数组参与运算 方式很多
for(i=0;i<number;i++){
    printf("%d:%dn",i,count[i]);
}--遍历数组输出

6.2函数定义与使用

“代码复制”表示代码质量不良
函数定义

函数头 返回类型void sum--函数名(int begin,int end--参数表){
    int i;--函数体
}
调用函数

函数名(参数值)
()起到了表示函数调用的重要作用
即使没有参数也需要()
·若有参数,需要给出正确的数量和顺序
·这些值会被按照顺序依次用来初始化函数中的参数
–函数返回值

6.3函数的参数和变量

函数原型
函数的先后关系
函数声明 位置 函数定义位置
-函数参数
调用函数:
·如果函数有参数,调用函数时必须传递给它数量、类型正确的值
·可以传递给函数的值是表达式的结果,include:
字面量、变量、函数的返回值、计算的结果
类型自动转换 C++/Java更严格
传值:每个函数有自己的变量空间,参数也独立 形式参数

 void swap(int a,int b)//形参
 swap(a,b)--a,b为实参

本地变量,局部变量
自动变量:生存期是自动的
变量的生存期和作用域

本地变量的规则:
1、本地变量是定义在块内的
可以定义在函数的块内
可以定义在语句的块内
可以定义在一对大括号内
2、程序进入块内前,变量不存在,程序离开这个块,变量消失
3、快外面定义的变量在里面依旧有效
4、块里面定义的和外面定义的重名无法掩盖外面的
5、不能在一个块内定义同名的变量
6、本地变量默认不会被初始化
7、参数在进入函数的时候被初始化了
—其他细节
1、没有参数时 void f(void)–明确表明无任何参数
void f()–不确定参数形式
逗号运算符?
函数不能嵌套
return (i);表达式 --建议写 retrun i;表达式

6.4二维数组

二维数组定义

int a[3][5]

通常理解为a是一个3行5列的矩阵
二维数组的遍历 一重for循环遍历行号 第二重循环遍历列号
1、二维数组的初始化

int a[][5]={
    {0,1,2,3,4},
    {2,3,4,5,6},
};

·列数是必须给出的,行数可以由编译器来数
·每行一个{},逗号分隔

// tic-tac-toe游戏 井字棋
// 读入矩阵
const int size=3;
int board[size][size];
int i,j;
int num0fX;
int num0fO;
int result=-1;//-1 平局 1 X win 0 O win
//读入矩阵
for(i=0;i<size;i++){
    for(j=0;j<size;j++){
        scanf("%d",&board[i][j]);//读入矩阵
    }
}
//检查行
for(i=0;i<size&&result==-1;i++){
    num0fO=num0fX=0;
    for(j=0;j<size;j++){
        if(board[i][j]==1){
            num0fX++;
        }else{
            num0fO++;
        }
    }
    if(num0fO==size){
        result=0}else if(num0fX==size){
        result=1;
    }
}
//检查列
if(result==-1){
    for(j=0;j<size&&result==-1;j++){
        num0fO=num0fX=0;
        for(i=0;i<size;i++){
            if(board[i][j]==1){
                num0fX++;
            }else{
                num0fO++;
            }
        }
        if(num0fO==size){
            result=0}else if(num0fX==size){
            result=1;
            }
    }
}

第五部分 数组的运算及排序算法

7.1 数组运算

数组的集成初始化

数组初始化02

int num0[10] = {0};

数组的大小

  • sizeof给出的整个数组所占据的内容的大小,单位是字节
  • sizeof(a)/sizeof(a[0])
  • sizeof(a[0])给出的数组中单个元素的大小,相除得到了数组的单元个数
  • 一旦修改代码中的初始数据,不需要修改遍历代码

—数组的赋值 不可以直接赋值 只能遍历数组(Python区别)
数组变量本身不能被赋值,必须采用遍历–the only one

for(i=0;i<length;i++){
    b[i]=a[i];
}

eg:通常都是使用for循环,让循环变量i从0到<数组的长度,让循环体内最大的i正好是数组最大的有效下标
常见错误
1、循环结束条件是<=数组长度
2、离开循环后,继续用i的值来做数组元素的下标

数组作为函数参数时,必须再用另一个参数来传入数组的大小

  • 不能在[]中给出数组的大小
  • 不能再利用sizeof来计算数组的元素个数

eg: isPrime
01、如果x是偶数,n/2
02、sqrt(x) 循环sart(x)
–unix系统中 man sqrt
03、判断是否能被已知的且<x的素数整除

int isPrime(int x);
ways01:
int isPrime(int x){
    int ret=1;
    int i;
    if(x==1) ret=0;
    for(i=2;i<x;i++){
        if(x%i==0){
            ret=0;
            break;
        }
    }
    return ret;
}--2到x-1测试是否可以整除

程序效率
分析时间复杂度 :对于n要循环n-1遍,当n很大时就是n遍

ways02:
int isPrime(int x){
    int ret=1;
    int i;
    if(x==1||
        (x%2==0&&x!2))
        ret=0;
    for(i=3;i<x;i+=2){
        if(x%i==0){
            ret=0;
            break;
        }
    }
    return ret;
}--去掉偶数后,从3到x-1,每次加2

如果x是偶数,则非素数
循环(n-3)/2 +1遍—趋近于n/2

ways03:
int isPrime(int x){
    int ret=1;
    int i;
    if(x==1||(x%2==0&&x!=2))
    ret=0;
    for(i=3;i<sqrt(x);i+=2){
        if(x%i==0){
            ret=0;
            break;
        }
    }
    return ret;
}--无需到x-1sqrt(x)即可

ways04:
判断是否能被已知的且<x的素数整除

int main(void){
    const int number=100;
    int prime[number]={2};
    int count=1;
    int i=3;
    while(count<number){
        if(isPrime(i,prime,count)){
            prime[count++]=i;
        }
        i++;
    }
    for(i=0;i<number;i++){
        printf("%d",prime[i]);
        if((i+5)%5) printf("t");
        else printf("n");
    }
    return 0;
}
int isPrime(int x,int knownPrimes[],int numberOfKnownPrimes){
    int ret=1;
    int i;
    for(i=0;i<numberofKnownPrimes;i++){
        if(x%knownPrimes[i]==0){
            ret=0;
            break;
        }
    }
    return ret;
}

素数表
构造素数表

  • 构造n以内的素数表

1、令x为2
2、将2x、3x、…倍数删除
3、令x为下一个没有被标记为非素数的数,重复2;直到所有的数都已经尝试完毕
—伪代码
构造n以内(不含)的素数表
1、开辟prime[n],初始化其所有元素五日1,prime[x]为1表示x是素数
2、令x=2
3、如果x是素数,则对于(i=2;xi<n;i++)令prime[ix]=0
4、令x++,如果x<n,重复3,or end;

7.2搜索

在一个数组中找到某个数的位置 基本方法:遍历

int search(int key,int a[],int len){
    int ret=-1;//默认找不到
    for(int i=0;i<len;i++){
     if(key==a[i]){
         //return i;
         ret=i;//返回元素所在位置
         break;
     }
    }
    //return -1;//违反单一出口 虽然没有ret变量
    return ret;
}

进阶eg:

char *name[]={'','',};
结构体 struct{
    int amount;
    char *name;
}coins[]={
    ,,,
}
sizeof(coins)/sizeof(coins[0])

线性搜索没有效率,
对于有序数组,
二分搜索法

left right mid
mid=left+right /2
left=mid+1 
...
right=mid-1;

二分搜索的效率很高:log2N 以2为底的N的对数

Nlog2N
103
1007
100010
100000020
100000000030

7.3 排序初步

排序算法
无序数组-有序数组-二分法
选择排序 选出最大的数 和位置交换
一、找出最大的数 另i=0的数最大 遍历 找出max
二、和最大位置的数交换 len-1开始
遍历全部数组

第六部分 指针及字符串

8.1指针

sizeof(int) 4byte
&:获得变量的地址,操作数必须是变量
printf("%pn",&i);
printf("%x",&i);
x86和x64 int的结果不同

指针

scanf
// 指针 就是保存地址的变量
int i;
int* p=&i;
int* p,q;
//*p是一个int int *p,*q;

指针变量:变量的值是内存的地址;普通变量的值是实际的值;指针变量的值是具有实际值的变量的地址

作为参数的指针

void f(int *p) 在被调用的时候得到了某个变量的地址;
int i=0; f(&i); 在函数里面可以通过这个指针访问外面的这个i

&i是i的地址
f函数可以防访问外部变量i
访问那个地址上的变量*

 * 是一个单目运算符,用来访问指针的值所表示的地址上的变量
int k=*p;
*p=k+1;

传入地址
传入函数的数组:实际上是指针,sizeof(a)==sizeof(int*),但是可以用数组的运算符[]进行运算。
数组变量是特殊的指针

int *const a[];

8.2字符类型

char是一种整数,也是一种特殊的类型,字符。
reason:
01:用单引号表示的字符字面量:‘a’,‘1’;
02:''也是一个字符

// printf和scanf 用%c来输入输出字符 
c=1
d='1'
printf("c=%d",c); result:c=1
printf("d=%d",d); result:d=49
// problem:如何输入'1'这个字符给char c?
scanf("%c",&c);//输入字符型 1相当于49
scanf("%d",&i); c=i;//输入49 得到字符型'1'
// scanf不能处理char型变量 需要赋值给int型变量

混合输入

scanf("%d %c",&i,&c);
scanf("%d%c",&i,&c); 不能读到空格后面的数字 c=32 ' '

字符计算

c='A';
c++;
  • 一个字符加一个数字得到ASCII码表中那个数之后的字符
  • 两个字符的减,得到它们在表中的距离

/逃逸字符/

字符意义
b回退一格
b回退一格
t到下一个表格位
n换行
r回车
"双引号
单引号
反斜杠本身

8.3字符串

char word[]={'H','e','l','l','o','!'}; // 字符数组
// 字符串:
char word[]={'H','e','l','l','o','!',''};
  • difference:字符串末尾有一个

字符串:

1、以0结尾的一串字符
2、0和’’是一样的,但是和’0’不同
3、0标志字符串的结束,但它不是字符串的一部分,计算字符串长度的时候不包含这个0
4、字符串一数组的形式存在,以数组或指针的形式访问,更多的是以指针的形式

string.h
字符串变量

char *str="Hello"
char word[]="Hello"
char line[10]="Hello"

字符串常量:“Hello”
两个相邻的字符串常量,会自动连接

char *s="Hello World"; 
// 只读

s是一个指针,初始化为指向一个字符串常量
如果需要修改字符串,应该用数组:

char s[]="Hello,world!";

本地变量

char *str="Hello";
char word[]="Hello";

数组:这个字符串在这里,作为本地变量空间自动被回收
指针:这个字符串不知道在哪里,用以处理参数,动态分配空间
构造字符串,指针;处理字符串,数组

8.4字符串运算

字符串赋值:

char *t="title";
char *s;
s=t;

并没有产生新的字符串,只是让指针s指向了t所指的字符串,对s的任何操作就是对t做的
构建新的字符串 需要字符串函数
字符串的输入输出

char string[8];
scanf("%s",string); // 读入一个单词,到空格、tab或者回车为止
// 不安全 容易溢出
scanf("%7s",string);//最多读7个字符
printf("%s",string);

常见错误

fisrt:
char *string;
scanf("%s",string);

1、误以为char*就是字符串类型,定义了一个字符串类型的变量string就可以直接使用了

second:
空字符串

char buffer[100]="";
  • 这是一个空的字符串,
  • buffer[0]==‘’;
 char buffer[]="";
  • 数组的长度只有 1

字符串函数

// string.h
#incldue<string.h>
// strlen、strcmp、strcpy、strcat、strchr、strstr 
// strlen:
size_t strlen(const char *s);//返回s的字符串长度(不包括结尾的0)
// strcmp:
int strcmp(const char*s1,const char*s2);//比较两个字符串,返回:
// 0:s1==s2
// 1:s1>s2
// -1:s1<s2
// strcpy:
char*strcpy(char*restrict dst,const char *restrict src);

把src的字符串拷贝到dst
restrict表明src和dst不重叠
返回dst,为了能链其代码来

安全函数版本:

char *strncpy(char *restrict dst,const char *restrict src,size_t n);
char *strncat(char *restrict s1,const char *restrict s2, size_t n);
int strncmp(const char*s1,const char*s2,size_t n);

最后

以上就是怕黑高山为你收集整理的C语言基础学习笔记C语言基础学习笔记的全部内容,希望文章能够帮你解决C语言基础学习笔记C语言基础学习笔记所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部