当前位置: 首页 > news >正文

零基础C入门到深入简出

文章目录

  • 零基础C入门到深入简出
    • 第一章 C语言概述
      • 1.1、数据类型、运算、表达式
      • 1.2顺序设计
    • 第二章 控制语句与数组
      • 2.1分支结构程序
      • 2.2循环结构程序
      • 2.3、数组
        • 2.3.1、一维数组
        • 2.3.2、二维数组
    • 第三章 函数与指针
      • 3.1、函数
      • 3.2、指针
        • 3.2.1、指针是什么?
        • 3.2.2、指针是一种数据类型
        • 3.2.3、间接赋值指针存在的最大意义
        • 3.2.4、指针与数组
        • 3.2.5、指针、数组与函数
    • 第四章 C语言扩展
      • 4.1、const、static专题
      • 4.2、结构体
      • 4.3、拷贝、文件、线程
        • 4.4.1、什么是浅拷贝和深拷贝
        • 4.4.2 FILE文件操作
        • 4.4.3 Thread线程
      • 4.4 正规接口规范
        • 4.4.1接口
        • 4.4.2函数扩展

零基础C入门到深入简出

第一章 C语言概述

为什么学习C语言?
C语言是一门基础的编程语言,适用底层开发、硬件开发、跨平台等场景,场景很多不管你从事什么软件或硬件开发很容易遇到C语言,很有必要学习。

从事开发人员还是零基础,不要语言束缚思维,真正用场景思维逻辑、算法等才是主要,语言可以快速学习,项目在做时候部分不理解可以查找资料不齐。

#include <stdio.h>//包含有关标准库的信息
int main() {//主方法//main函数调用库函数printf可打印字符序列,\n代表换行符printf("Hello, World!\n");return 0;
}

1.1、数据类型、运算、表达式

1、“类型”是对数据的抽象
2、类型相同的数据有相同的表示形式、存储格式以及相关的操作
3、 程序中使用的所有数据都必定属于某一种数据类型

请添加图片描述
在这里插入图片描述

变量说明:
1、程序通过变量来申请和命名内存空间int k=3;
2、通过变量名访问内存空间
3、(一段连续)内存空间的别名(是一个门牌号)
在这里插入图片描述

printf中的转换说明占位符:
1、%d 打印十进制整数
2、%f 打印浮点数
3、%c打印字符
4、%s 打印字符串
5、%ld打印长整型

在这里插入图片描述

运算符:
(1) 算术运算符(+, -, *, /, %, ++, - -)

(2) 赋值运算符(=)

(3) 圆括号运算符(( ))

(4) 强制类型转换运算符(( 类型))

(5) 求字节数运算符(sizeof)

(6) 关系运算符(<, >, <=, >=, ==, !=) 。

(7) 逻辑运算符(!, &&, ||) 。

在这里插入图片描述

1.2顺序设计

程序从main函数的起始点开始执行,在main函数的结束点结束执行。程序按照代码的先后顺序逐行执行,每个语句依次执行完毕后再执行下一条语句。

顺序程序设计涉及以下几个方面:

1、变量声明和定义:在程序开始前,可以声明和定义需要使用的变量,为其分配内存空间。

2、输入输出:程序可以通过输入函数(如scanf)接收用户的输入,并通过输出函数(如printf)显示结果。

3、运算符和表达式:C语言提供了丰富的运算符和表达式,用于对变量进行数学和逻辑运算,从而得到期望的结果。

4、函数调用:可以调用已经定义好的函数来完成特定的功能。函数可以有返回值和参数,通过函数调用实现代码的模块化和重用。

5、控制流语句:C语言提供了控制流语句,如条件语句(if语句)、循环语句(for、while、do-while循环),用于根据条件或者需求来选择执行不同的代码块。

6、数组和指针:C语言支持数组和指针的使用,可以有效地处理大量数据和引用内存地址。

