C语言学习笔记

结构体(struct)

结构体的嵌套

struct point{int x;int y;
};//定义平面上的点
struct rectangle{struct point p1;struct point p3;
}//已知斜对角两点,可定义一个矩形

如果有struct rectangle r;,就可以有r.p1.xr.p1.yr.p2.xr.p2.y
如果有变量定义:

struct rectangle r, *rp;
rp = &r;

注意:r.p1.xrp->p1.x是两种等价的形式。rp->p1->x写法错误,因为p1不是指针。

//对嵌套的结构体赋值
struct rectangle r = {{-1,0},{{1,1}};
struct rectangle react[]={{{-1,0},{{1,1}},{{2,1},{{3,7}}
};

自定义数据类型

C语言提供 typedef 的功能来声明一个已有的数据类型的新名字
typedef int Length使得Length成为int类型的别名

typedef int Length;
Length a, b, len;
typedef struct ADate{int x;int y;
} Date;//Date 为struct ADate 的新名字
int main()
{Date test = {1, 2};//利用Date 定义结构体变量testprintf("x=%d y=%d\n", test.x, test.y);
}
//为字符串类型取名typedef char *string;string s = "hello";typedef char strings[10];//string为长度为10的字符串类型strings s2 = "world";printf("s=%s s2=%s\n", s, s2);

联合(union)

union anelt {int i;char c;
} elt1, elt2;elt1.i = 4;elt2.c = 'a';printf("size=%d\n",sizeof(union anelt));//size=4

上面代码的含义是anelt的成员是一个int或是一个char,union类型的大小由成员中最大值决定

typedef union{int i;char ch[sizeof(int)];
} CHI;CHI chi;chi.i = 1234;int i;printf("i=0x%X\n", chi.i);//1234的16进制为0x000004D2for (i = 0; i < sizeof(int); i++){printf("%02hhX", chi.ch[i]);}printf("\n");

x86cpu为小端机,内存存放数时 低位在前 ,故chi.ch[i]输出了D2040000,说明chi.ch与chi.i公用同一处内存空间。

全局变量

全局变量初始化:
1.没有做初始化的全局变量会得到0值,指针会得到NULL
2.只能用编译时刻已知的值来初始化全局变量
3.它的初始化在main函数之前

int f(void);
int gall = 12;
int main()
{printf(" in %s gall1=%d\n", __func__, gall);//gall = 12f();//gall = 14printf(" in %s gall2=%d\n", __func__, gall);//gall = 14
}
int f(void){gall += 2;printf(" in %s gall_f=%d\n", __func__, gall);
}

全局变量的赋值不能是变量

int gall = 12;
int gall2 = gall;//gall是变量,会报错
int gall3 = f();//同样会报错

正确的做法是

const int gall = 12;
int gall2 = gall;

还需要注意,如果函数内部存在与全局变量同名的变量,全局变量会被隐藏

静态本地变量

  • 静态本地变量实际上是特殊的全局变量,位于相同的内存区域
  • 静态本地变量具有全局的生存性,函数内的局部作用域
int gall = 100;
int f(void);
int main()
{f();//i=2f();//i=3
}
int f(void){static int i=1;//不加static每次运行函数会初始化i为1printf("&gall=%p &i=%p\n", &gall, &i);i++;printf("i=%d\n", i);
}
//&gall=403014 &i=403010刚好相差4个字节,故i为全局变量

返回指针的函数需要注意:

  • 返回本地变量的地址是危险的
  • 返回全局变量或静态本地变量的地址是安全的
  • 安全的做法是返回传入的指针

宏定义(编译预处理指令)

  • #开头的是编译预处理指令
  • #define用来定义一个宏
    • #define <名字> <值>
    • C语言的编译器开始编译之前,编译预处理软件会将程序中的名字换成值(完全的文本替换)
    • 值可以为任何东西(包括命令)
#define PI 3.14
#define PI2 2*PI
int main()
{printf("%f\n", 2*PI2*3.0);return 0;
}//输出37.68
#define PI 3.14
#define PI2 printf("%.2f\n", PI);\printf("%.2f\n", 2*PI)
int main() { PI2; }//输出3.14和6.28

预定义的宏

  • __LINE__源代码文件的行号(整数)
  • __FILE__文件名称(字符串)
  • __DATE__编译文件时的日期(字符串)
  • __TIME__编译时的时间(字符串)
  • __FUNCTION__ __func__返回程序名(字符串)
    使用宏注意加上括号
#define L(x) x*10
#define L2(x) (x)*10printf("%d\n", L(2 + 5));//输出52printf("%d\n", L2(2 + 5));//输出70

多个源代码文件

有两个文件get.c``main.c分别为

void get(void){printf("运行成功");
}
#include<stdio.h>
#include "get.c"
int main(){ get(); }//运行成功

多个C文件的调试

法一:

  1. 将多个C项目文件放入同一个新建文件夹project。我们以文件main.cget.c为例子
//main.c
#include<stdio.h>
#include "get.h"
int main()
{get();
}
//get.c
#include"get.h"
void get(void){printf("congratulation!");
}
//get.h
void get(void);
  1. 在终端中输入以下命令用于生成编译文件my_multi.exe
gcc -g .\main.c .\get.c  -o my_multi
  1. 在运行和调试栏处新建gcc.exe的配置文件lanuch.json(前提是已经将mingw64\bin加入了环境变量)
  2. 打开lanuch.json找到"preLaunchTask"并将改行注释掉
  3. "cwd"行改为"${workspaceFolder}";然后将"program"行改为编译执行文件目录"${workspaceFolder}/my_multi.exe"
    完成这些就可以顺利调试了

法二 CMake

  1. 新建CMakeLists.txt在其中写入
project(MYMULTI)
add_executable(my_cmake_multi main.c get.c)
//包含生成文件,两个需要编译的c文件
  1. Ctrl+Shift+p调出命令栏,输入cmake:Configure,选择gcc编译器。成功后会生成build文件夹
  2. 在终端处进入build文件夹输入cmake ..再输入mingw32-make.exe。终端最后一行显示Built target my_cmake_bulti则表示创建编译文件成功。
  3. 重复方法一中的操作5,将"program"后改为my_cmake_bulti.exe文件的路径即可进行调试。

build文件

不用cmake自己创建build文件。在终端project处输入

mkdir build
cd build
cmake -G "MinGW Makefiles" .. //这一步是为了使程序调用gcc编译器
mingw32-make.exe

文件输入和输出

格式化输入和输出

printf %[flags][width][.prec][hIL]type

printf("%-9d\n", 123); //靠左对齐输出
123
printf("%9d\n", 123);123
printf("%+9d\n", 123);//表示前面保留加号或减号+123
printf("%-+9d\n", 123);
+123     //
printf("%09d\n", 123);//空的位置填上0
000000123
printf("%hhd\n",12345);//0x3039只取一个字节的部分39,变成十进制是57

hIL类型修饰

类型修饰 含义
hh 单个字节
h short
l long
ll long long
L long double

文件

fopen 函数

FILE *fopen(const char *filename, const char *mode)输入文件的路径,打开方式,返回文件指针。"r"模式下,文件若不存在则返回NULL

  • filename–这是C语言字符串,包含了要打开的文件名称。
  • mode–这是 C 字符串,包含了文件访问模式,模式如下:
模式 描述
“r” 打开一个用于读取的文件。该文件必须存在。
“w” 创建一个用于写入的空文件。如果文件名称与已存在的文件相同,则会删除已有文件的内容,文件被视为一个新的空文件。
“a” 追加到一个文件。写操作向文件末尾追加数据。如果文件不存在,则创建文件。
“r+” 打开一个用于更新的文件,可读取也可写入(不删除原有数据)。该文件必须存在。
“w+” 创建一个用于读写的空文件,若文件已经存在则删除已有内容
“a+” 打开一个用于读取和追加的文件。没有则会新建一个文件

fscanf

int fscanf(FILE *stream, const char *format, ...)
返回:如果成功,该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回 EOF。

