C语言从0到1算法小白训练营——day2

简介: C语言从0到1算法小白训练营——day2

我们学习不仅仅是要把难的学会,也要注重基础,注重内功。

接下来我们继续先从基础知识开始:

1.  字符串+字符常量+注释

1.1  字符串

如:“abc”

①定义:由双引号引起来的一串字符称为字符串。

②C语言规定,每个字符串的末尾隐藏放了一个‘\0’

③字符串的结束标志是一个‘\0’。(注:‘\0’是结束标志,不算作字符串内容)

代码实例:

1. int main()
2. {
3.  char arr1[] = "abc";//字符串数组
4.  char arr2[] = { 'a','b','c' };//字符数组
5.  return 0;
6. }

调试:


加油站:字符串的相关知识点

①%s:打印字符串,直到遇到‘\0’才停止打印(‘\0’是结束标志,不算作字符串内容)

代码实例:

#include<stdio.h>
int main()
{
  char arr1[] = "abc";//字符串数组
  char arr2[] = { 'a','b','c' };//字符数组
  //打印arr1
  printf("%s\n", arr1);
  //打印arr2
  printf("%s\n", arr2);
  return 0;
}


运行结果:

图解:

②strlen:C语言提供的库函数,可以计算字符串的长度,统计的‘\0’之前字符的长度(‘\0’是结束标志,不算字符串内容)

补充:strlen:string字符串,length长度  它的头文件“string.h”(如使用别人的东西你要打招呼)

代码实例:

#include<stdio.h>
#include<string.h>//预处理,对strlen的声明
int main()
{
  char arr[] = "abc";
  //调用库函数strlen,计算字符串的长度
  int len = strlen(arr);
  //打印长度
  printf("%d\n", len);
  return 0;
}

运行结果:

注意:

1、字符串的占用空间VS长度

       占用空间要加上'\0',长度不加‘\0’

2、不能把一个字符串赋给一个字符变量。例:c="a";是错的

3、C语言没有字符串变量,但可用字符数组来表示


1.2  字符常量

如:‘a’  

1、分类:C语言中,字符常量分为普通字符常量和转义字符两种

       ①普通字符:用单引号括起来的一个字符,该字符是除单引号和反斜杠以外所有可显示字符。

       ②转义字符:a.转义字符以反斜杠开头;b.转义字符具有特定的含义,不同于字符原来的意义(就是转变原来的意义),故称“转义”字符

常用:\n换行

          \t水平制表符,用来占位,一般相当于四个空格,或者tab键的功能

重点:\ddd        ddd表示1~3个八进制的数字。如:\130  

          \xdd        dd表示1~2个十六进制数字。如:\x30


1.3  字符串和字符常量的区别

①从表示形式上看:字符常量是用单引号括起来的,字符串是用双引号括起来的

②从字符的个数上看:字符常量只能是单个字符,字符串常量可以是0个或多个字符

③有字符变量,但没有字符串变量。C语言没有专门的字符串类型变量,而是使用字符型数组或字符型指针来存储字符串

④字符常量在内存中占用1个字符,字符串常量在内存的字节数是字符个数加1。(每一个字符串的末尾隐藏存在一个字符串结束标志‘\0’)


1.4  字符型数据在内存的存储形式

①在C语言中字符型数据包括字符和字符串两种。

②字符型数据在内存中存储的是字符的ASCII码值的二进制,一个字符的存储占用一个字节。

常用的ASCII值:

0-ASCII码值48

A-ASCII码值65(小写字母=大写字母+32)

③%c-打印字符-ASCII值(十进制)


1.5  注释

(1)注释有两种风格:

       ①C语言风格的注释/*xxxxxx*/

               段注释

               缺陷:不能嵌套注释

       ②C++风格的注释//xxxxxx

               行注释

(2)理解

       ①注释可以出现在程序中的任意位置

       ②注释不参与程序的运行,主要用于对程序的某些关键部分进行说明,其目的是提高程序的可读性