7、结构体和枚举:结构体和枚举类型可以帮助组织和管理复杂的数据结构和数据类型。

第二章 控制语句与数组

在这里插入图片描述

2.1分支结构程序

1、if语句:用于根据条件执行不同的代码块

if (condition) {// 执行语句块1
}
else {// 执行语句块2
}

2、switch语句:根据表达式的值选择执行不同的代码块

switch (expression) {case value1:// 执行语句块1break;case value2:// 执行语句块2break;default:// 执行默认语句块break;
}

3、循环语句中的break和continue:用于控制循环的执行流程(略)

break语句:跳出当前循环或switch语句。
continue语句:跳过当前循环的剩余代码,进入下一次循环迭代。

4、goto语句:无条件地将控制转移到指定的标签处

goto label;
// ...
label: // 执行语句块

5、?: 三元运算符:根据条件选择不同的值

result = (condition) ? value1 : value2;

2.2循环结构程序

1、for循环

for (初始化表达式; 循环条件; 更新表达式) {// 循环体
}

初始化表达式:在循环开始前执行一次,用于初始化循环变量。
循环条件:每次循环开始前判断是否满足条件,如果满足则执行循环体,否则跳出循环。
更新表达式:在每次循环结束后执行一次,用于更新循环变量的值。
2、while循环,先判断条件

while (循环条件) {// 循环体
}

3、do-while循环,先执行一次循环体

do {// 循环体
} while (循环条件);

2.3、数组

2.3.1、一维数组

数组语法type arrayName[arraySize];
int mark[100];本质是什么?

在这里插入图片描述

1、数组初始化

int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//定义一个数组,同时初始化所有成员变量
int a[10] = { 1, 2, 3 };//初始化前三个成员,后面所有元素都设置为0
int a[10] = { 0 };//所有的成员都设置为0
//[]中不定义元素个数,定义时必须初始化
int a[] = { 1, 2, 3, 4, 5 };//定义了一个数组,有5个成员
char name[10] = "John"; // 其他元素默认初始化为'\0'
2.3.2、二维数组

type arrayName[rowSize][columnSize];

初始化数组

int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};int a[3][4] = { {0, 1, 2, 3} , /*  初始化索引号为 0 的行 */{4, 5, 6, 7} ,   /*  初始化索引号为 1 的行 */{8, 9, 10, 11}   /*  初始化索引号为 2 的行 */
};//案例一
int a[3][4] = {{1},{2},{3}};
等价:
int a[3][4] = {{1,0,0,0},{2,0,0,0},{3,0,0,0}};
//案例二
int a[3][4] = {{1}};
等价:
int a[3][4] = {{1,0,0,0},{0,0,0,0},{0,0,0,0}};
char names[2][10] = {"John", "Alice"}; // 其他元素默认初始化为'\0'

遍历:

int matrix[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};// 使用嵌套循环遍历二维数组
for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {printf("%d ", matrix[i][j]);}printf("\n");
}

int a[2][3]={{1,2,3},{4,5,6}};
在这里插入图片描述

第三章 函数与指针

3.1、函数

1、无返回值函数(void函数)

void printMessage() {printf("Hello, World!\n");
}

2、有返回值函数

int add(int a, int b) {return a + b;
}

3、函数原型(函数声明)

int add(int a, int b); // 函数原型

4、递归函数
递归函数是指能够调用自身的函数。使用递归可以解决那些可以被分解成较小、相似形式的问题

int factorial(int n) {if (n == 0) {return 1;} else {return n * factorial(n - 1);}
}

5、内置函数(标准库函数)

printf()、scanf()

6、预处理器函数(宏函数)

#define MAX(a, b) ((a) > (b) ? (a) : (b))
int maxNum = MAX(10, 5); // 宏替换为最大值的判断表达式:((10) > (5) ? (10) : (5))

7、内联函数(inline函数)

inline int myfunc(int a, int b)
{return a < b ? a : b;
}

