C语言基础

目录

1. 初识C语言

2. 第一个c语言程序

3. 数据类型及其长度

4. 数据的输入输出

a.输入

b.输出

5. 字符串&&转义字符&&注释

6. 数组

6.1. 一维数组:

6.2. 二维数组

7. 变量&&常量

7.1. 常量

7.1.1. 字面常量

7.1.2. const 修饰的常变量

7.1.3. #define 定义的标识符常量

7.1.4. 枚举常量

7.2. 变量:

7.2.1. 定义变量

7.2.2. 变量的分类

8. 判断&&选择语句

8.1 if...else

8.2 if...else if...else

8.3 switch

9. 循环

9.1 while 语句

9.2 for 语句

9.2.1 for循环变种

9.3 do ... while 语句

10. 函数

11. 运算符

11.1. 算术运算符 + - * / %

11.2. 移位运算符

11.3. 关系运算符

11.4. 位运算符

11.5. 逻辑运算符

11.6. 三目运算符

11.7. 强制类型转换

11.7.1. 整数提升

11.7.2. 常用的算术转换

12. 常见关键字

12.1. static:

12.1.1.修饰局部变量--称为静态局部变量

12.2.2.修饰全局变量--称为静态全局函数

12.2.3.修饰函数

12.2. #define定义常量

13. 指针

14. 结构体


1. 初识C语言

在中学物理我们知道:电子元件只能传达"开"或"闭"两种信息,所以电子元件(即晶体管)之间也只能用这两种方式通信。人们把"开"用1代替,把"闭"用0代替。电子计算机在初期时,只能识别0和1两种信号,所以那个时候只有科学家才能进行编程工作,这在那时候是十分困难的。

上面提到的0/1信号,正好为二进制提供了用武之地,所以我们把最基本的、计算机能够直接读取的语言称之为低级语言。

在这里,低级语言就是一串由0和1组成的东西,它转换成汇编语言,进而转换成高级语言,才被我们大多数人学习。

编译器的作用就是把上面的过程反过来,将我们人能看得懂、接近自然语言的、而且能写出来的高级语言转换成机器能够读懂的低级语言。

最小的单位是bit,8bit = 1Byte,1024Byte = 1KB,接着是MB,GB,TB等。bit(比特)是最小单位。这里说个题外话,不少人在办理宽带有这样的困惑:为什么我明明买的是200M宽带呀,为什么最高才十几二十兆每秒呢?原因是:运营商所宣传的200M宽带实际上是宽带接入的速率为200Mbps,这里的bps指的是每秒能传输的bit,换算下来200M宽带理论上峰速为25.6MB/s。200/8

2. 第一个c语言程序

#include <stdio.h>
int main(){
    printf("hello heiyu\n");
    printf("heiyu\n");
    return 0; 
}

#include是一种预处理命令,它的作用是找到尖括号(或者英文双引号)中的文件,并将它包含到当前文件,被包含的文件中的文本将替换源代码文件(就是我们正在编写的东西)中的#include指令。

被包含的文件通常是由系统提供的,扩展名为.h,还有一部分是自己编写的.h文件。

3. 数据类型及其长度

char //字符数据类型1byte-2^7~(2^7-1)
short //短整型   2-2^15~(2^15-1)
int //整形  4-2^31~(2^31-1)
long //长整型4-2^31~(2^31-1)
long long //更长的整形 8-2^63~(2^63-1)
float //单精度浮点数40以及1.2*10^38~3.4*10^38
double //双精度浮点数80以及1.2*10^308~3.4*10^308
unsigned int //无符号整数40~2^32-1

在整形前加unsigned表示无符号数 unsigned int   0~2^32-1

#include <stdio.h>
int main(){
    printf("%d\n", sizeof(char));
    printf("%d\n", sizeof(short));
    printf("%d\n", sizeof(int));
    printf("%d\n", sizeof(long));
    printf("%d\n", sizeof(long long));
    printf("%d\n", sizeof(float));
    printf("%d\n", sizeof(double));
    printf("%d\n", sizeof(long double));
	return 0;
}