2.printf的输出格式

2.1  说明符

       说明符用于规定输出数据的类型,含义如下:


2.2  flags(标志)

       标志(flags)用于规定输出样式,含义如下:


2.3  width(最小宽度)

       最小宽度(width)用于控制显示字段的宽度,取值和含义如下:



2.4  .precision(精度)

       精度(.precision)用于指定输出精度,取值和含义如下:



我们上机试试:

代码实例:

#include<stdio.h>
int main()
{
  //标志用来规定输出样式
  //%-5d  占5个终端位宽  左对齐,不足右边填充空格
  printf("#%5d#\n", 123);
  //%05d  占5个终端位宽  右对齐,不足用0补齐
  printf("#%05d#\n", 123);
  //%+d   输出正负号
  printf("#%+d# #%+d#\n", 123, -123);
  //% d   正号用空格替代,负号输出
  printf("#% d# #% d#\n", 123, -123);
  // %#x  输出进制的前导符
  printf("%x %X %#x\n", 12, 12, 12 );
  //最小宽度用来控制显示字段的宽度
  //输出的字段长度(实际数据)大于最小宽度,不会截断输出
  printf("%2d\n", 123);
  //%10d  123   输出的字段长度小于最小宽度,默认右对齐,左边补空格
  printf("#%10d#\n", 123);
  //%*d    指示下一个参数是宽度
  printf("%*d\n", 3, 123);//等价于printf("%3d\n",123)
  //精度用来指定输出精度
  //对于f说明符:要在小数点后输出的小数位数
  //若小数实际位数大于指定的精度n,
  //则截取n位小数,并自动对后面的数进行四舍五入
  printf("%.2f\n", 3.45);
  printf("%.1f\n", 3.45);
  printf("%.5f\n", 3.45);
  return 0;
}


3. 表达式求值

表达式求值的顺序一部分是由操作符的优先级和结合性决定。

同时需注意:有些表达式的操作数再求值的过程中可能需要转换为其他类型。

操作数在求值过程中是否需要转换为其他类型是我们现在主讲的重点。


3.1  隐式类型转换

       C语言的整形算术运算总是至少以缺省(缺省就是默认的意思)整形类型的精度来进行的。

       为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整形,这种转换称为整形提升


整形提升的意义:

表达式的整形运算要在CPU的相应运算器件内执行,CPU内整形运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。

所以,表达式中各种长度可能小于int长度的整形值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。


代码实例:

代码1:

//C的整形算术运算总是至少以缺省整形类型的精度来进行的。
//为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整形,
//这种转换称为整形提升
//整形提升是针对类型小于整形的
//char short int ……
// 1     2    4
#include<stdio.h>
int main()
{
  char ch = 'a';
  short data = 20;
  //char short类型在使用之前整形提升
  printf("%d\n", sizeof(ch + data));//4
  printf("%d\n", sizeof(ch + ch));//4
  printf("%d\n", sizeof(data + data));//4
  return 0;
}

整形提升是针对于类型小于整形的,如char short类型操作数在 参与表达式运算之前 转换为int型


代码2:

如何进行整形提升呢?

整形提升是按照变量的数据类型的符号位来提升的

int main()
{
  //负数的整形提升
  char ch1 = -1;
  //变量ch1的二进制位(补码)中只有8个比特位
  //11111111
  //因为char为有符号的char
  //所以整形提升的时候,高位补充符号位,即为1
  //提升之后的结果为:
  //1111111111111111111111111111111
  //正数的整形提升
  char ch2 = 1;
  //ch2的补码:
  //00000001
  //符号位为0,提升之后的结果为:
  //00000000000000000000000000000001
  //无符号整形提升,高位补0
  return 0;
}

代码3:char之间的运算