内联函数\宏代码片段都是为减少而外开销
内联函数由 编译器处理,直接将编译后的函数体插入调用的地方
宏代码片段 由预处理器处理, 进行简单的文本替换,没有任何编译过程
用法区分案例

#include <stdio.h>#define MYFUNC(a, b) ((a) < (b) ? (a) : (b))int myfunc(int a, int b);
// 定义一个内联函数
inline int myfunc(int a, int b)
{return a < b ? a : b;
}int main() {int a = 1;int b = 3;int c = myfunc(++a, b);// int c = MYFUNC(++a, b);printf("a = %d\n", a);printf("b = %d\n", b);printf("c = %d\n", c);return 0;
}

函数调用模型
在这里插入图片描述

3.2、指针

3.2.1、指针是什么?

指针是用来存放地址的,地址是唯一标示一块地址空间的
一个房间的门口门牌号:2008,2008地址就是指针,这个门牌号的房间存储人就是它存储的变量

int main() {int a = 100//定义整型变量a,b并初始化(开辟内存空间存储10)int* p1;     //定义指向整型数据的指针变量p1;p1 = &a;          //把变量a的地址赋给指针变量p1printf("a=%d\n", a);//输出变量a值printf("*p1=%d\n", *p1);}

指针 &a(0xfff)
指针就是地址,地址就是指针。

指针变量 p1
指针变量是变量。定义一个指针变量,是在内存中开辟一个空间,该空间里面存放地址

在这里插入图片描述

3.2.2、指针是一种数据类型

1、指针初始化(两步骤)与获取指针指向变量值:

int nums=10;//定义一个变量
int *p = &nums;//定一个指针变量指向内存地址&nums
int value = *p;//访问指针所指向的值
*p=12;
int *ptr=NULL;//空指针NULL

1)两码事:指针变量和它指向的内存块变量
2)条件反射:指针指向某个变量,就是把某个变量地址否给指针
*p放在等号的左边赋值(给内存赋值)
*p放在等号的右边取值(从内存获取值)

2、指针变量和它指向的内存块是两个不同的概念
//含义1 给p赋值p=0x1111; 只会改变指针变量值,不会改变所指的内容;p = p +1; //p++
//含义2 给p赋值p=1; 不会改变指针变量的值,只会改变所指的内存块的值
//含义3 =左边p 表示 给内存赋值, =右边p 表示取值 含义不同切结!
//含义4 =左边int*p
//含义5 保证所指的内存块能修改

3、多级指针

#include <stdio.h>int main() {int num = 10;int *ptr1 = &num; // 一级指针int **ptr2 = &ptr1; // 二级指针printf("Value: %d\n", **ptr2); // 解引用操作printf("Address: %p\n", *ptr2); // 一级指针地址printf("Double Address: %p\n", ptr2); // 二级指针地址return 0;
}
3.2.3、间接赋值指针存在的最大意义

2、间接赋值、直接赋值
*p间接赋值成立条件:3个条件
a)2个变量(通常一个实参,一个形参)
b) 建立关系,实参取地址赋给形参指针
c) *p形参去间接修改实参的值

int nums = 0; //实参
int *p = &nums;
nums = 1;//直接赋值
*p =2 ; //通过*形参 == 间接地改变实参的值
*p成立的三个条件:

间接赋值


int *p = &nums;
nums = 1;//直接赋值
上面两部放函数实现
int showbuf(int *p)

理解指针必须和内存四区概念相结合
1)主调函数 被调函数
a)主调函数可把堆区、栈区、全局数据内存地址传给被调用函数
b)被调用函数只能返回堆区、全局数据
2)内存分配方式
a)指针做函数参数,是有输入和输出特性的。

在这里插入图片描述

3.2.4、指针与数组

1、一级指针与一维数组
int a[]={3,2,1}; int *p = a
知识点:1、a的类型为int[2],p的类型为int *
2、a=数组的首地址,p指向数组首地址