4. 数据的输入输出

d c s f m.nf -m.nf e i o x u g P67页

a.输入

getchar:输入单个字符,保存到字符变量中

gets:输入一行数据,保存到字符串变量中

scanf:格式化输入函数,一次可以输入多个数据,保存到多个变量中

b.输出

putchar:输出单个字符

puts:输出字符串

printf:格式化输出函数,可输出常量、变量等

#include <stdio.h>
#include <string.h>

int main()
{
    int age=0;
    char sex=0;
    double weight=0;

    char name[21];

    printf("请输入您的姓名、姓别(x-男;y-女),年龄和体重,中间用空格分隔:");
    scanf("%s %c %d %lf",name,&sex,&age,&weight); // name变量前不用加&

    printf("您的姓名是:%s,姓别:%c,年龄:%d岁,体重%lf公斤。\n",name,sex,age,weight);

    return 0;
}

5. 字符串&&转义字符&&注释

C语言中没有字符串类型,使用char[]数组存储

#include <stdio.h>
//下面代码,打印结果是什么?为什么?(突出'\0'的重要性)
int main()
{
    char arr1[] = "hei";
    char arr2[] = {'h', 'e', 'i'};
    char arr3[] = {'h', 'e', 'i', '\0'};
    printf("%s\n", arr1);
    printf("%s\n", arr2);
    printf("%s\n", arr3);
    return 0; 
}

转义字符:

\? 在书写连续多个问号时使用,防止他们被解析成三字母词

\' 用于表示字符常量'

\“ 用于表示一个字符串内部的双引号

\\ 用于表示一个反斜杠,防止它被解释为一个转义序列符。

\a 警告字符,蜂鸣

\b 退格符

\f 进纸符

\n 换行

\r 回车

\t 水平制表符

\v 垂直制表符

#include <stdio.h>
int main()
{
    printf("abcd\tef");
    return 0;
}
注释:

//程序输出什么?
#include <stdio.h>
int main()
{
	/*printf("%d\n", strlen("abcdef"));
	printf("%d\n", strlen("c:\test\628\test.c"));*/
	return 0;
}

6. 数组

6.1. 一维数组:

定义:一组有序数据的集合

#include <stdio.h>

int main() {
    int arr1[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};//定义一个整形数组,最多放10个元素
    //如果数组10个元素,下标的范围是0-9
    int arr2[10];
    int i = 0;   //定义一个变量
    for (i = 0; i < 10; i++) {           //当i<10时,打印出数组下标对应位置的数组元素
        printf("%d ", arr1[i]);
        arr2[i]=i;
    }
    printf("\n");
    return 0;
}

6.2. 二维数组

#include <stdio.h>

int main(){
    int a1[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
    int a2[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
    int a3[3][4]={{1},{2},{3}};
    int a4[3][4]={{1},{2},{3}};
    int a5[3][4]={{1,2},{2}};
    int a6[][4]={1,2,3,4,5,6,7,8,9,10,11,12};
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 4; ++j) {
            printf("%3d",a1[i][j]);
        }
        printf("\n");
    }
    return 0;
}

7. 变量&&常量

7.1. 常量

7.1.1. 字面常量

//字面常量演示
3.14;//字面常量
1000;//字面常量

7.1.2. const 修饰的常变量

//const 修饰的常变量
const float pai = 3.14f;   //这里的pai是const修饰的常变量
pai = 5.14;//是不能直接修改的!

上面例子上的 pai 被称为 const 修饰的常变量, const 修饰的常变量在 C 语言中只是在语法层面限制了变量 pai 不能直接被改变,但是 pai 本质上还是一个变量的,所以叫常变量。

7.1.3. #define 定义的标识符常量

//#define的标识符常量 演示
#define MAX 100
printf("max = %d\n", MAX);

define就是定义一个常量,即定义MAX是一个数值为100的常量.

7.1.4. 枚举常量

