程序:一组计算机能识别和执行的指令。
计算机语言:计算机和人都能识别的语言。
C语言是在B语言的基础上发展而来。
计算机语言发展阶段:
C语言特点:
函数包括:函数首部(第一行)+函数体(‘{’+内容+‘}‘),函数体=函数声明(即函数原型)+执行部分。
注意易错:
全局变量与局部变量同名:在局部变量作用域内,全局变量被“屏蔽”。
变量的静态存储方式和动态存储方式:
malloc
**、**free
等。动态存储的变量在程序运行时根据需要分配内存,因此其生命周期和作用域可以在运行时动态地确定。
动态存储方式主要包括:自动变量+形参等等程序的内存区域:
字符串的注意事项
比较
"hello"=="hello" //两个不相等,比较的是地址,要用strcmp进行比较
赋值
char ch[5];
ch="hello"; //error,而是strcpy(ch,"hello");
待续
【例1.1】 最简单的C语言程序:
#include <stdio.h>//包含输入输出函数
int main()//返回int型,所以需要return 0;
{
printf("hello world!\n");//换行:‘\n’,printf表示输出
return 0;
}
【例1.2】求两个整数和
#include <stdio.h>
int main()
{
int a,b;
scanf("%d%d",&a,&b);//scanf()输入函数,除字符串都要加&
int sum=a+b;
printf("a+b=%d\n",sum);
return 0;
}
【例1.3】求两个整数的较大者
#include <stdio.h>
int max(int num1,int num2);
int main()
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",max(a,b));
return 0;
}
int max(int num1,int num2){
return num1>num2?num1:num2;
}
程序=算法+数据结构 算法的特性:
循环结构:当型和直到型
1. 判断是否是闰年(被4整除但不可被100整除 || 被400整除) 2. 1+1/2-1/3+1/4-...+1/n
【例2.1】计算1*2*3*4*5
#include <stdio.h>
int Mul(int n);//计算从1乘至n的积
int main(){
int n;
scanf("%d",&n);
printf("乘积为%d\n",Mul(n));
return 0;
}
int Mul(int n){//计算从1乘至n的积
int product=1;
for(int i=1;i<=n;i++){
product*=i;
}
return product;
}
【例2.2】略(文字表述)
【例2.3】判断是否是闰年(被4整除但不可被100整除 || 被400整除)
#include <stdio.h>
void RunYear(int n1,int n2);//判断n1至n2中属于闰年的年份并输出
int main()
{
int year1,year2;
scanf("%d%d",&year1,&year2);
RunYear(year1,year2);
return 0;
}
void RunYear(int n1,int n2){//判断n1至n2中属于闰年的年份并输出
int count=1;//限制输出格式
for(int i=n1;i<=n2;i++){
if((i%4==0 && i%100!=0) || (i%400==0)){
if(count%6==0){
printf("\n");
count=1;
}
count++;
printf("%d ",i);
}
}
}
【例2.4】1+1/2-1/3+1/4-...+1/n
#include <stdio.h>
double Count(int n);
int main()
{
int n;
scanf("%d",&n);
printf("sum=%.2f",Count(n));
}
double Count(int n){//计算并返回值:1+1/2-1/3+1/4-...+1/n
int sign=1;
double add=0;
for(int i=1;i<=n;i++){
add=add+sign*(1.0/i);
sign=(-1)*sign;
}
return add;
}
【例2.5】判断一个大于等于3的正整数是否为素数(只能被1和它本身整除)
#include <stdio.h>
int PrimeNum(int n);//n是素数返回1,否则-1
int main()
{
int n;
scanf("%d",&n);
if(PrimeNum(n)>0){
printf("%d是素数\n",n);
}
else printf("%d不是素数\n",n);
return 0;
}
int PrimeNum(int n){//n是素数返回1,否则-1
for(int i=2;i<=n;i++){
if(i==n) {return 1;break;}
if(n%i==0){return -1;break;}
}
return 0;
}
1.常量
2.变量
3.常变量
4.标识符:字母、数字(不可’首位)或下划线
#include <stdio.h>
int main()
{
printf("10%%5=%d 5%%10=%d",10%5,5%10);//输出:10%5=0 5%10=5
return 0;
}
scanf:
printf:
putchar(参数):输出单个字符
getchar():输入单个字符
选择语句:
#include <stdio.h>
int main() {
int choice;
printf("Enter a number (1-3): ");
scanf("%d", &choice);
switch (choice) {
case 1:
printf("You chose option 1.\n");
break;
case 2:
printf("You chose option 2.\n");
break;
case 3:
printf("You chose option 3.\n");
break;
default:
printf("Invalid choice.\n");
}
return 0;
}
switch语句的注意事项:
case
**后要加**break
**: 在switch
语句的每个case
块结束后都要加上break
语句,以避免穿透到下一个case
。如果省略break
,程序会继续执行后面的case
块,直到遇到break
或者switch
语句结束。switch
**表达式的类型:** switch
表达式的类型必须是整数类型+字符型(int
、char
、enum
等)。不支持浮点数或字符串作为switch
的表达式。case
**中的常量表达式: case
标签中的值必须是常量**。default
**语句(可省略):** default
语句通常放在switch
的最后,用于处理未匹配到任何case
的情况。然而,它也可以放在任何位置。条件表达式:表达式1?表达式2:表达式3;
示例:
max=a>b? a:b;
//等价于
if(a>b) max=a;
else max=b;
循环语句:
注意:
break:终止循环 continue:结束本次循环,进入下次循环 for的表达式3如i++会被执行
数组特点:
C语言无string和bool类型
注意:
1.
int a[10];//范围是a[0]至a[9],不存在a[10]
2.
//需要提前开辟大小
int a[10];//ok
int n=10;
int a[n];//error!
int a[10];//a[0]至a[9],共10个
int a[10]={1,2};//整型后面默认0,字符型默认'\0',指针默认NULL
int a[0]={0};//全0
int a[0]=123;//类推
float a[3][5];
float a[3][5]={{1,2},{3,4,5},{}};
float a[2][2]={0,1,2,3};
char c[10]={'h','e','l','l','o'};///长度10
char c[]={'h','e','l','l','o'};//长度5
char c[]={"hello"};//长度6
#include <stdio.h>
double CountNum(int n);
int main(){
char ch1[]={'h','e','l','l','o'};//5
char ch2[]="hello";//5+1
printf("ch1.len=%d ch2.len=%d\n",sizeof(ch1),sizeof(ch2));
char c1[]={"I am happy"};//10+1
char c2[]="I am happy";//10+1
printf("c1.len=%d c2.len=%d\n",sizeof(c1),sizeof(c2));
char c3[]={'I',' ','a','m',' ','h','a','p','p','y','\0'};//10+1
char c4[]={'I',' ','a','m',' ','h','a','p','p','y'};//10
printf("c3.len=%d c4.len=%d\n",sizeof(c3),sizeof(c4));
return 0;
}
函数调用:
函数类型:
数组做函数参数示例:
内部函数和外部函数:
数组做参数在函数内变化,则原数组值也会变。示例:
#include <stdio.h>
void inv(int a[],int n);
int main()
{
int a[5]={1,2,3,4,5};
inv(a,5);
for(int i=0;i<5;i++){
printf("%d ",a[i]);
}
return 0;
}
void inv(int a[],int n)
{
for(int i=0;i<n-1;i++){
for(int j=0;j<n-1-i;j++){
if(a[j]<a[j+1]){
int t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
}
基本概念:
指针就是地址=数据类型+存储编号 int a1;float a2;//前后的地址不同
int a;
int * ptr; //指针变量是ptr,类型是int *
ptr=&a;
指针的强制类型转换需要加上*,如
int intValue = 42;
int *intPointer = &intValue;
// 强制转换int指针为float指针
float *floatPointer = (float*)intPointer;
指针数组:每个元素存放一个地址,应用场景:指向若干字符串+做main()的形参
int *p[4]; //指针数组
int (*p)[4]; //指针变量:指向一维数组
const指针用法详见:define与const关键字的多种用法-CSDN博客
【例8.2】看懂即可
/*地址变,值不变*/
#include <stdio.h>
int main()
{
int a,b;//5 3
scanf("%d%d",&a,&b);
int *ptr1=&a;
int *ptr2=&b;
if(a>b){
int t;t=ptr1;ptr1=ptr2;ptr2=ptr1;
}
printf("a=%d b=%d\n",a,b);//5 3
printf("*ptr1=%d *ptr2=%d",*ptr1,*ptr2);//3 5
return 0;
}
【例8.3】看懂即可
#include <stdio.h>
void swap(int *ptr1,int *ptr2);
int main()
{
int a,b;//5 3
scanf("%d%d",&a,&b);
int *ptr1=&a;
int *ptr2=&b;
if(a>b){
swap(ptr1,ptr2); //而不是swap(*ptr1,*ptr2);
}
printf("a=%d b=%d\n",a,b);//5 3
printf("*ptr1=%d *ptr2=%d",*ptr1,*ptr2);//3 5
return 0;
}
void swap(int *ptr1,int *ptr2){//地址不变;a,b值交换
int t=*ptr1;
*ptr1=*ptr2;
*ptr2=t;
}
/*
void swap(int *ptr1,int *ptr2){//地址变;a,b值不变
int *t=ptr1;
ptr1=ptr2;
ptr2=t;
}*/
/*
void swap(int ptr1,int ptr2){//没有用
int t=ptr1;
ptr1=ptr2;
ptr2=t;
}*/
一维数组:
//一维数组
int a[5]={1,2,3,4,5};
int *ptr1=&a[0];//等价于int *ptr1=a;
&a i 等 价于 p+i 等价于a+i
*(p+i) 等价于 *(a+i)等价于a i
scanf("%d",p);
多维数组:
&a0 等价于 * (a+0)+i 等价于 a0+i
a0 等价于 *(* (a+0)+i) 等价于 *(a0+i)
举例:a1表示为 *(*(a+1)+2)而非*(a+1+2),后者表示a3
int a[3][4]={1,2,3,0,0,0,0,0,0};
int *p=a[0];
int (*p)[4]=a;//指针变量p指向 包含4个元素的一维数组
//(*p)[0],(*p)[1],(*p)[2],(*p)[3]分别代表a[0]至a[3]
字符串
对于字符指针指向字符数组,需要注意使用scanf需要加&,后续定义或输出都不加*和&。
对于字符指针指向字符串,需要注意使用scanf不要加&,后续定义加&,输出不加*。
字符指针指向字符数组
char *str="hello world";
//等价于
char *str;
str="hello world";//而不是* str="hello world";
printf("%s",str);//而不是printf("%s",* str);
#include <stdio.h>
int main(){
/*简单示例*/
char ch[100];
scanf("%s",&ch);//字符串则不用加 &
char *str;
str = ch; // 而不是 str =& ch;
printf("%s\n", str);
return 0;
}
字符指针指向字符串【C++程序,C语言不提供string类型】
#include <iostream>
#include <cstring>
using namespace std;
int main(){
/*简单示例*/
string s;
getline(cin,s);//字符串使用scanf 则不用加 &
char *str;
str = &s[0]; // 而不是 str =& ch;
printf("%s\n", str);
return 0;
}
/*
hellow djck
hellow djck
*/
【例8.8】数组翻转
#include <stdio.h>
void inv(int a[],int n);//数组翻转
int main()
{
int a[6]={1,2,3,4,5,6};
inv(a,6);
for(int i=0;i<6;i++){
printf("%d ",a[i]);//6 5 4 3 2 1
}
return 0;
}
//等价于void inv(int *a,int n){
void inv(int a[],int n){//数组翻转
for(int i=0;i<n/2;i++){
int j=n-i-1;
int t=a[i];
a[i]=a[j];
a[j]=t;
}
}
局部变量存放栈区,而malloc开辟的数据存放在堆区。
malloc
和 free
是 C 语言中用于动态内存分配和释放的函数
需要导入
#include <stdlib.h>
头文件
int *a=(int *)malloc(sizeof(int));//变量
int *arr=(int*)malloc(sizeof(int) * 5);//数组
注意:使用 malloc
分配内存后,一定要使用 free
来释放,以防止内存泄漏。
示例:
#include <stdio.h>
#include <stdlib.h>//调用maloc和free
int main() {
// 分配一个可以存储 5 个整数的内存块
int *arr=(int*)malloc(5 * sizeof(int));
// 使用动态分配的内存
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}
// 打印数组元素
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
// 释放动态分配的内存
free(arr);
int *a=(int *)malloc(sizeof(int));
a=5;
printf("a=%d\n",a);
free(a);
return 0;
}
注意在使用
void *
指针时,为了正确解引用指针并获取其指向的值,需要在使用前进行类型转换。无法进行指针运算 malloc返回的就是void *指针
下面代码中使用了 (int*)
、(double*)
和 (char*)
分别进行了类型转换。
#include <stdio.h>
int main() {
// 声明一个 void 指针
void *p;
// 声明一些变量
int num = 10;
double pi = 3.14159;
char letter = 'A';
// 将 void 指针指向不同类型的变量
p = #
printf("整数变量的值:%d\n", *((int*)p));
p = π
printf("双精度浮点数变量的值:%lf\n", *((double*)p));
p = &letter;
printf("字符变量的值:%c\n", *((char*)p));
return 0;
}
作用:不同数据类型的组合型,结构体长度=各个成员变量长度累加 结构体类型声明形式
示例:
#include <stdio.h>
#include <string.h>
// 定义学生结构体
struct Student {
int studentID;
char name[50];
int age;
float GPA;
};
int main() {
// 声明一个学生结构体变量
struct Student student1;
// 初始化结构体成员
student1.studentID = 12345;
strcpy(student1.name, "John Doe");//不可student1.name="John Doe";
student1.age = 20;
student1.GPA = 3.8;
// 打印学生信息
printf("Student ID: %d\n", student1.studentID);
printf("Name: %s\n", student1.name);
printf("Age: %d\n", student1.age);
printf("GPA: %.2f\n", student1.GPA);
// 声明一个指向结构体的指针
struct Student *ptrStudent;
// 让指针指向学生结构体变量
ptrStudent = &student1;
// 通过指针访问结构体成员
printf("\nVia Pointer:\n");
printf("Student ID: %d %d\n", ptrStudent->studentID,(*ptrStudent).studentID);
printf("Name: %s %s\n", ptrStudent->name,(*ptrStudent).name);
printf("Age: %d %d\n", ptrStudent->age,(*ptrStudent).age);
printf("GPA: %.2f %.2f\n", ptrStudent->GPA,(*ptrStudent).GPA);
return 0;
}
作用:同一段存储单元存放不同类型的变量,共用体长度=max(各个成员变量的存储长度) 共用体类型声明形式
注意:同一时间只能存在一个成员。
作用:一个变量只有几种可能的值 枚举型声明形式
注意:枚举元素按常量处理,不能赋值。默认从0开始赋值。
#include <stdio.h>
// 定义一个枚举类型
enum Weekday {
SUNDAY, // 0
MONDAY, // 1
TUESDAY, // 2
WEDNESDAY, // 3
THURSDAY, // 4
FRIDAY, // 5
SATURDAY // 6
};
int main() {
// 声明一个枚举变量
enum Weekday today;
// 给枚举变量赋值
today = WEDNESDAY;
// 使用枚举变量
switch (today) {
case SUNDAY:
printf("It's a lazy day!\n");
break;
case MONDAY:
printf("Start of the workweek\n");
break;
case WEDNESDAY:
printf("Halfway through the week!\n");
break;
default:
printf("It's a regular day\n");
}
return 0;
}
嘘,听说有一位C语言大师突破了次元壁,成功通关了编程的炼金之路!从入门到进阶,你的代码之旅如同编程宇宙的星空,熠熠生辉。你不仅掌握了代码的秘法,更诠释了编程的独特魔力。每一次Debug都是一场魔法修炼,每一行代码都是一篇炫目的咒语。恭喜你,编程冒险家,你已经成为这片代码大陆的传奇英雄。未来等着你用键盘书写更加壮丽的代码史
诗,展开属于你的数字冒险。继续释放编码魔法,让代码的光芒照亮前行的路途!