a = &a[0] = &a 只是地址相等 意义不一样
&a是一个数组指针 其类型为 int (*)[2];
a+1 相当于 a的地址+sizeof(int)*1
&a+1 相当于 a的地址 + sizeof(int [2])*1

	int a[]={3,2,1};int *p = a;printf("p = %d\n",p);printf("&a = %d\n",&a);printf("a = %d\n",a);printf("&a[0] = %d\n",&a[0]);printf("&p = %d\n\n",&p);printf("*p = %d\n",*p);printf("a[0] = %d\n",a[0]);int a[]={1,2,3};int *p = a;printf("*(p+1) = %d\t",*(p+1));printf("p[1] = %d\n",p[1]);printf("*(a+1) = %d\t",*(a+1));printf("a[1] = %d\n\n",a[1]);printf("p = %d\n",p);printf("p+1 = %d\n",p+1);printf("&p[1] = %d\n",&p[1]);printf("a+1 = %d\n",a+1);printf("&a[1] = %d\n",&a[1]);

指针多维数组
指针数组:
这里就要先说明和[]的优先级了,[]的优先级是高于的,所以int *p[3];等同于int *(p[3]);。所以它是一个指针数组

#include <stdio.h>int main() {int num1 = 10;int num2 = 20;int num3 = 30;int *p[3] = {&num1, &num2, &num3}; // 指针数组存储整型数据的指针for (int i = 0; i < 3; i++) {printf("Value: %d\n", *(p[i])); // 解引用指针获取整型数据的值printf("Address: %p\n", p[i]); // 打印指针地址printf("\n");}return 0;
}

数组指针:
int a[3][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}};
int (*p)[4];
a[0]、a[1]、a[3]可以在二维数据拆为每个分别有3个参数一维数组首地址

#include <stdio.h>
int main()
{int a[3][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}};int(*p)[4];p = a;printf("%d\n", sizeof(*(p + 1)));return (0);
}

a[i][j] = *(p[i]+j) = ( (p+i)+j)
a[1][0]的值 ((p + 1))
a[1][1]的值
(
(p + 1)+1)

	int a[2][3]={1,2,3,4,5,6};printf("一维数组:\n");printf("a = %d\n",a);printf("*a = %d\n",*a);printf("&a = %d\n",&a);printf("a[0] = %d\n",a[0]);printf("&a[0][0] = %d\n\n",&a[0][0]);printf("二维数组:\n");printf("a[1][2] = %d\n",a[1][2]);printf("*((a[1])+2) = %d\n",*((a[1])+2));printf("*(*(a+1)+2) = %d\n",*(*(a+1)+2));

在这里插入图片描述

int arr[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int (*ptr)[3] = arr; // 定义一个指向整型数组的指针,指向二维数组arrfor (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {printf("%d ", *(*(ptr + i) + j)); // 使用指针访问二维数组元素}printf("\n");
}

int (*p)[4];是数组指针,它指向二维数组中每个一维数组的类型,它指向的是一个数组。

int *p[4];是指针数组,它是一个数组,数组中每个数是指向int型的指针

3.2.5、指针、数组与函数

一级指针典型用法(指针做函数参数)
int showbuf(char *p)
int showArray(int *array, int iNum)

void showArray(int[]array, int iNum) {for (int i = 0; i < iNum; i++) {printf("%d ", array[i]);}printf("\n");
}void showArray(int *array, int iNum) {for (int i = 0; i < iNum; i++) {printf("%d ", array[i]);}printf("\n");
}

malloc 和 free动态分配和释放内存

malloc\free

一级指针做输入
int showbuf(char *p)
int showArray(int *array, int iNum)
一级指针做输出
int goLen(char *pName, int *len);
理解
主调函数还是被调用函数分配内存
被调用函数是在heap/stack上分配内存

二级指针典型用法(指针做函数参数)
二级指针做输入
int main(int arc ,char *arg[]); 字符串数组
int shouMatrix(int [3][4], int iLine);
二级指针做输出
int GetName(char **name);