#include <stdio.h>
enum Sex{
 MALE,
 FEMALE,
 SECRET
};
//括号中的MALE,FEMALE,SECRET是枚举常量
int main()
{
//枚举常量演示
    printf("%d\n", MALE);
    printf("%d\n", FEMALE);
    printf("%d\n", SECRET);
    //注:枚举常量的默认是从0开始,依次向下递增1的
}

enum是一个关键字,枚举关键字

7.2. 变量:

7.2.1. 定义变量

int age = 150;
float weight = 45.5f;
char ch = 'w';

7.2.2. 变量的分类

局部变量

全局变量

#include <stdio.h>
int global = 2019;//全局变量
int main(){
    int local = 2018;//局部变量
    //下面定义的global会不会有问题?
    int global = 2020;//局部变量
    printf("global = %d\n", global);
    return 0; 
}

global = 2019就是全局变量,而下边的 local = 2018;和global = 2020是局部变量,通俗一点来理解,定义在{}之外的变量就是全局变量,定义在{}之内的变量就是局部变量。此外在代码中我们也提到了一个问题,global被定义了两次,那这样子会不会有问题呢?其实这样子是没有问题的,当局部变量和全局变量名字冲突时,局部变量优先,不建议各位这样写,毕竟看起来也很容易混乱,我们还是怎么简单怎么来比较好。

8. 判断&&选择语句

8.1 if...else

#include <stdio.h>
int main(){
	int a = 0;
	printf("你会努力吗?(选择1 or 0):>");
	scanf("%d", &a);
	if (a == 1){
		printf("努力学习\n");
	}else{
		printf("早早放弃\n");
	}
	return 0;
}

8.2 if...else if...else

#include <stdio.h>

int main() {
    int a = 2, b = 0;
    scanf("%d", &b);
    if (a == 1) {
        printf("a\n");
    } else if (b == 2) {  //这里改变了变量
        printf("b\n");
    } else {
        printf("c\n");
    }
    return 0;
}

8.3 switch

  • (1) switch括号内的常量表达式,必须是一个整型或枚举类型(上面有提到)。
  • (2) case 语句可以有任意个,case 后跟一个对应switch括号内相同数据类型的值和一个冒号(前面需要一个空格)。
  • (3) 当case内的浴具语句执行完毕后,如果未遇到break,将会继续执行下一个语句,直到遇见break或直到switc语句终止。当然,break不是必要的。
  • (4) default语句 用于switch接收的常量或枚举类型都不等于上面case语句冒号后的常量或枚举常量,同样,default也不是必要的。
  • (5) case语句和default语句后最好加上花括号。
#include<stdio.h>
int main()
{
    int n;
    scanf("%d",&n);
    switch(n){
        case 1:
            printf("你输入的是1\n");
        case 2:
            printf("你输入的是2\n");
            break;
        case 3:
            printf("你输入的是3\n");
            break;
        default:
            printf("你输入的是其他数字\n");
    }
    return 0;
}

9. 循环

9.1 while 语句

break&&continue

#include<stdio.h>

int main(){
    int n = 1; //创建一个临时变量来存放打印的值
    //当表达式为真时才进入循环
    while (n <= 10){
        printf("%d ", n);
        n++;//调整循环的部分
        if(n==8) break;
    }
    return 0;
}
#include <stdio.h>

int main() {
    int i = 1;
    while (i <= 10) {
        if (i == 5) {
//            i++;
            continue;
        }
        printf("%d ", i);
        i = i + 1;
    }
    return 0;
}

9.2 for 语句

#include <stdio.h>

int main() {
    int i = 0;
    for (i = 1; i <= 10; i++) {
        if (i == 4)
            break;
        printf("%d ", i);
    }
    return 0;
}
#include <stdio.h>

int main() {
    int i = 0;
    for (i = 1; i <= 10; i++) {
        if (i == 5)
            continue;
        printf("%d ", i);
    }
    return 0;
}

这里我们可以看到,程序运行结束后并没有像while循环那样进入死循环,而是在屏幕上输出了1 2 3 4 6 7 8 9 10 这九个数。因为当i++ 后i = 5时,进入循环部分后,if(i == 5)为真,执行continue语句,然后不执行continue语句后面的部分,程序又回到 i++,然后程序直到 i <= 10 为假结束循环。所以当continue放在调整循环次数语句后面时,容易造成程序的错误。