    fp = fopen("F:\\VScode\\VScode-C\\test.txt", "a+");printf("name\t num\t score\n");for (i = 0; i < 3;i++){fscanf(fp,"%d%s%d", &num, name, &score);printf("j=%d\n", j);//j=3,返回成功酦醅和赋值的个数printf("%s\t%d\t%d\n", name, num, score);}fclose(fp);

fprintf

int fprintf(FILE *stream, const char *format, ...)

  • stream为指向FILE对象的指针
    如果成功,则返回写入的字符总数,否则返回一个负数。
   fp = fopen ("file.txt", "w+");fprintf(fp, "%s %s %s %d", "We", "are", "in", 2014);//输出为We are in 2014

下面为示例:

#include<stdio.h>
int main()
{FILE *fp;int i, n;int num, score;char name[20];fp = fopen("test.txt", "w+");printf("你想输入多少组数据:");scanf("%d", &n);for (i = 0; i < n;i++){printf("姓名:");scanf("%s", name);printf("学号:");scanf("%d", &num);printf("分数:");scanf("%d", &score);fprintf(fp, "%s\t%d\t%d\n", name, num, score);}fseek(fp, 0, SEEK_SET);printf("name\tnum\tscore\n");for (i = 0; i < n;i++){fscanf(fp, "%s\t%d\t%d\n", name,&num,&score);//fscanf会改变指针位置printf("%s\t%d\t%d\n", name, num, score);}fclose(fp);
}

sprintf

int sprintf(char *str, const char *format, ...)

fwrite

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)

  • ptr – 这是指向要被写入的元素数组的指针。
  • size – 这是要被写入的每个元素的大小,以字节为单位。
  • nmemb – 这是元素的个数,每个元素的大小为 size 字节。
  • stream – 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。
    返回:写入成功返回写入字符总数(不包括末尾空字符),失败则返回负数。
    FILE *fp;fp = fopen("file.txt", "w");char str[] = "This is runoob.com";fwrite(str, sizeof(str), 1, fp);fclose(fp);

注意:fprintf将每一位用ASCII码储存,然后txt将ASCII码翻译位字符输出;而fwrite是直接将字符写入,例如65,65为A的ASCII码,txt中写为A

fread

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)

  • ptr – 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
  • size – 这是要读取的每个元素的大小,以字节为单位.
  • nmemb – 这是元素的个数,每个元素的大小为 size 字节。
  • stream – 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。
    返回成功读取的元素总数
FILE *fp;char c[] = "This is runoob";char buffer[20];FILE *fp;/* 打开文件用于读写 */fp = fopen("file.txt", "w+");/* 写入数据到文件 */fwrite(c, strlen(c) + 1, 1, fp);/* 查找文件的开头 */fseek(fp, 0, SEEK_SET);/* 读取并显示数据 */fread(buffer, strlen(c)+1, 1, fp);printf("%s\n", buffer);fclose(fp);

fseek

int fseek(FILE *stream, long int offset, int whence)

  • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
  • offset – 这是相对 whence 的偏移量,以字节为单位。
  • whence – 这是表示开始添加偏移 offset 的位置。
    1. SEEK_SET文件开头
    2. SEEK_CUR文件指针的当前位置
    3. SEEK_END文件末尾
  • 注意:利用a+a模式打开的文档,SEEK_SET就是在追加的起始位置而非文档开头
    如果成功,则该函数返回零,否则返回非零值。

ftell

long int ftell(FILE *stream)该函数返回位置标识符的当前值。如果发生错误,则返回 -1L,全局变量 errno 被设置为一个正值。因此ftell可以得到文本大小

#include<stdio.h>
int main()
{FILE *fp = fopen("test.txt", "w+");int loc = ftell(fp);printf("loc=%d\n", loc);//loc=0fprintf(fp,"abcde");int loc2 = ftell(fp);printf("loc2=%d\n", loc2);//loc2=5
}

位运算

按位与&

若(x)i=1且(y)i=1,则(x&y)i=1,否则(x&y)i=0

  • 利用0xFF对某个数做按位与运算,可以取得其后8位bit的情况
  • 利用0xFE可以使数的最后一位bit为0

按位取反~

(~x)i=1-(x)i

c = 0xaa  10101010
~c = 0x55 01010101
-c = 0x56 01010110  //-c=2^8-c

按位异或(^)

若(x)i=(y)i,则(xy)<sub>i</sub>=0,否则(xy)i=1

1^0^0=1
0^0^0=0
1^1^1=1
0^1^1=0
(x^y)^y=x
x^(~x)=0xFF

左移(<<)与右移(>>)

i<<ji所有位左移j位,右边填0
右移:unsigned型左填0;signed型左填原来的最高位。小于int类型的数以int来做

unsigned char b = 0xA5;
printf("b<<2=%hhx\n", (char)b<<2); //0x94
int a = 0x80000000;   //2^31,signed型,保留第32个bit上的1,右移后第31个bit也变为1,结果为-2^30
unsigned int d = 0x80000000;//直接右移,最高位bit变为0
printf("a=%d\n", a>>1);//-1073741824
printf("d=%d\n", d>>1);//1073741824

位段

下面的struct结构定义位段,每一位为1bit,从右向左排列,当所需位超过一个int时会采取多个int

#include<stdio.h>
struct U0{unsigned int leading : 3;unsigned int FLAG1 : 1;unsigned int FLAG2 : 1;int trailing : 27;
};
void prtbin(unsigned int number);int main()
{struct U0 uu;uu.leading = 3;uu.FLAG1 = 1;uu.FLAG2 = 0;uu.trailing = 0;printf("sizeof(uu)=%d\n", sizeof(uu));prtbin(*(int *)&uu);           //将uu指针变成整型指针输出,结果前五位01011
}
void prtbin(unsigned int number)  //以二进制方式打印整数
{unsigned m = 1u << 31;for (; m;m>>=1){printf("%d", number & m ? 1 : 0);}printf("\n");
}

数的二进制转换

#include<stdio.h>
int main(){int n=0xaaaaaaaa ;//10101010101010101010101010101010//scanf("%d", &n);unsigned m = 1u << 31;for (; m;m>>=1){printf("%d", n & m ? 1 : 0);}printf("\n");
}

链表

可变数组

设计一组函数,他们能提供可变大小的数组。他们需要满足:可变大小、能得到当下数组的大小、能获取里面的元素