野指针的避免

  1. 指针初始化
  2. 小心指针越界
  3. 指针指向空间释放即使置NULL
  4. 避免返回局部变量的地址
  5. 指针使用之前检查有效性
//指针初始化
#include<stdio.h>
int main()
{int* p;                       *p = 10;  return 0;
}//指针越界
int main()
{int arr[10] = { 0 };int i = 0;int* p = arr;for (i = 0; i <= 10; i++){*p = i;                   //i=10时越界}return 0;//返回局部变量的地址
int* test()
{int a = 10;return &a;
}//指针使用之前检查有效性
int showbuf(char *p)
{if(p==NULL){}
}

第四章 C语言扩展

4.1、const、static专题

int main()
{
const int a;  //
int const b; 
const char *c;
char * const d; char buf[100]
const char * const  e ;return 0;
}int goFun(const )

初级理解:const是定义常量----->const意味着只读

含义:
//第一个第二个意思一样 代表一个常整形数
//第三个 c是一个指向常整形数的指针(所指向的内存数据不能被修改,但是本身可以修改)
//第四个 d 常指针(指针变量不能被修改,但是它所指向内存空间可以被修改)
//第五个 e一个指向常整形的常指针(指针和它所指向的内存空间,均不能被修改)

//合理的利用const,
//1指针做函数参数,可以有效的提高代码可读性,减少bug;
//2清楚的分清参数的输入和输出特性

结论:
//指针变量和它所指向的内存空间变量,是两个不同的概念。。。。。。
//看const 是放在*的左边还是右边 看const是修饰指针变量,还是修饰所指向的内存空变量

在C语言中,static是一个关键字,用于修饰变量、函数和数据类型
1、静态局部变量

void myFunction() {static int count = 0; // 静态局部变量count++;printf("Count: %d\n", count);
}int main() {myFunction(); // 输出:Count: 1myFunction(); // 输出:Count: 2return 0;
}

2、静态全局变量、静态全局变量


#include <stdio.h>static int count = 0; // 静态全局变量void increment() {count++;
}
static void myFunction() { // 静态函数printf("Hello, World!\n");
}void display() {printf("Count: %d\n", count);
}int main() {increment();display(); // 输出:Count: 1return 0;
}

4.2、结构体

结构体类型定义及结构体变量定义
结构体是一种构造数据类型
用途:把不同类型的数据组合成一个整体-------自定义数据类型
结构体类型定义


声明一个结构体类型
struct _Teacher
{char	name[64];//64char	tile[32];int		age; //4char	addr[128];
};struct _Student {char name[32];char title[32];int age;char addr[128];
} s1, s2;//定义类型的同时,定义变量;typedef struct _Teacher
{char	name[64];//64char	tile[32];int		age; //4char	addr[128];}AdvTeacher;//初始化结构体变量的几种方法
//1)
struct _Teacher t4 = {"name2", "tile2", 2, "addr2"};
//2)
struct Dog1
{char	name[32];char	tile[32];int		age;char	addr[128];
}d5 = {"dog", "gongzhu", 1, "ddd"};// 定义匿名结构体类型并创建结构体变量struct {char name[32];char title[32];int age;char addr[128];} s3;// 给结构体成员赋值strcpy(s3.name, "John");strcpy(s3.title, "Mr.");s3.age = 20;strcpy(s3.addr, "123 Main St");// 创建指向结构体变量的指针struct {char name[32];char title[32];int age;char addr[128];} *ptr_s3;// 给结构体成员赋值通过指针访问strcpy(ptr_s3->name, "John");strcpy(ptr_s3->title, "Mr.");ptr_s3->age = 20;strcpy(ptr_s3->addr, "123 Main St");

4.3、拷贝、文件、线程

4.4.1、什么是浅拷贝和深拷贝

浅拷贝就是直接赋值
深拷贝就是把一个内存值拷贝到另外一个内存,相互不影响

#include <stdlib.h>
#include <string.h>
#include <stdio.h>typedef struct Teacher
{char name[64];int age ;char *pname2;}Teacher;//如果 想执行深copy,再显示的分配内存
void copyTeacher(Teacher *to, Teacher *from)
{*to = *from;to->pname2 = (char *)malloc(100);strcpy(to->pname2, from->pname2);//memcpy(to, from , sizeof(Teacher));
}
void main51()
{Teacher t1;Teacher t2;strcpy(t1.name, "name1");t1.pname2 = (char *)malloc(100);strcpy(t1.pname2, "ssss");//t1 copy t2copyTeacher(&t2, &t1);if (t1.pname2 != NULL){free(t1.pname2);t1.pname2 = NULL;}if (t2.pname2 != NULL){free(t2.pname2);t2.pname2 = NULL;}printf("hello...\n");system("pause");return ;
}
4.4.2 FILE文件操作

1、常用的函数有fopen、fclose、fread、fwrite

4.4.3 Thread线程

1、定义pthread_t
2、创建方法 :void *Fun(void *arg);
3、创建pthread_create
4、等待线程结束 pthread_join

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>#define NUM_THREADS 5// 线程函数
void *printHello(void *threadID) {long tid = (long)threadID;printf("Hello from thread %ld\n", tid);pthread_exit(NULL);
}int main() {pthread_t threads[NUM_THREADS];int rc;long t;// 创建多个线程for (t = 0; t < NUM_THREADS; t++) {printf("Creating thread %ld\n", t);rc = pthread_create(&threads[t], NULL, printHello, (void *)t);if (rc) {printf("Error creating thread: %d\n", rc);exit(-1);}}// 等待所有线程完成for (t = 0; t < NUM_THREADS; t++) {pthread_join(threads[t], NULL);}printf("All threads have finished execution.\n");return 0;
}

4.4 正规接口规范

4.4.1接口

1、提供头文件h对应方法申明
2、c文件方法实现

4.4.2函数扩展

1、指针函数

<数据类型>  *<函数名称>(<参数说明>){语句序列;}

2、函数指针

<数据类型> (*<函数指针名称>)(<参数说明列表>);int test(int a, int b, int (*pFunc)(int,int));

定义函数指针类型

typedef <数据类型> (*<函数指针类型名称>)(<参数说明列表>);typedef int (*MFunc)(int, int);
http://www.xdnf.cn/news/821395.html

相关文章:

  • RPMforge(Repoforge)源
  • 遗传算法求解TSP问题
  • 冒险岛无敌挂小思路
  • dwr
  • WBSC垒球世界杯规则·野球1号位
  • python图书销售管理系统(案例分析)
  • C#:读取数据DataReader
  • shell(7):四则运算
  • RDCMan之DPI 和 Screen Resolution设置
  • browser插入数据 db_SQLite Database Browser数据库查看器图文使用教程
  • ckplayer.js视频播放插件
  • sql中in、exists和not exists的用法
  • 基于PHP的编程类MOOC网站设计与实现
  • MSSQL数据库的安装与使用
  • C++程序正向编译逆向反编译(一)
  • FPGA学习——触发器(FF)
  • MySQL数据库优化(基于酒店2000w条数据)
  • 3dmax vray如何创建真实的灯光?3dmax vray 室内照明教程
  • 番茄花园 Windows XP Pro SP2 美化版 V 6.2
  • LCD1602中文资料
  • java关键字abstract(抽象)详解
  • Android中layout过程详解
  • 网络 || 科来网络分析系统
  • 0磁道损坏的硬盘如何修复?
  • 分享70个Java源码总有一个是你想要的
  • Linux的安装与配置(保姆级教学)
  • Servlet--HttpServletRequest获取请求信息(请求头、请求行、参数)详解
  • Linux网络命令详解
  • 05 ORM
  • 天龙八部单机版(兽血沸腾):大背包天机华裳格武道二