#include<stdio.h>
int main()
{
  //VS编译器char---->signed char
  char a = 3;
  //整形的二进制:00000000000000000000000000000011
  //截断
  //char存储:00000011
  char b = 127;
  //整形的二进制:00000000000000000000000001111111
  //截断
  //char存储:01111111
  char c = a + b;
  //a-00000011
  //b-01111111
  //整形提升
  //a-00000000000000000000000000000011
  //b-00000000000000000000000001111111
  //a+b:00000000000000000000000010000010
  //截断
  //c-10000010
  printf("%d\n", c);
  //%d是打印十进制的整数
  //c-10000010
  //整形提升
  //补码:11111111111111111111111110000010
  //过程:11111111111111111111111110000001
  //原码:10000000000000000000000001111110
  return 0;
}

运行结果是多少呢?

-126

tip:我们了解一下char的取值范围:

3.2  算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。

long double

double

float

unsigned long int

long int

unsigned int

int

由低到高转换(从下向上)

注意:算术转换讨论的类型都是大于或等于int型的

警告:但是算术转换要合理,要不然会有一些潜在的问题。(就高不就低,否则可能精度丢失)

例:

float f=3.14;

int num = f;//隐式转换,会有精度丢失

代码1:有符号和无符号的转换

#include<stdio.h>
int main()
{
  int data1 = -20;
  unsigned int data2 = 10;
  //有符号data1和无符号data2参加计算的时候
  //会先将data1转换成无符号(-20的补码很大的整数)
  //if多分支语句判断
  if ((data1 + data2) > 0)
  {
    printf(">0\n");
  }
  else if ((data1 + data2) < 0)
  {
    printf("<0\n");
  }
  return 0;
}

运行结果:

代码2:int和double的转换

1. #include<stdio.h>
2. 
3. int main()
4. {
5.  int data = 10;
6.  printf("%d\n", sizeof(data + 3.14));
7.  return 0;
8. }

运行结果:

总结:

①低于int型的char,short为整形提升

②等于或大于int型的为算术转换(从低字节到高字节)

③只要参与表达式运算,就有可能发生

4.C语言的三种基本结构

C语言是一门结构化的程序设计语言

C语言支持三种结构:

4.1  顺序结构

4.2  选择结构

4.3  循环结构

想一想,我们生活的所有事是不是都是这三种结构组成的,有了这三种结构我们就可以解决生活中的任何事!!!

4.1  顺序结构

顺序结构的程序设计是最简单的,只要按照解决问题的顺序写出相应的语句就行,它的执行顺序是自上而下,依次执行。(从主函数main开始)

4.2  选择结构(分支语句)

选择结构用于判断给定的条件;根据判断的结果判断某些条件,根据判断的结果来控制程序的流程。

C语言中用if语句和switch语句来表达选择结构。


4.2.1  if语句的三种形式

(1)单分支if语句

①语法结构:

if(条件表达式)

{

       语句;

}

②流程图:

③功能:如果表达式的值为真,则执行其后面的语句,否则不执行该语句。


(2)双分支if语句

①语法结构:

if(条件表达式)

{

       语句1;

}

else

{

       语句2;

}

②流程图



③功能:如果表达式的值为真,则执行语句1,否则执行语句2。

④if……else……等同条件操作符

注:if……else……是一个语句,不要想成两个语句了。else子句不能作为语句单独使用,它必须是if语句的一部分,与if配对使用。


(3)多分支if语句

①语法结构:

if(条件表达式1)

{

       语句1;

}

else if(条件表达式2)

{

       语句2;

}

       ……

else if(条件表达式n)

{

       语句n;

}

else

{

       语句n+1;

}

②流程图:

③功能:依次判断表达式的值,当出现一个表达式的值为真时,则执行其对应的语句,然后跳转到整个if语句之后继续执行程序;如果所有表达式均为假,则执行else后的语句,即语句n+1.


④else if(表达式):表达式如果当且仅当只有一种条件时可以省略if


⑤单分支if语句VS多分支if语句:多分支更好,因为单分支if语句,每个都要判断,多分支if语句判断为真就跳到整个if语句之后了。即多分支if语句效率更高。  

加油站:

①注意:在if和else后面只能控制一条语句--->要控制多条语句,此时要用花括号“{}”将这几条语句括起来成为一个复合语句(也即代码块,这里的一对{}就是一个代码块)

②if语句的嵌套:当if语句的操作语句中包含其他if语句时,称为嵌套的if语句。

③else的匹配(悬空else):else总是与它前面最近的一个尚未匹配的if相匹配。

④if语句允许嵌套,但不建议嵌套层数太多(一般为7层)


4.2.2  switch语句

switch语句也是一种分支语句,是多分支选择语句。

有了if语句可以解决多分支选择,那为什么还要加上switch语句呢?

因为:如果分支较多,则if语句层次多,程序冗长且可读性降低。(即太复杂)

那我们就得有不一样的语法形式。

这就是switch语句。

1、语法结构:

switch(整形表达式)

{

  case 整形常量表达式1:

                      语句1;

                       //break;//实现真正的分支

                       ……

       default:

                   语句n;

                   //break;

}

2、功能:当表达式的内容与某个case标签后的常量相等后,就执行该case下的语句,break表示该case以后的内容不会执行,如果没有跟break,会继续执行当前case之后的case分支。

3、在switch语句中的break:

       ①作用:在switch语句中,我们没有办法直接实现分支,搭配break使用才能实现真正的分支。

       ②那是不是我们case后面一定加break呢?

               不是,我们要根据实际问题选择是否加break。(如:多个case共用一组执行语句时,共用的执行语句写在最后一个,其余可省略。)

       ③break只能跳出本次的switch语句(注:像打游戏一样只能一关一关过,一次只能过一关)

4、default子句:

       ①功能:当表达式的值与所有的case标签的值都不匹配时,这个default子句后面的语句就会执行。(注:每个switch语句中只能出现一条default子句)

       ②虽然default子句可以出现在switch中的任意位置,但是建议放在最后。(习惯上我们前面处理正确的,后面处理异常的)

       ③虽然不加default子句,switch语句也是对的,但是每个switch语句中都放一条default子句是个好习惯,甚至可以在后面再加一个break。

5、注意:

       ①switch后的表达式为整形,如:int 、long、short、char(字符内存是二进制的ASCII值)

       ②每一个case的常量表达式的值,必须互不相同,否则就会出现互相矛盾的现象。

6、switch语句可以嵌套使用。

4.3  循环结构

循环结构是指在程序中需要反复执行某个功能而设置的一种程序结构。它由循环体中的条件,判断继续执行某个功能还是退出循环。根据判断条件,循环又可细分为以下两种形式:先判断后执行的循环结构和先执行后判断的循环结构。

结构理解:

①循环结构可以看成是一个条件判断语句和一个向回转向语句的结合。

②循环结构包含的三要素:循环变量、循环体和循环终止条件。

4.3.1  在C语言中常用的三种循环:

循环的使用:for>while>do……while(具体按实际情况使用)

(1)while语句--->先判断,在执行

1、语法结构:

while(条件表达式)

{

       循环体;

}

2、流程图


3、功能:条件表达式为真,才执行后面的循环语句,否则不执行。

(2)for语句--->与while一样的效果,但是形式更优

1、语法结构:

for(初始化部分;循环条件部分;调整部分)

{

       循环体;

}

2、流程图:

3、理解for的三个部分

       ①初始化部分:用来初始化循环变量,注只能在循环开始时,执行一次

       ②循环条件部分:用来判断循环什么时候终止(每次循环都要执行,如果循环条件为true,进入循环体,如果为false,退出循环)

       ③调整部分:用于循环条件的调整,每次循环结束的时候执行(使循环条件趋于false的语句)

4、一些for循环的变种

       例如:for(;;)

       ①for循环中的初始化部分,判断部分,调整部分是可以省略的,但是不建议初学者省略,容易导致问题。

       ②省略掉判断部分,判断就恒为真,循环就死循环。