9.2.1 for循环变种

最简单for循环:

#include <stdio.h>

int main() {
    for (;;) {
        printf("haha\n");
    }
    return 0;
}

for循环嵌套:

#include<stdio.h>

int main() {
    int i = 0;
    for (i = 0; i < 10; i++) {
        int j = 0;
        for (j = 0; j < 10; j++) {
            printf("hehe ");
        }
        printf("\n");
    }
    return 0;
}

省略掉初始化部分:

#include<stdio.h>

int main() {
    int i = 0;
    int j = 0;
    for (; i < 10; i++) {
        for (; j < 10; j++) {
            printf("hehe ");
        }
    }
    return 0;
}

多变量控制for循环:

#include <stdio.h>

int main() {
    int i = 0;
    int j = 0;
    for (i = 0, j = 0; i < 2 && j < 5; ++i, j++) {
        printf("hehe\n");
    }
    return 0;
}

问:

//请问该循环执行多少次?
#include <stdio.h>

int main() {
    int i = 0;
    int k = 0;
    for (i = 0, k = 0; k = 0; i++, k++)
        k++;
    return 0;
}

9.3 do ... while 语句

#include <stdio.h>

int main() {
    int i = 1;//初始化部分
    do {
        printf("%d ", i);
        i = i + 1;//调整部分
    } while (i <= 10);//判断部分
    return 0;
}

10. 函数

我们求两个数的和可以下边这么写这段代码

#include <stdio.h>

int main() {
    int num1 = 0;
    int num2 = 0;
    int sum = 0;
    printf("输入两个数:");
    scanf("%d %d", &num1, &num2);
    sum = num1 + num2;
    printf("sum = %d\n", sum);
    return 0;
}

那如果我们用函数怎么写这段代码呢?

#include <stdio.h>

int Add(int x, int y) {
    int z = x + y;
    return z;
}

int main() {
    int num1 = 0;
    int num2 = 0;
    int sum = 0;
    printf("输入两个数:");
    scanf("%d %d", &num1, &num2);
    sum = Add(num1, num2);
    printf("sum = %d\n", sum);
    return 0;
}

11. 运算符

算 移 关 位 逻

11.1. 算术运算符 + - * / %

#include<stdio.h>

int main() {
    double c = 10 / 3;
    printf("%lf\n", c);
    return 0;
}

这里需要注意:当除法操作符(/)两边的操作数都是整型类型时,执行的是整型除法,所以结果是3.000000。

如果希望执行的是浮点数除法,那么需要将一个操作数写成浮点数类型。下面是代码和验证过程:

#include<stdio.h>

int main() {
    double c = 10.0 / 3;

    printf("%lf\n", c);
    return 0;
}

11.2. 移位运算符

左移操作符:<< *2

右移操作符: >> /2

#include<stdio.h>

int main() {
    int a = 4;
    a = a << 1;
    a = a >> 1;
    printf("%d", a);
    return 0;
}

11.3. 关系运算符

<——小于

<=——小于等于

>——大于

>=——大于等于

==——相等

!=——不相等

11.4. 位运算符

& --按位与操作符

| --按位或操作符

^ --按位异或操作符

注意:操作数必须是整数

按位与:

00000000000000000000000000010010--18

00000000000000000000000000001010--10

00000000000000000000000000000010---2

#include<stdio.h>

int main() {
    int a = 18;
    int b = 10;
    int c = a & b;
    printf("%d\n", c);
    return 0;
}

按位或:

按位或操作符,两个对应位同时为0则表示0,否则表示1。

-3 | 5

111111111111111111111111111111111101--3补码

0000000000000000000000000000101 -5补码

11111111111111111111111111111111101 = -3补码

#include <stdio.h>

int main() {
    int a = -3;
    int b = 5;
    int c = a | b;
    printf("c = %d\n", c);
    return 0;
}