  • Array array_creat(int init_size);创建指定大小数组
  • void array_free(Array *a); 将数组空间回收
  • int array_size(const Array *a); 得到数组内可用单元
  • int* array_at(Array *a, int index); 访问数组中的某个单元
  • void array_inflate(Array* a, int more_size); 使数组空间扩充

PS:空指针表示==“未分配”或者“尚未指向任何地方”。它与未初始化的指针有所不同,空指针可以确保不指向任何对象或函数==,而未初始化指针可能指向任何地方。空指针与任何对象或函数的指针都不相同,malloc成功调用和&成功取址都不会得到空指针

链表

每一个节点都是结构体,包含两部分,一部分位值value,一部分为指向下一个结构体的指针

#include<stdio.h>
#include<stdlib.h>typedef struct _node{int value;struct _node *next;
} Node;int main()
{Node *head = NULL;//定义指向第一个节点的指针headint number;do{scanf("%d", &number);if (number!=-1){Node *p = (Node *)malloc(sizeof(Node));p->value = number;p->next = NULL;Node *last = head;  //让last从head通过循环到达最后一个节点if (last){while(last->next){last = last->next; //保持last为最后一个节点的指针,next为NULL}last->next = p;//将最后一个节点中的next指向新的节点} else {head = p;   //注意在第一次赋值时将指针p交给head}}} while (number == -1);
}
include<stdio.h>
#include<stdlib.h>typedef struct _node{int value;struct _node *next;
} Node;
typedef struct{Node * head;
}List;
//Node *add(Node *head, int number);
void add(List* plist, int number);int main()
{List list;list.head= NULL;int number;scanf("%d", &number);while(number!=-1){//head = add(head, number); //对链2表输入值,输入-1表示结束add(&list, number);scanf("%d", &number);}Node *p;int count = 0;for (p = list.head; p;p = p->next,count++){printf("%d:%d\n", count+1,p->value);}Node *q;printf("请输入你想删除的数:");scanf("%d", &number);for (q = NULL, p = list.head; p;q = p,p = p->next){ if(p->value==number){  //注意保证箭头左侧的指针不能为NULLif(q){q->next = p->next;//找到之后将p之前节点的结构体的next变量换成p之后节点的指针} else{list.head = p->next; //当需要删除的节点位于第一个位置时}free(p);break;   }}count = 0;for (p = list.head; p;p = p->next,count++){printf("%d:%d\n", count+1,p->value);}for (p = list.head,q = NULL; p;p = q){  //删除整个链表q = p->next;free(p);}
}void add(List* plist,int number){Node *p = (Node*)malloc(sizeof(Node));p->value = number;p->next = NULL;Node *last = head;if(last){while(last->next){last = last->next;}last->next = p;}else {head = p;}
}
/* Node* add (Node*list,int number);函数有一个缺点,他是由另一个指针变量接受head,若不反回head,则可能因为最初head=NULL使程序错误
一个好办法是定义一个结构体
typedef struct{Node * head;
}List;
然后传入List *plist,在add函数中对plist->head = p,这样add类型可以是void*/

浙大mooc翁凯 C语言笔记相关推荐

  1. mooc翁凯C语言习题第七周(7-2)鞍点

    习题7-2 找鞍点(5分) 题目内容: 给定一个n*n矩阵A.矩阵A的鞍点是一个位置(i,j),在该位置上的元素是第i行上的最大数,第j列上的最小数.一个矩阵A也可能没有鞍点. 你的任务是找出A的鞍点 ...

  2. 多项式加法(MOOC 翁凯 C语言源码)

    题目内容: 一个多项式可以表达为x的各次幂与系数乘积的和,比如: 2x6+3x5+12x3+6x+20 现在,你的程序要读入两个多项式,然后输出这两个多项式的和,也就是把对应的幂上的系数相加然后输出. ...

  3. 念整数( MOOC 翁凯 c语言源码)

    题目内容: 你的程序要读入一个整数,范围是[-100000,100000].然后,用汉语拼音将这个整数的每一位输出出来. 如输入1234,则输出: yi er san si 注意,每个字的拼音之间有一 ...

  4. 鞍点(MOOC 翁凯 C语言源码)

    题目内容: 给定一个n*n矩阵A.矩阵A的鞍点是一个位置(i,j),在该位置上的元素是第i行上的最大数,第j列上的最小数.一个矩阵A也可能没有鞍点. 你的任务是找出A的鞍点. 输入格式: 输入的第1行 ...

  5. 翁凯c语言单词长度,中国大学MOOC-C程序设计(浙大翁恺)—— 单词长度

    题目内容: 你的程序要读入一行文本,其中以空格分隔为若干个单词,以'.'结束.你要输出这行文本中每个单词的长度.这里的单词与语言无关,可以包括各种符号,比如"it's"算一个单词, ...

  6. MOOC翁凯_零基础学Java语言

    Week 1 计算 1.0 计算机与编程语言 程序的执行:解释和编译(翻译成计算机能懂的机器语言) 1.1 第一个Java程序 JRE:Java运行环境,Oracle网站 Eclipse/IDEA:编 ...

  7. C语言程序设计习题集(中国大学MOOC翁凯)02

    02-0. 整数四则运算(10) 本题要求编写程序,计算2个正整数的和.差.积.商并输出.题目保证输入和输出全部在整型范围内. 输入格式: 输入在一行中给出2个正整数A和B. 输出格式: 在4行中按照 ...

  8. 中国大学MOOC翁恺C语言PTA入门练习(更新中)

    目录 7-1 重要的话说三遍 (5 分) 7-2 I Love GPLT (5 分) 7-3 输出带框文字 (5 分) 7-4 输出菱形图案 (5 分) 7-5 输出倒三角图案 (5 分) 7-6 厘 ...

  9. 翁凯c语言字符串函数,C语言基础及指针⑥字符操作

    字符操作 , 是我们写程序时 , 最常用的一种操作 , 例如:字符串截取 , 字符串替换 , 字符串转整数类型等等 , 都是字符操作 , 在java中String类就是二三十个方法 , 还有Strin ...

  10. 高精度小数 mooc 翁恺c 语言

    题目内容: 由于计算机内部表达方式的限制,浮点运算都有精度问题,为了得到高精度的计算结果,就需要自己设计实现方法. (0,1)之间的任何浮点数都可以表达为两个正整数的商,为了表达这样两个数的商,可以将 ...

最新文章

  1. 决心开始写博,坚持!
  2. mysql if value t f_mysql常用函数
  3. 如何查看云服务器的系统版本,如何查看云服务器系统版本
  4. mysql事务与jdbc事务_事务(mysql事务、jdbc事务)
  5. Django框架——类视图
  6. 虚拟机网络模式与网络配置
  7. mysql 增加分区_mysql在原有表的基础上添加分区
  8. char 转换 二进制 java_使用Java读取二进制文件并将其转换为char文件 - java
  9. STM32开关总中断
  10. linux越狱时手机怎么进入dfu,通过软件恢复进入DFU刷机模式教程
  11. (六)linux中的进程管理
  12. c语言火车票退票系统流程图,[图解12306退票流程与步骤]
  13. 软件开发生命周期汇总
  14. 自动驾驶哪国强?各国和地区自动驾驶成熟度指数 | 自动驾驶系列
  15. 不忘来时路 心系梦归处
  16. 使用Fiddler监控雷电/夜神模拟器浏览网页:安全警告:该网站的安全证书有问题.解决方案!
  17. 如何在ionic5 release版本降级安装ionic3
  18. web(vue) 简单使用 mixpanel 网页埋点
  19. 实战 Java 第8天:开发商品详情查询接口
  20. Django解决扩展用户表时,后台Admin显示密码为明文的问题

热门文章

  1. android re浏览器下载,RE文件浏览器
  2. html在线post提交,HTML 两种方法实现post
  3. linux mp4box安装,视频处理利器 MP4Box常用的12个命令
  4. 好用的5款火狐浏览器必备插件,每一款都很实用
  5. 如何设置华为悦盒Ubuntu系统的无线WiFi自动连接
  6. 证件管理系统开发1 :明确需求
  7. 2020年中国激光切割运控系统需求现状及竞争格局分析,高功率快速增长「图」
  8. 车辆模型-动力学模型(Dynamics Model)
  9. 【书记舞】MMD动作+镜头+配音下载
  10. DCDC与LDO浅析