5、循环嵌套:外层循环的次数  *  内层循环的次数  =  总循环次数


(3)do……while语句--->先执行,再判断(至少执行一次)

1、语法结构:

do

{

       循环体;

}while(条件表达式);

2、流程图:


3、注意:while(表达式)后面有‘;’

4、特点:先执行,再判断--循环至少执行一次,使用的场景有限,所以不常用


 

4.3.2  break和continue

(1)break的作用和应用

①break只在switch和循环中应用

②作用:在switch中break的作用是实现分支;在循环中break的作用是终止循环

③应用在某种情况(条件)满足时,想让循环提前终止

④注意:break只能跳出离它最近的一层循环。

(2)continue的作用和应用

①continue只在循环中应用

②作用:终止本次循环,进入下一次循环

③应用:当某种情况(条件)满足时,这一次循环后面的代码我不想它执行

4.3.3  goto语句(跳转)

goto语句为无条件转向语句。

1、语法结构:

goto 语句标号;

2、goto语句的一般有两个用法:

       ①与if语句一起构成循环结构

       ②最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。

       例如:一次跳出两层循环或多层循环。

       多层循环这种情况使用break是达不到目的的,它只能从最内层循环退出到上一层的循环。(注:break一次只能跳出一层循环)

案例:求1~100的和

代码1:for循环实现

#include<stdio.h>
int main()
{
  int i = 0;//循环变量
  int sum = 0;//和
  //从1遍历到100,
  for (i = 1; i <= 100; i++)
  {
    sum += i;//累加
  }
  //输出
  printf("sum=%d\n", sum);
  return 0;
}

代码2:累加跳过50

#include<stdio.h>
int main()
{
  int i = 0;
  int sum = 0;
  for (i = 1; i <= 100; i++)
  {
    if (50 == i)
    {
      continue;
    }//当i=50时终止本次循环循环
    sum += i;
  }
  //输出
  printf("%d\n", sum);
  return 0;
}

代码3:累加到9时,结束循环

#include<stdio.h>
int main()
{
  int i = 0;
  int sum = 0;
  for (i = 1; i <= 100; i++)
  {
    if (10 == i)
    {
      break;
    }//当i=10时终止循环
    sum += i;
  }
  printf("%d\n", sum);
  return 0;
}


相关文章
|
2月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
58 1
|
2月前
|
搜索推荐 C语言
【排序算法】快速排序升级版--三路快排详解 + 实现(c语言)
本文介绍了快速排序的升级版——三路快排。传统快速排序在处理大量相同元素时效率较低,而三路快排通过将数组分为三部分(小于、等于、大于基准值)来优化这一问题。文章详细讲解了三路快排的实现步骤,并提供了完整的代码示例。
65 4
|
5月前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
119 1
|
1月前
|
存储 算法 程序员
C 语言递归算法:以简洁代码驾驭复杂逻辑
C语言递归算法简介:通过简洁的代码实现复杂的逻辑处理,递归函数自我调用解决分层问题,高效而优雅。适用于树形结构遍历、数学计算等领域。
|
2月前
|
存储 缓存 算法
C语言在实现高效算法方面的特点与优势,包括高效性、灵活性、可移植性和底层访问能力
本文探讨了C语言在实现高效算法方面的特点与优势,包括高效性、灵活性、可移植性和底层访问能力。文章还分析了数据结构的选择与优化、算法设计的优化策略、内存管理和代码优化技巧,并通过实际案例展示了C语言在排序和图遍历算法中的高效实现。
50 2
|
2月前
|
机器学习/深度学习 算法 数据挖掘
C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出
本文探讨了C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出。文章还介绍了C语言在知名机器学习库中的作用,以及与Python等语言结合使用的案例,展望了其未来发展的挑战与机遇。
55 1
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
71 1
|
2月前
|
存储 算法 数据管理
C语言算法复杂度
【10月更文挑战第20天】
C语言算法复杂度
|
2月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
158 7
|
2月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
132 8
下一篇
开通oss服务