按位异或,两数对应二进制为相同为0,相异为1。

-3 ^ 5

111111111111111111111111111111111101--3补码

0000000000000000000000000000101 -5补码

11111111111111111111111111111111000 补码

11111111111111111111111111111110111 先-1

1000000000000000000000000001000 -再按位取反(原码)-8

#include <stdio.h>

int main() {
    int a = -3;
    int b = 5;
    int c = a ^ b;
    printf("c = %d\n", c);
    return 0;
}

11.5. 逻辑运算符

&& 逻辑与

|| 逻辑或

// && 和 || 逻辑与和逻辑或是用来判断真假的
int main() {
//C语言中0为假,非0为真
    int a = 10;
    int b = 20;
    //a && b 结果为真
    //a || b 结果也为真

    int c = 0;
    int d = 10;
    //a && b 结果为假
    //a || b 结果为真

    int x = 0;
    int y = 0;
    //a && b 结果为假
    //a || b 结果为假

    return 0;
}

短路:

//逻辑或操作符的短路
#include<stdio.h>

int main() {
    int i = 0, a = 0, b = 2, c = 3, d = 4;
    i = a++ || ++b || d++;
    printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
    return 0;
}

11.6. 三目运算符

exp1 ? exp2 : exp3

//求两个数的较大值
#include <stdio.h>

int main() {
    int a = 10;
    int b = 20;
    int m = 0;

    if (a > b)
        m = a;
    else
        m = b;

    printf("m = %d\n", m);

    return 0;
}

//用条件操作符,求两个数的较大值

//int main() {
//    int a = 10;
//    int b = 20;
//
//    printf("较大值 = %d\n", a > b ? a : b);
//
//    return 0;
//}

11.7. 强制类型转换

强制类型转换是把变量从一种类型转换为另一种数据类型。例如,如果想存储一个 long 类型的值到一个简单的整型中,需要把 long 类型强制转换为 int 类型。可以使用强制类型转换运算符来把值显式地从一种类型转换为另一种类型

请看下面的实例,使用强制类型转换运算符把一个整数变量除以另一个整数变量,得到一个浮点数:

#include <stdio.h>

int main() {
    int sum = 17, count = 5;
    double mean;

    mean = (double) sum / count;
    printf("Value of mean : %f\n", mean);

}

这里要注意的是强制类型转换运算符的优先级大于除法,因此 sum 的值首先被转为 double 型,然后除以 count,得到一个类型为 double 的值。

类型转换可以是隐式的,由编译器自动执行,也可以是显式的,通过使用强制类型转换运算符来指定。在编程时,有需要类型转换的时候都用上强制类型转换运算符,是一种良好的编程习惯。

11.7.1. 整数提升

整数提升是指把小于 intunsigned int 的整数类型转换为 intunsigned int 的过程。请看下面的实例,在 int 中添加一个字符:

#include <stdio.h>

int main() {
    int i = 17;
    char c = 'c'; /* ascii 值是 99 */
    int sum;

    sum = i + c;
    printf("Value of sum : %d\n", sum);

}

在这里,sum 的值为 116,因为编译器进行了整数提升,在执行实际加法运算时,把 'c' 的值转换为对应的 ascii 值。

11.7.2. 常用的算术转换

常用的算术转换是隐式地把值强制转换为相同的类型。编译器首先执行整数提升,如果操作数类型不同,则它们会被转换为下列层次中出现的最高层次的类型:

12. 常见关键字

auto  break   case  char  const   continue  default  do   double else  enum   
extern float  for   goto  if   int   long  register    return   short  signed
sizeof   static struct  switch  typedef union  unsigned   void  volatile  while

12.1. static:

12.1.1.修饰局部变量--称为静态局部变量

#include <stdio.h>

void test() {
    int a = 1;
    a++;
    printf("%d ", a);
}

int main() {
    int i = 0;
    while (i < 10) {
        test();
        i++;
    }
    return 0;
}
#include <stdio.h>

void test() {
    static int a = 1;
    a++;
    printf("%d ", a);
}

int main() {
    int i = 0;
    while (i < 10) {
        test();
        i++;
    }
    return 0;
}

我们发现输出是连贯的a并没有被重新建立,通过这两段差别我们可以发现static修饰局部变量改变了变量的生命周期,让静态局部变量出了作用域依然存在,没有被销毁,到程序结束,生命周期才结束。

12.2.2.修饰全局变量--称为静态全局函数

#include <stdio.h>

extern int aaa;

int main() {
    printf("%d\n",aaa);
    return 0;
}

所以,static修饰全局变量的时候,这个全局变量的外部链接属性就变成了内部链接属性,其他源文件(.c)就不能使用这个全局变量了,但是这个变量自身的文件下还可以使用的。

12.2.3.修饰函数

我们建立一个源文件,写下下边这段代码

int Add(int x, int y)
{
	return x + y;
 
}

然后回到另一个的源文件,写下这段代码

#include<stdio.h>
extern int Add(int x, int y);
int main()
{
	int a = 10;
	int b = 20;
	int z = Add(a, b);
	printf("%d\n", z);
	return 0;
}

是可以正常运行的

然后我们在定义函数的源文件函数前边加上static

static int Add(int x, int y)
{
	return x + y;
}

运行之后会报错

 所以,一个函数本来是具有外部链接属性的,但是被static修饰的时候,外部连接属性就变成了内部连接属性,其他源文件就无法使用了。

12.2. #define定义常量

//define定义标识符常量
#include<stdio.h>

#define NUM 100

int main() {
    printf("%d\n", NUM);
    int n = NUM;
    printf("%d\n", n);
    return 0;
}

13. 指针

1. 内存

内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。

变量是创建内存中的(在内存中分配空间的),每个内存单元都有地址,所以变量也是有地址的。在前面我提到:*a = &a,为什么呢?

对于等号右边,它表示的是变量a的地址,它也是一个具体的值,我得用房间给它住,所以人们规定定义int *a存放a的地址。注意: 在定义指针变量时,*符号只是表示定义的是一个指针变量,而使用指针变量时*a中的*符号指的是机器通过存放的a的地址找到a的值。

#include <stdio.h>

int main() {
    int a = 100, b = 10;//定义整型变量a,b并初始化
    int *p1, *p2;     //定义指向整型数据的指针变量p1,p2;
    p1 = &a;          //把变量a的地址赋给指针变量p1
    p2 = &b;         //把变量b的地址赋给指针变量p2
    printf("a=%d,b=%d\n", a, b);//输出变量a和b的值
    printf("*p1=%d,*p2=%d\n", *p1, *p2);
}
#include <stdio.h>

int main() {
    int a[3]={1,2,3};
    int* arr=a;
    arr=arr+=1;
    *arr=22;
    printf("%d\n",*(arr+1));
    printf("%d",a[1]);

}

14. 结构体

#include <stdio.h>
#include <string.h>
 struct Person{
    char name[16];
    int age;
};

int main(){
    struct Person p={"小明",13};
    printf("%s  %d",p.name,p.age);
    return 0;
}

 加上typedef:也就是起别名的意思

别名可以直接使用,struct后面的结构体名字使用的时候必须在前面加上struct

#include <stdio.h>
#include <string.h>
typedef struct Person{
    char name[16];
    int age;
}per;

int main(){
    struct Person p1={"小明",13};
    per p2={"小华",18};
    printf("%s  %d",p1.name,p1.age);
    printf("%s  %d",p2.name,p2.age);
    return 0;
}

 另一种写法,*per,这代表per直接指向一块内存,可以存放一个结构体,而不需要再新建一个,当然,该结构体任然可以使用,再新建其他的对象。

#include <stdio.h>
#include <string.h>
#include <malloc.h>

struct Person{
    char name[16];
    int age;
}*per;

int main(){
    per = malloc(sizeof(struct Person));
    strcpy(per->name, "xiaoming");
    per->age = 16;

    printf("%s\n", per->name);
    printf("%d\n", per->age);

    free(per);

    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值