关于c:记录使用dlclose后so无法卸载问题

记录应用dlclose后so无奈卸载问题问题形容有一个相似插件的性能,应用dlopen形式加载一个so,降级so的时候,先dlclose,而后再dlopen加载。这样能够做到更换so的时候不必重新启动程序。原本所有运行的比拟好,但有一个so比拟奇怪,降级so后,某些函数无奈应用新的so外面的实现,还是旧的so中的实现。 问题定位在gdb中应用info sharedlibrary命令查看加载的so,再应用lsof查看如下: (gdb) info sharedlibrary 0x00007fff2132a2c0 0x00007fff213bc5f8 Yes /xxxx/xxx/libxxx.so[email protected]:~# lsof |grep libxxx.songinx 3391245 root mem REG 253,0 8604544 5250054 /xxx/xxx/libxxx.so从这些信息中能够看到,目前正在应用的so的inode是5250054,而是用stat查看当初so的inode信息,发现inode是5377891,如下所示: [email protected]:~# stat /xxx/xxx/libxxx.so File: /apisec/modules/component/sensitive_data/libs/libdi_rechk.so Size: 8604544 Blocks: 16808 IO Block: 4096 regular fileDevice: fd00h/64768d Inode: 5377891 Links: 1Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)Access: 2022-10-21 17:01:57.404283135 +0800Modify: 2022-10-21 15:48:29.000000000 +0800Change: 2022-10-21 17:00:23.423822609 +0800两者inode不一样,阐明应用的不是同一个so文件,因为旧的so曾经被删除。但程序中曾经dlclose并从新dlopen了,于是从网上查找材料,有些材料中都说查看下是否有NODELET标记。于是应用readelf命令查看下: [email protected]:~# readelf -d libxxx.so |grep NODELETE 0x000000006ffffffb (FLAGS_1) Flags: NODELETEso中有此标识,则动静加载程序已被告知不要卸载库,所以调用dlclose后,不会从过程中卸载此so。 手动测试本人写一个test.c的测试例子,代码如下: ...

October 24, 2022 · 1 min · jiezi

关于c:深入剖析Sgementation-fault原理

深刻分析Sgementation fault原理前言咱们在日常的编程当中,咱们很容易遇到的一个程序解体的谬误就是segmentation fault,在本篇文章当中将次要剖析段谬误产生的起因! Sgementation fault产生的起因产生Sgementation fault的间接起因是,程序收到一个来自内核的SIGSEGV信号,如果是你的程序导致的内核给过程发送这个信号的话,那么就是你的程序正在读或者写一个没有调配的页面或者你没有读或者写的权限。这个信号的起源有两个: 程序的非法拜访,本身程序的指令导致的Sgementation fault。另外一种是由别的程序间接发送SIGSEGV信号给这个过程。在类Linux零碎中,内核给过程发送的信号为SIGGEV,信号对应数字为11,在Linux当中信号对应的数字状况大抵如下所示: 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR111) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+338) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+843) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+1348) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-1253) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-758) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-263) SIGRTMAX-1 64) SIGRTMAX当一个程序产生 segmentation fault 的时候,这个程序的退出码 exitcode 等于 139! ...

October 20, 2022 · 2 min · jiezi

关于c:01C语言基础知识

最简略的C语言程序int main(){ return 0;}//该函数为入口函数//int 代表函数的返回值类型,return语句返回的数据类型要和它对应//main 函数名,main函数是C中惟一一个固定的函数名称,每个程序必须且只有一个main函数快捷键 CTRL+F5 是运行编写好的程序 查看编译后生成的exe文件: C语言中的头文件什么是头文件?头文件是他人给咱们写的代码,蕴含了头文件就能够应用其他人给咱们写好的代码,咱们通常将这些代码称为接口 如何蕴含头文件有两种形式 #include <xxx.h>:此种形式只在规范库中搜寻#include "xxx.h:此种形式依照所给门路查找头文件,首先搜寻规范库,再搜寻所给门路本人写的头文件也能放大规范库中去间接援用,然而不举荐随便更改规范库,容易导致隐患 如果须要援用能够通过配置我的项目属性的形式,减少规范库目录: 门路有两种模式: 绝对路径:带盘符相对路径 当前目录:./下层目录:../上下层目录:../../(有多少层,写多少个../)入口函数详解一个解决方案能够有多个我的项目 在以后我的项目右击,抉择【设为启动我的项目】后,能力应用CTRL+F5的形式调试本我的项目 入口函数的写法入口函数的写法多种多样,分为规范式和非标准式 tips:能够通过【工具】----【谬误查找】性能来查找错误代码的根本含意 system 函数作用:就是将命令字符串发送给零碎执行,相当于在cmd中执行无关命令 tips:应用时须要蕴含 stdlib.h头文件 利用场景: 执行exe文件执行cmd命令 常见cmd命令 pause:按任意键持续cls:清屏others程序运行和编译过程运行过程 从入口函数开始从上往下顺次执行程序生成 编辑--→ 生成 xxxooo.c(源文件)编译---→xxoo.obj(指标文件)链接----→xxoo.exe(二进制可执行文件)运行----→软件 gcc编译命令 gcc -E xxoo.c -o xxoo.i --→预处理文件.i gcc -S xxoo.i -o xxoo.s --→编译文件.s gcc -C xxoo.s -o xxoo.o --→二进制文件.o 谬误分类 编译谬误:所有编译谬误都能够通过VS查找定位,个别是因为语法问题引起的,另一些是因为不仔细引起的运行谬误:能够通过断点测试,代码量少间接F10逐句执行,代码量多,先预估谬误地位,再打断点测试逻辑谬误:只能通过解决,解决办法就是有错就改,改完再犯,千锤百炼# 课后作业 #include<stdio.h>#include<stdlib.h>int main(){ system("mode con lines=10 cols=40"); system("shutdown -s -t 60"); printf("60s内关机,按下任意键勾销!"); system("pause"); system("shutdown -a"); return 0;}

September 18, 2022 · 1 min · jiezi

关于c:指针函数|函数指针|回调函数|指针数组|数组指针

指针函数指针函数,简略了解就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。申明格局如下: *类型标识符 函数名(参数表) 例如, int *myfun(int x,int y);留神:在函数名后面多了一个*号,而这个函数就是一个指针函数。其返回值是一个 int 类型的指针。 #include <iostream>using namespace std;#include<string.h>int *newAdd(int a, int b); // 申明指针函数int main() { int *p1 = NULL; p1 = newAdd(1, 2); printf("p1 = 0x%x \n", p1); printf("*p1 = %d \n", *p1); getchar(); return 0; }int *newAdd(int a, int b) { int *p = (int *)malloc(sizeof(int)); memset(p, 0, sizeof(int)); printf("函数内:p = 0x%x \n", p); *p = a + b; printf("函数内:*p = %d \n", *p); return p;}留神:在调用指针函数时,须要一个同类型的指针来接管其函数的返回值。 ...

September 11, 2022 · 2 min · jiezi

关于c:动态链接库如何函数寻址

原文地址:动态链接库如何函数寻址 最近咱们发现 go 编译为 so 之后,内存占用涨了好多,初步剖析下来,是动静符号导致的,感觉不太合乎常识趁着娃还在里面放假,正好学习学习~ hello worldint main() { printf("hello world\n")}在最简略的 hello world 中,printf 最终也是来自 libc.so 这个动态链接库通过 objdump,咱们能够找到这一行: 400638: call 400520 <printf@plt>这里的 printf@plt,示意 printf 这个函数是依赖的内部函数,是要动静寻址的。 为什么须要函数寻址不同于动态链接,函数地址在链接期(执行前),就能够确定下来了。然而,动态链接库的地址,是在程序执行的时候,加载 so 文件时能力确定的。那么,要调用动静库中的函数,是没有方法提前晓得的地址的,所以须要一套机制来寻找函数的地址。 具体而言,分为两种寻址: so 中导出的函数地址so 外部调用非导出的函数地址简而言之第一种,是通过函数名来寻址的,相当于在主程序里调用了 dlsym(x, "printf") 来寻址,而后 dlsym 会在 so 文件里找 printf 的地址第二种,是通过偏移量来寻址的,尽管相对地址不固定,然而 so 文件外部,两个函数之间的偏移量是固定的。 缓存减速通过字符串来查找,想想也晓得是比拟低效的,那有什么方法提速呢?原理也简略,就是加缓存。具体而言呢,是通过可执行文件中的两个段的配合,其中 .plt 可执行,.got.plt 可写,来实现缓存的成果。 还是从这一行 call 指令开始 400638: call 400520 <printf@plt>400520 来自 .plt 段,而且 .plt 是可执行的持续用 objdump 能够看指令: 400520: jmp QWORD PTR [rip+0x200afa] # 601020 <printf@GLIBC_2.2.5> 400526: push 0x0 40052b: jmp 400500 <.plt>这里有两个 jmp:第一个 jmp 的地址来自 601020,而这个 601020 来自 .got.plt 段,.got.plt 是可写的首次执行的时候,601020 里存的就是 400526,此时意味着慢门路,须要动静查找。当查到地址之后,会批改 601020 中的值,这样后续就能够间接一个 jmp 就实现寻址了,不须要再依照字符串查找了。 ...

September 6, 2022 · 1 min · jiezi

关于c:记录一次C语言调用go生成的动态库的踩坑过程

记录一次C语言调用go生成的动静库的踩坑过程问题景象因为某些非凡起因,须要在C语言中调用go语言生成的so,原本挺顺利,所有都运行的很好。忽然某一天,不晓得怎么回事,再一个新程序中无奈失常运行了,看到的景象是程序无任何响应,相似于间接卡死了。应用gdb查看过程以后的信息,看到如下调用栈: (gdb) source /root/go/src/runtime/runtime-gdb.pyLoading Go Runtime support.(gdb) bt#0 runtime.futex () at /usr/local/go/src/runtime/sys_linux_amd64.s:520#1 0x00007fff23c550f6 in runtime.futexsleep (addr=0xfffffffffffffe00, val=0, ns=140733793710979) at /usr/local/go/src/runtime/os_linux.go:44#2 0x00007fff23c35667 in runtime.notetsleep_internal (n=0x7fff23dc66e8 <runtime.work+232>, ns=-1) at /usr/local/go/src/runtime/lock_futex.go:183#3 0x00007fff23c35785 in runtime.notetsleepg (n=0x7fff23dc66e8 <runtime.work+232>, ns=-1) at /usr/local/go/src/runtime/lock_futex.go:237#4 0x00007fff23c41338 in runtime.gcBgMarkStartWorkers () at /usr/local/go/src/runtime/mgc.go:1126#5 0x00007fff23c3fd92 in runtime.gcStart (trigger=...) at /usr/local/go/src/runtime/mgc.go:637#6 0x00007fff23c36e3d in runtime.mallocgc (size=565248, typ=0x7fff23cfd160, needzero=true) at /usr/local/go/src/runtime/malloc.go:1174#7 0x00007fff23c6dfaa in runtime.growslice (et=, old=..., cap=) at /usr/local/go/src/runtime/slice.go:267#8 0x00007fff23c918ef in regexp/syntax.(*compiler).inst (c=0xc000044bf8, op=) at /usr/local/go/src/regexp/syntax/compile.go:164#9 regexp/syntax.(*compiler).rune (c=0xc000044bf8, r=[]int32 = {...}, flags=212) at /usr/local/go/src/regexp/syntax/compile.go:273#10 0x00007fff23c90f1e in regexp/syntax.(*compiler).compile (c=0xc000044bf8, re=0xc000190000) at /usr/local/go/src/regexp/syntax/compile.go:101#11 0x00007fff23c8f805 in regexp/syntax.Compile (re=0xc000190000) at /usr/local/go/src/regexp/syntax/compile.go:74#12 0x00007fff23ca4a9a in regexp.compile (expr=,mode=, longest=false) at /usr/local/go/src/regexp/regexp.go:178#13 0x00007fff23ca5591 in regexp.Compile (expr="") at /usr/local/go/src/regexp/regexp.go:133#14 regexp.MustCompile (str="") at /usr/local/go/src/regexp/regexp.go:309#15 0x00007fff23ca8e0a in main.CheckPostAddress (buf=, bufLen=) at /root/codes/di_rechk/rechk.go:540#16 0x00007fff23ca9a88 in _cgoexp_67df0785bef2_CheckPostAddress (a=0x7fffffffc740) at _cgo_gotypes.go:162#17 0x00007fff23c2e21a in runtime.cgocallbackg1 (fn=0x7fff23ca9a60 <_cgoexp_67df0785bef2_CheckPostAddress>, frame=0x7fffffffc740, ctxt=0)at /usr/local/go/src/runtime/cgocall.go:306#18 0x00007fff23c2dee9 in runtime.cgocallbackg (fn=0x7fff23ca9a60 <_cgoexp_67df0785bef2_CheckPostAddress>, frame=0x7fffffffc740, ctxt=0)at /usr/local/go/src/runtime/cgocall.go:232#19 0x00007fff23c83791 in runtime.cgocallbackg (fn=0x7fff23ca9a60 <_cgoexp_67df0785bef2_CheckPostAddress>, frame=0x7fffffffc740, ctxt=0)at :1#20 0x00007fff23c813f3 in runtime.cgocallback () at /usr/local/go/src/runtime/asm_amd64.s:915#21 0x00007fff23c81601 in runtime.goexit () at /usr/local/go/src/runtime/asm_amd64.s:1581#22 0x0000000000000000 in ?? ()(gdb) info goroutines 17 syscall runtime.notetsleepg 2 waiting runtime.gopark 3 waiting runtime.gopark 4 waiting runtime.gopark 19 runnable runtime.gcBgMarkWorker(gdb) goroutine 17 bt#0 runtime.notetsleepg (n=0x7fff23dc66e8 <runtime.work+232>, ns=-1) at /usr/local/go/src/runtime/lock_futex.go:237#1 0x00007fff23c41338 in runtime.gcBgMarkStartWorkers () at /usr/local/go/src/runtime/mgc.go:1126#2 0x00007fff23c3fd92 in runtime.gcStart (trigger=...) at /usr/local/go/src/runtime/mgc.go:637#3 0x00007fff23c36e3d in runtime.mallocgc (size=565248, typ=0x7fff23cfd160, needzero=true) at /usr/local/go/src/runtime/malloc.go:1174#4 0x00007fff23c6dfaa in runtime.growslice (et=, old=..., cap=) at /usr/local/go/src/runtime/slice.go:267#5 0x00007fff23c918ef in regexp/syntax.(*compiler).inst (c=0xc000044bf8, op=) at /usr/local/go/src/regexp/syntax/compile.go:164#6 regexp/syntax.(*compiler).rune (c=0xc000044bf8, r=[]int32 = {...}, flags=212) at /usr/local/go/src/regexp/syntax/compile.go:273#7 0x00007fff23c90f1e in regexp/syntax.(*compiler).compile (c=0xc000044bf8, re=0xc00022a000) at /usr/local/go/src/regexp/syntax/compile.go:101#8 0x00007fff23c8f805 in regexp/syntax.Compile (re=0xc00022a000) at /usr/local/go/src/regexp/syntax/compile.go:74#9 0x00007fff23ca4a9a in regexp.compile (expr=,mode=, longest=false) at /usr/local/go/src/regexp/regexp.go:178#10 0x00007fff23ca5591 in regexp.Compile (expr=""") at /usr/local/go/src/regexp/regexp.go:133#11 regexp.MustCompile (str=""") at /usr/local/go/src/regexp/regexp.go:309#12 0x00007fff23ca8e0a in main.CheckPostAddress (buf=, bufLen=) at /root/codes/di_rechk/rechk.go:540#13 0x00007fff23ca9a88 in _cgoexp_67df0785bef2_CheckPostAddress (a=0x7fffffffc740) at _cgo_gotypes.go:162#14 0x00007fff23c2e21a in runtime.cgocallbackg1 (fn=0x7fff23ca9a60 <_cgoexp_67df0785bef2_CheckPostAddress>, frame=0x7fffffffc740, ctxt=0)at /usr/local/go/src/runtime/cgocall.go:306#15 0x00007fff23c2dee9 in runtime.cgocallbackg (fn=0x7fff23ca9a60 <_cgoexp_67df0785bef2_CheckPostAddress>, frame=0x7fffffffc740, ctxt=0)at /usr/local/go/src/runtime/cgocall.go:232#16 0x00007fff23c83791 in runtime.cgocallbackg (fn=0x7fff23ca9a60 <_cgoexp_67df0785bef2_CheckPostAddress>, frame=0x7fffffffc740, ctxt=0)at :1#17 0x00007fff23c813f3 in runtime.cgocallback () at /usr/local/go/src/runtime/asm_amd64.s:915#18 0x00007fff23c81601 in runtime.goexit () at /usr/local/go/src/runtime/asm_amd64.s:1581#19 0x0000000000000000 in ?? ()(gdb) goroutine 2 bt#0 runtime.gopark (unlockf=, lock=, reason=, traceEv=, traceskip=)at /usr/local/go/src/runtime/proc.go:367#1 0x00007fff23c5b86d in runtime.goparkunlock (reason=, traceEv=, traceskip=, lock=)at /usr/local/go/src/runtime/proc.go:372#2 runtime.forcegchelper () at /usr/local/go/src/runtime/proc.go:306#3 0x00007fff23c81601 in runtime.goexit () at /usr/local/go/src/runtime/asm_amd64.s:1581#4 0x0000000000000000 in ?? ()(gdb) goroutine 3 bt#0 runtime.gopark (unlockf=, lock=, reason=, traceEv=, traceskip=)at /usr/local/go/src/runtime/proc.go:367#1 0x00007fff23c48ee8 in runtime.goparkunlock (reason=, traceEv=, traceskip=, lock=)at /usr/local/go/src/runtime/proc.go:372#2 runtime.bgsweep () at /usr/local/go/src/runtime/mgcsweep.go:163#3 0x00007fff23c81601 in runtime.goexit () at /usr/local/go/src/runtime/asm_amd64.s:1581#4 0x0000000000000000 in ?? ()(gdb) goroutine 4 bt#0 runtime.gopark (unlockf=, lock=, reason=, traceEv=, traceskip=)at /usr/local/go/src/runtime/proc.go:367#1 0x00007fff23c46fed in runtime.goparkunlock (reason=, traceEv=, traceskip=, lock=)at /usr/local/go/src/runtime/proc.go:372#2 runtime.bgscavenge () at /usr/local/go/src/runtime/mgcscavenge.go:265#3 0x00007fff23c81601 in runtime.goexit () at /usr/local/go/src/runtime/asm_amd64.s:1581#4 0x0000000000000000 in ?? ()(gdb) goroutine 19 bt#0 runtime.gcBgMarkWorker () at /usr/local/go/src/runtime/mgc.go:1166#1 0x00007fff23c81601 in runtime.goexit () at /usr/local/go/src/runtime/asm_amd64.s:1581#2 0x0000000000000000 in ?? ()(gdb) info threadsId Target Id Frame1 Thread 0x7ffff7966b80 (LWP 2024707) "nginx" runtime.futex () at /usr/local/go/src/runtime/sys_linux_amd64.s:5202 Thread 0x7ffef1ffb700 (LWP 2024717) "nginx" 0x00007ffff7a483bf in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7ffef1ffae80, rem=rem@entry=0x0) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:783 Thread 0x7ffef27fc700 (LWP 2024718) "ZMQbg/Reaper" 0x00007ffff7a8a5ce in epoll_wait (epfd=42, events=events@entry=0x7ffef27fb200, maxevents=maxevents@entry=256, timeout=timeout@entry=-1) at ../sysdeps/unix/sysv/linux/epoll_wait.c:304 Thread 0x7ffef2ffd700 (LWP 2024719) "ZMQbg/IO/0" 0x00007ffff7a8a5ce in epoll_wait (epfd=44, events=events@entry=0x7ffef2ffc200, maxevents=maxevents@entry=256, timeout=timeout@entry=-1) at ../sysdeps/unix/sysv/linux/epoll_wait.c:30问题解决过程因为对go不太熟悉,所以不晓得出了什么问题。go自身的代码也比较简单,没有太简单的操作。而且之前的程序调用这些go代码生成的so,也能整成运行。从网上查资料也是一头雾水,不晓得该怎么查。通过一段时间的搜寻,终于在stackoverflow中看到了一个相似问题。依照这个起因进行批改,果然批改好了。 ...

August 24, 2022 · 3 min · jiezi

关于c:C语言中文网课后作业day01

一、第一天1、C 语言能够用来开发网站吗?C语言只能做一些简略的事件,不适宜用来开发网站。 2、很多人认为“当程序员像农民一样苦逼”,对此你是怎么认为的?是一种自我讥嘲 3、就编程而言,可移植性意味着什么?一次编码,多平台运行,不必思考多平台硬件差别,更注程序自身的逻辑。 4、二进制、八进制、十进制、十六进制的前缀是什么?二进制:0b八进制:0十进制:失常数字十六进制:0x 5、二进制 1011 1101 转换为十六进制是多少?转10进制:11 13转16进制:b d后果为:0xbd 6、十进制 89 转换为二进制是多少?先将二进制位数对应到10进制数值,再拼凑起来 64 32 16 8 4 2 1 1 0 1 1 0 0 1后果为:1011001 7、0x7D 转换为十进制是多少?112(7*16) + 13 = 125 8、 076 转换为十进制是多少?后果为:62 9、二进制 101 110 转换为八进制是多少?后果为:56

August 20, 2022 · 1 min · jiezi

关于c:C语言级联内存池之轻松零拷贝IPC

让程序轻松逾越堆与共享内存的阻碍,轻松实现零拷贝IPC 什么是级联内存池?如何让程序轻松逾越堆与共享内存的阻碍?如何轻松实现零拷贝IPC?本文给你带来不一样的程序设计视线 以前的文章中,码哥介绍过利用内存池有哪些长处,咱们列举如下: 集中开释,便于编码逻辑,集中开释缩小空洞特定的调配开释算法及池构造,能够借助指令预取及cache命中来晋升性能提早开释闲置内存块,通过晋升复用率来晋升调配效率因而,本文不再赘述下面的局部。 这篇文章咱们介绍一种级联构造内存池,该内存池的实现能够参考:Github: Melon库 池构造的模型大抵如下: ------------- | 父池 | ------------- | | ----------- --------- | 子池1 | | 子池2 | ----------- --------- | | .... -------- -------- | 孙池1 | | 孙池2 | -------- --------这种构造是什么意思呢? 子池所应用的内存及其所能调配的内存均来自于父池。故此,孙池的内存也是由其依赖的子池而来的。 在Melon库的内存池组件中,内存的起源有三处: 堆内存(或者匿名映射区),即malloc库所提供共享内存(次要是用于奴才过程间的共享,因而是mmap的匿名映射区共享)其余内存池治理的内存咱们先来看一个简略的内存池应用的例子: 示例一,Melon惯例内存池应用举例#include <stdio.h>#include <stdlib.h>#include "mln_core.h"#include "mln_log.h"#include "mln_alloc.h"int main(int argc, char *argv[]){ char *p; mln_alloc_t *pool; struct mln_core_attr cattr; /* libmelon init begin*/ cattr.argc = argc; cattr.argv = argv; cattr.global_init = NULL; cattr.master_process = NULL; cattr.worker_process = NULL; if (mln_core_init(&cattr) < 0) { fprintf(stderr, "init failed\n"); return -1; } /* libmelon init end */ pool = mln_alloc_init(NULL); if (pool == NULL) { mln_log(error, "pool init failed\n"); return -1; } p = (char *)mln_alloc_m(pool, 6); if (p == NULL) { mln_log(error, "alloc failed\n"); return -1; } memcpy(p, "hello", 5); p[5] = 0; mln_log(debug, "%s\n", p); mln_alloc_destroy(pool); return 0;}在这个例子中,咱们创立了一个堆内存池,并且利用该内存池调配了6个字节的内存区用于写入"hello"字符串。 ...

August 20, 2022 · 2 min · jiezi

关于c:未来源码丨会写代码的AI开源了C语言写得比Codex还要好掌握12种编程语言丨CMU

举荐语: 近期,代码的大型语言模型 (LM)在实现代码和从自然语言形容合成代码方面显示出微小的后劲。然而,以后最先进的代码 LM(例如 Codex (Chen et al., 2021))尚未公开,留下了许多对于其模型和数据设计决策的问题。援用咱们的指标是通过对各种编程语言中最大的现有模型的零碎评估来填补其中的一些空白:Codex、GPT-J、GPT-Neo、GPT-NeoX-20B 和 CodeParrot。只管 Codex 自身不是开源的,但咱们发现,针对自然语言建模,现有的开源模型的确在某些编程语言中获得了靠近的后果。咱们进一步确定了一个重要的缺失局部,即专门在多语言代码语料库上训练的大型开源模型。咱们公布了一个新模型 PolyCoder,它具备基于 GPT-2 架构的 2.7B 参数,该模型在单台机器上应用 12 种编程语言的 249GB 代码进行了训练。在 C 编程语言中,PolyCoder 优于包含 Codex 在内的所有模型。咱们训练有素的模型是开源的,可在此 https URL 上公开取得,这使得该畛域的将来钻研和利用成为可能。援用—— MobTech袤博科技资深java开发工程师 零零发 MobTech袤博 比Codex还会写C语言的AI代码生成模型,当初开源了!这段时间,用AI写代码能够说是大火,其中最驰名的要属OpenAI的Codex和DeepMind的AlphaCode。 然而,这两个AI模型,全都没有开源: 其中AlphaCode只给出了一些测试样例,而Codex只凋谢了API。 为此,来自CMU的几个钻研人员,用GPT-2搞出了一个名叫PolyCoder的AI代码生成模型,而且还是开源的。 据钻研人员示意,尽管PolyCoder最大只有27亿参数(相比Codex有120亿参数),但它用C语言写进去的代码,比Codex的成果还要好。 这外面到底有什么秘诀? 用12种编程语言代码集训练首先来看训练用的数据集,这也是PolyCoder的最大特点之一。 此前,包含Codex、CodeParrot等AI代码生成模型,次要都是基于Python语言的代码来训练。 例如Codex的评估数据集之一HumanEval,评估的也是生成Python代码的成果。相比之下,PolyCoder采纳了多种编程语言代码集来训练,一共有12种:C、C#、C++、Go、Java、JavaScript、PHP、Python、Ruby、Rust、Scala和TypeScript。 其中,C语言的代码量是最多的,达到了221GB;而Python代码的数据量比Codex和CodeParrot用得都要少。 这里PolyCoder用的是GitHub上的公开代码,次要选取的是各种编程语言中比拟受欢迎的库,每个库至多有50 Stars。 据钻研人员示意,每种编程语言库的Stars总数加起来不超过25k,以防止模型生成的代码成果太过于歪斜最风行的编程语言(通常编程语言越风行,库的Stars就越多)。 通过提取库中的文件、通过简略解决(包含打消反复代码)后,一共筛选出大概254GB的数据用于训练。 而后是预训练的办法。 语言模型的预训练方法通常有三种。第一种是自左向右的语言模型,依据上文预测下文,比拟实用于代码生成等;第二种是掩蔽语言模型,基于上下文预测屏蔽片段,比拟适宜代码分类等;第三种是编解码器模型,比拟实用于代码正文等工作。 这里PolyCoder次要采纳的是第一种预训练方法。 相比于同样采纳GPT-2训练的CodeParrot和Codex,PolyCoder在超参数设置上也略微有一些差别:PolyCoder一共提供了三种不同的模型,别离有27亿参数、4亿参数和1.6亿参数,钻研人员能够依据本身需要和不同的训练能力来选取适合的模型。那么,最终训练进去的AI模型,代码生成成果如何? C语言写得尤其好,但Python不行钻研人员将PolyCoder与已有的AI代码生成模型进行了比照。因为AlphaCode不好比拟(接口没凋谢),所以钻研人员次要剖析了上面这些模型,包含GPT-Neo、CodeParrot和Codex等。其中蓝色的是开源的,橙色的是没开源的:从参数量来看,PolyCoder并不是最顶尖的,最大的27亿参数模型也只有Codex的四分之一不到。钻研人员先是用语言模型评估罕用的困惑度对一系列模型进行了比拟。 困惑度(Perplexity),用于掂量语言模型(LM)的好坏。困惑度越低,语言模型面对代码感到困惑的水平就越低,模型生成成果越好。从图中来看,PolyCoder在C语言中意外获得了最好的成果(困惑度最低)。用大量C语言训练PolyCoder的后果阐明,即便模型整体原理不变(基于GPT-2),单纯扭转训练用的代码集,也能训练出善于不同语言格调的AI代码生成模型。 惋惜的是,从其余语言来看,生成的成果就齐全没方法和Codex相比了:例如,在次要用于评估Python代码的HumanEval上,PolyCoder的能力远不如Codex好:据论文剖析,这可能是Python代码数据量、模型参数量有余等起因导致的。此外,作者们也提到,做出PolyCoder的目标次要还是为了开源一个AI代码生成模型,让更多人参加钻研和应用。 目前代码曾经开源,无论是间接拿来用,还是试着在它的根底上开发新模型都能够。 感兴趣的小伙伴能够上手一试了~

August 16, 2022 · 1 min · jiezi

关于c:编程利器-实用的CC语言在线编译器

无论应用什么语言编程,编译器始终是一个绕不开的问题。很多学习编程的小伙伴往往在开发环境装置、配置这一步,提前解锁了从入门到放弃的成就。 大家可能在学习编程语法的时候并不感觉太难,却在奇怪的中央被编译器卡住了。很多人可能花了微小的心理和工夫下载、装置并且进行各种配置,到头来却发现编译器没法应用而被浇了一盆冷水,学习编程的劲儿也因而被耗费磨损掉了。 明天次要来安利一款反对C语言、 C++、 Java、Python、Go等多种语言的在线编译器:Lightly IDE(https://lightly.teamcode.com/c)。 以C语言在线编译器为例,大家只须要在浏览器关上就能够开始编程并一键运行: 抉择编程语言和版本,让C语言在线编译器主动创立我的项目文件。 我的项目文件创建好后,就能够在编辑区编写代码了。实现后,只须要点击右上角的运行键就能够应用C语言在线编译器一键编译并运行代码。 与其余本地编译器不同,这款C语言在线编译器能够不依靠于本地环境也不须要用户手动进行各种简单配置。在文件治理上也非常业余,用户只须要登录本人的账号便能够在任何设施上拜访主动保留在云端的我的项目文件。 在编程的过程中,咱们还能在C语言在线编译器中应用断点性能调试代码,解决代码中的各种bug。 最初,心愿这款C语言在线编译器能帮忙大家在学习编程的路上更轻松、更便捷,同时也帮忙大家无需再受本地编译环境的限度,逾越不同设施随时随地编程。

August 6, 2022 · 1 min · jiezi

关于c:假如有n个台阶一次只能上1个台阶或2个台阶请问走到第n个台阶有几种走法

2023王道作业week4_day12————走楼梯1.题目:如果有n个台阶,一次只能上1个台阶或2个台阶,请问走到第n个台阶有几种走法?为便于读者了解题意,这里举例说明如下:如果有3个台阶,那么总计就有3种走法:第一种为每次上1个台阶,上3次;第二种为先上2个台阶,再上1个台阶;第三种为先上1个台阶,再上2个台阶。输出为n,输入为走到第n个台阶有几种走法 2.思路设台阶为n个 当n=1时,走法为1当n=2时,走法为2,1+1或2当为n个时,相当于在n-1这个台阶走一步或者在n-2这个台阶走两两步所以n个台阶相当于n-1个台阶的走法加上n-2个台阶的走法 递归函数 :ways(n) = ways(n-1) + ways(n-2);递归进口:n=1 return 1;n=2 return 2; ### 代码实现//如果有n个台阶,一次只能上1个台阶或2个台阶,请问走到第n个台阶有几种走法?//为便于读者了解题意,这里举例说明如下:如果有3个台阶,那么总计就有3种走法:第一种为每次上1个台//阶,上3次;第二种为先上2个台阶,再上1个台阶;第三种为先上1个台阶,再上2个台阶。输出为n,输入//为走到第n个台阶有几种走法 include<stdio.h>int ways(int n){ if (n == 1){ return 1;}if (n == 2){ return 2;}return ways(n - 1) + ways(n - 2);}int main(){ int n;scanf("%d", &n);int result = ways(n);printf("%d\n", result);return 0;}

August 4, 2022 · 1 min · jiezi

关于c:如何在C语言中定义自己的数据类型

在C语言编程中,咱们其实能够关上编程语言的拘谨,本人定义本人想要的数据类型。只有记住 struct 和 typedef 两个关键词,咱们就能够通过C语言中的数据结构和共用体来保留非同质化的数据类型。 定义新的数据类型首先,在C语言在线编译器中输出以下代码: typedef struct student_structure { char* name; char* surname; int year_of_birth;} student;实现后,这段代码会把 student 预存为保留词,那样咱们能创立 student 类型的变量了。 那么这个新变量到底是怎么形成的呢?咱们所创立的这个结构化新变量是通过一系列根底变量组成的。在下面的代码中,咱们把 char name、char surname 这些变量组成了新的 student 变量中,其实就是放到内存块的一个名下。 应用新数据类型咱们当初创立好新的 student 变量后,能够在C语言在线编译器中为它初始化一些属性: student stu; strcpy(stu.name, "John"); strcpy(stu.surname, "Snow"); stu.year_of_birth = 1990; printf("Student name : %s\n", stu.name); printf("Student surname : %s\n", stu.surname); printf("Student year of birth : %d\n", stu.year_of_birth);在下面的例子中,眼尖的你可能曾经发现了咱们须要为新数据类型的所有变量调配一个值。除了应用 stu.name 来拜访外,咱们还能够应用更短的形式来为这些构造调配值: typedef struct { int x; int y;} point;point image_dimension = {640,480};你也能够应用不同的程序来设定值:point img_dim = { .y = 480, .x = 640 }; ...

July 29, 2022 · 1 min · jiezi

关于c:c语言实现点名系统

点名零碎分为两种,一种为反复点名,一种为不反复点名反复点名:顾名思义,随机点到后,下次兴许还会点到 反复点名 #define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include<string.h>#include <stdlib.h>#include <time.h>#include<conio.h>#define N 57 //同学人数int main(){ int num = 0; void menu(); scanf("%d", &num); switch (num) { case 1: void chongfu(); break; case 2: void buchongfu(); break; default: } return 0;}void menu(){ printf("请输出数字,进入不同模式"); printf("1.反复点名"); printf("2.不反复点名");}void chongfu(){ int list[N], i, j, r, k; const char* s[N] = { “aa".......57个同学名字,define定义数雷同,否则报错 };//人名单 printf(" 随机点名,输出'0'退出。\n"); while (1) { printf("请问想点几个:"); scanf("%d", &k); //输出人数 if (k == 0) break; if (k > N) { printf("输出谬误\n"); continue; } else { srand(time(NULL)); for (i = 0; i < k; i++) //生成不反复的随机数组 { while (1) { r = rand() % N; for (j = 0; j < i; j++) { if (list[j] == r) break; } if (j == i) { list[i] = r; break; } } } //输入人名 for (i = 0; i < k; i++) { printf("%s\n", s[list[i]]); } } } return;}不反复点名 ...

July 18, 2022 · 2 min · jiezi

关于c:typedef有四种用法你都会了吗

此篇博客适宜初学者浏览,心愿我的科普能为你的学习减少更多能源Typedef 是编程语言 C 和 C + + 中的一个保留关键字。它用于为另一个数据类型创立附加名称(别名) ,但不创立新类型,除非是数组类型的限定 typedef,其中 typedef 限定符被转移到数组元素类型。因而,它通常用于简化申明由 struct 和 union 类型组成的简单数据结构的语法,然而在为不同长度的整数数据类型提供特定的描述性类型名称时也同样常见。 1.为自定义数据类型(构造体、共用体和枚举类型)定义简洁的类型名称刚自学入门c的时候,坦率的说,我看的这个demo和输入后果,我对typedef的第一印象是替换,当然我对我当初的了解,在当初看来,也是可能解释的通的。 typedef struct tagPoint { double x; double y; double z; } Point;它理论等于 struct tagPoint { double x; double y; double z; } ;因为ponit转化成了构造体变量tagpoint 2.为根本数据类型定义新的类型名例如这样: typedef unsigned int ABC;可能看到这里,往往会想到构造体struct,具体区别能够参考 https://riptutorial.com/c/exa...,has%20to%20include%20the%20whole%20definition%20of%20bar.3.为数组定义简洁的类型名称例如这样: typedef int INT_ARRAY_100[100]; INT_ARRAY_100 arr;4.为指针定义简洁的名称 typedef char* PCHAR; PCHAR pa;以上就是全副区别了,如果你还有更多有意思或者更好的内容,欢送评论区补充

July 7, 2022 · 1 min · jiezi

关于c:数据结构与算法初级

复杂度解说算法效率算法效率分为两种:工夫效率(工夫复杂度)和空间效率(空间复杂度)它们别离掂量一个算法的运行工夫和所占的空间大小。工夫复杂度工夫复杂度计算的是一个函数中算法基本操作的执行次数。工夫复杂度针对的是一整个函数。工夫复杂度的计算方法(大O渐进表示法)大O渐进表示法是一种估算:只取表达式中对后果影响最大的一项。推导大O阶办法: 用数字1取代算数中的所有常数。在批改后的算数中,只保留最高项。如果最高阶存在且不是1,则去除这个项的常数,失去的后果就是大O阶。例如: 下列的工夫复杂度算数为 :F(N) = 2*N + 10所以大O阶表达式为 :O(N)void Fun1(int N){ int count = 0; for (int i = 0; i < 2 * N; i++) { ++count; } int M = 10; while (M--) { ++count; } printf("%d", count);}留神:当函数中未知数有多个时例如: 工夫复杂度表达式为:F(N) = M + N + 10 时,大O阶为 O(M+N) 或者 O(N)工夫复杂度表达式为:F(N) = 1000 时,大O阶为 O(1) (第一步将所有常数用1代替)O(1) 示意的是算法中基本操作执行常数次,而不是真的只执行一次。工夫复杂度表达式为:F(N) = M*M + N + 10 时,大O阶为 O(M^2)工夫复杂度中:为了不便个别把log2N(以2为底数)写作logN (log3N等就不会缩写了)所谓的线性工夫复杂度就是指O(N)。空间复杂度空间复杂度是对一个算法在运算过程中,长期占用的内存空间大小。空间复杂度不是计算程序占用了多少个字节,而是计算长期变量的个数。空间复杂度的计算方法也采纳大O渐进表示法。O(1) 代表常数个变量。递归算法的空间复杂度就是递归的深度乘以每个算法的空间复杂度(每递归一次,就会在栈中创立一个长期的函数)留神: 工夫是累计的,空间是能够复用的创立局部变量后,在程序出大括号后,就会销毁。程序表和链表线性表线性表是 n 个具备雷同个性的数据元素的无限序列常见的线性表:程序表、链表、栈、队列等。线性表在逻辑上是线性构造,但理论物理存储上通常是以数组和链式构造的模式存储的。程序表和链表程序表: ...

July 4, 2022 · 1 min · jiezi

关于c:C程序设计-10-文件操作

一、C 文件基本知识1. 文件与文件分类文件(flie)个别是指存储在内部介质(如磁盘)上的数据的汇合。操作系统是以文件为单位对数据进行治理的。文件有不同类型,C 语言中次要用到两种文件: 程序文件:包含源程序文件 .c、指标文件 .obj、可执行文件 .exe。文件的内容是程序代码。数据文件:文件的内容是供程序运行时读写的数据。咱们次要探讨的是数据文件。 C 语言把文件看作一个字符(或字节)的序列,即由一个一个字符(或字节)的数据程序组成。一个输入输出流就是一个字符流或字节(内容为二进制数据)流。C 的数据文件由一连串的字符(或字节)组成,对文件的存取是以字符(字节)为单位的。输入输出数据流的开始和完结仅受程序控制而不受物理符号(如回车换行符)管制,这就减少了解决的灵活性。这种文件称为流式文件。 一个文件要有惟一的文件标识,以便辨别和援用,这就是文件名。文件标识包含 3 局部:①文件门路;②文件名骨干;③文件后缀。如: D:\cProgram\temp\file1.dat工具数据的组织模式,将数据文件分为 ASCII 文件和二进制文件。数据在内存中是以二进制模式存储的,如果不加转换地输入到外存,就是二进制文件,能够认为它就是存储在内存的数据的映像,所以也称之为映像文件(image file)。如果要求在外存上以 ASCII 代码模式存储,则须要在存储前进行转换。ASCII 文件又称文本文件(text file),每一个字节寄存一个字符的 ASCII 代码。 用 ASCII 码模式输入时字节与字符一一对应,一个字节代表一个字符,因此便于对字符进行一一解决,也便于输入字符。但个别占存储空间较多,而且要花费转换工夫(二进制模式与 ASCII 码间的转换)。用二进制模式输入数值,能够节俭外存空间和转换工夫,把内存中的存储单元中的内容一成不变地输入到磁盘(或其余内部介质)上,此时每一个字节并不一定代表一个字符。如果程序运行过程中有的两头数据须要保留在内部介质上,以便在须要时再输人到内存,个别用二进制文件比拟不便。在事务管理中,常有少量数据寄存在磁盘上,随时调人十算机进行查问或解决,而后又把批改过的信息再存回磁盘,这时也罕用二进制文件。 2. 文件缓冲区ANSI C 规范采纳“缓冲文件系统”解决数据文件,所谓缓冲文件系统是指零碎主动地在内存区为程序中每一个正在应用的文件开拓一个文件缓冲区。从内存向磁盘输入数据必须先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘去。如果从磁盘向计算机读入数据,则一次从磁盘文件将一批数据输人到内存缓冲区(充斥缓冲区),而后再从缓冲区一一地将数据送到程序数据区(给程序变量)。这样做是为了节俭存取时间,提高效率,缓冲区的大小由各个具体的 C 编译系统确定。 3. 文件类型指针缓冲文件系统中,要害的概念是“文件类型指针”,简称文件指针。每个被应用的文件都会在内存中开拓一个相应的文件信息区,用来寄存文件的无关信息,这些信息是保留在一个零碎申明的构造体变量 FILE 中。例如,一种 C 编译环境提供的 stdio.h 头文件中有以下文件类型申明: typedef struct { short level; // 缓冲区“满”或“空”的长度 unsigned flags; // 文件状态标记 char fd; // 文件描述符 unsigned char hold; // 如缓冲区无内容不读取字符 short bsize; // 缓冲区大小 unsigned char* buffer; // 数据缓冲区的地位 unsigned char* curp; // 文件地位标记指针以后的指向 unsigned istemp; // 临时文件指示器 short token; // 用于无效查看} FILE;以上申明 FILE 构造体类型的信息蕴含在头文件 stdio.h 中。在程序中能够间接用 FILE 类型名定义变量。每一个 FILE 类型变量对应一个文件的信息区,在其中寄存该文件的无关信息。例如: ...

July 2, 2022 · 3 min · jiezi

关于c:C程序设计-09-自定义数据类型

一、定义和应用构造体变量1. 定义构造体类型后面定义应用的变量根本是互相独立、五无在分割的,在内存中的地址也是互不相干的。但在理论生存和工作中,有些数据是有内在联系的、成组呈现的。例如,一个学生的学号、姓名、性别、年龄等,是属于同一个学生的。如果将这些变量别离定义为互相独立的简略变量,难以反映他们之间的内在联系,而数组又只能寄存同一类型的数据。 C 语言容许用户本人建设又不同类型数据组成的数据结构,称为构造体(structure)。其余一些高级语言中也称为“记录”(record)。申明一个构造体类型的个别模式为: struct 构造体名 { 成员表列 };其中,struct 是申明构造体类型的关键字,不可省略。构造体名由用户指定,又称为构造体标记(structure tag),以区别于其余构造体类型。成员表列(member list)也称为域表(field list),每一个成员是构造体中的一个域。成员名命名规定与变量名雷同。构造体的成员也能够是另一个构造体。 也成为下面的例子申明构造体类型如下: struct Student { char id[10]; char name[20]; char sex; int age;}构造体类型和零碎提供的规范类型具备类似作用,都能够用来定义变量。 2. 定义构造体类型变量定义了构造体类型后,将来在程序中应用构造体类型的数据,应该定义构造体类型变量,并在其中存放数据。能够采取 3 种办法定义构造体类型变量。 先申明构造体类型,再定义该类型的变量能够应用下面定义的构造体类型 struct Student 来定义变量: struct Student student1, student2;这种模式和定义其余根本类型的变量是类似的。下面定义了 student1 和 student2 为 struct Student 类型的变量。 这种形式是申明类型和定义变量拆散,在申明类型后能够随时定义变量,比拟灵便。 在申明类型的同时定义变量这种定义方法的个别模式为: struct 构造体名 { 成员表列} 变量名表列;例如: struct Student { char id[10]; char name[20]; char sex; int age;} student1, student2;小型程序中,该办法能够间接看到构造体的构造,比拟直观不便。但在大型程序中,往往要求对构造体类型的申明和对变量的定义别离放在不同中央,以使程序结构清晰,便于保护。 不指定类型名而间接定义构造体类型变量其个别模式为: struct { 成员表列} 变量名表列;该办法指定了一个无名的构造体类型,因为没有构造体名,因而不宜再次以此构造体类型去定义其余变量。 ...

June 30, 2022 · 5 min · jiezi

关于c:C程序设计-08-指针

一、什么是指针1. 地址与指针在程序中定义了一个变量,编译时零碎会给这个变量调配存储单元,同时依据变量的数据类型,调配肯定长度的空间。内存区的每一个字节都有一个编号,这就是“地址”。因为通过地址就能够找到所需的变量单元,能够说,地址指向该变量单元。由此,将地址形象地称为指针。 C 语言对不同的数据类型调配不同大小的存储单元,且不同数据类型的存储形式是不一样的。因而,即便给了一个地址,也无奈保障能正确存取所须要的信息。为了能正确存取一个数据,前途须要地位信息,还须要该数据的类型信息。C 语言的地址包含地位信息(地址编号,或称纯地址)和它所指向的数据的类型信息,或者说它是“带类型的地址”。 2. 间接拜访与间接拜访在程序中,个别是通过变量名来援用变量的值的,如: scanf("%d", &n);printf("%d\n", n);这种间接按变量名进行的拜访称为间接拜访。 还能够采纳另一种称为间接拜访的形式,行将一个变量 n 的地址寄存在另一个变量 n_pointer 中,而后通过变量 n_pointer 来找到变量 n 的地址,从而拜访该变量。 如果咱们要对变量 n 赋值,当初就有了两种办法: 间接拜访:依据变量名间接向变量 n 赋值,因为变量名与变量地址有一一对应关系,因而就依照此地址间接对变量 n 的存储单元进行拜访。间接拜访:先找到寄存变量 n 地址的变量 n_pointer,从中失去变量 n 的地址,从而找到变量 n 的存储单元,对它进行拜访。如果一个变量专门用来寄存另一变量的地址,则称为指针变量。上述的 n_pointer 就是一个指针变量。指针变量就是地址变量,用来寄存地址。 二、指针变量寄存地址的变量就是指针变量,它用来指向另一个对象(如变量、数组、函数等)。 1. 定义指针变量定义指针变量的个别模式为: 类型名* 指针变量名;定义指针是必须指定其根本类型,该类型示意此指针能够指向的变量的类型。因而,指针类型是根本数据类型派生进去的类型,不能来到根本类型而独立存在。 定义指针的同时也能够对其进行初始化,如: int* a;char* b = &c;定义指针时要留神: 指针后面的 * 示意该变量为指针型变量,指针变量名为 a 而不是 *a。一个变量的指针的含意包含两方面:存储单元编号示意的地址和它指向的存储单元的数据类型。指针变量只能寄存地址,不能将一个整数赋值给指针变量。2. 援用指针变量援用指针变量有 3 种状况: 给指针变量赋值: p = &a;援用指针变量指向的变量: *p = 1;printf("%d", *p);援用指针变量的值: printf("%o", p); // 以八进制输入指针变量的值(即指向的变量的地址)要熟练掌握两个无关运算符: &:取地址运算符。*:指针运算符(或称为“间接拜访运算符”)。3. 指针变量作为函数参数将一个变量的地址传到一个函数中能够应用指针变量作为函数参数。 ...

June 30, 2022 · 5 min · jiezi

关于c:替换百度云这款开源网盘颜值更高功能更全面

你好,我是小金。 如果你还在纠结应用什么工具来存储文件,还在放心文件的内容不平安,还在因为云存储服务(比方百度云)的托管费用以及下载速度而不悦的话,请肯定要看完小金明天举荐的开源云盘我的项目。 说不定!这个我的项目就会成为你的所爱。 这个开源笔记我的项目就是 Seafile,一个一款平安、高性能的开源网盘,基于 C 语言开发而成,不论是自用还是搭建企业云盘都十分不错! Seafile 提供了支流网盘(云盘)产品所具备的性能,包含文件同步、文件共享、合作共享、Office 文档在线编辑、Wiki 与常识治理等。 成果预览上面咱们来简略看看应用 Seafile 搭建的在在线云盘的效果图。 跨平台文件同步 挪动端文件拜访 挂载盘客户端 不必同步即可像本地磁盘一样拜访云端文件。 在线编辑和协同编辑 Wiki 与常识治理 装置应用Seafile 是开源的,你能够把它部署在公有云的环境中,作为公有的企业网盘。Seafile 反对 Mac、Linux、Win­dows 三个桌面平台,反对 An­droid 和 iOS 两个挪动平台。 装置部署 Seafile 的教程:https://manual.seafile.com/build_seafile/server 。 如果你本人部署我的项目的话,能够间接应用 Seafile 官网提供的 SaaS 服务。你只须要注册一个账号,即可在云上应用多终端文件同步、合作共享、Office 文档在线编辑、全文检索、常识治理等 Seafile 企业版性能。 总结Seafile 提供了支流网盘(云盘)产品所具备的性能,包含文件同步、文件共享、合作共享、Office 文档在线编辑等。 如果你或者你的团队须要搭建一个在线云盘应用的话,能够考虑一下这个我的项目。 我的项目地址: https://github.com/haiwen/seafile

June 27, 2022 · 1 min · jiezi

关于c:C语言的文件操作

文件分类程序文件:源程序文件(.c文件)、指标文件(.obj文件)、可执行文件(.exe文件)数据文件:程序运行时读写的数据。文件的关上和敞开文件类型指针文件在被关上时,都会在内存中开拓一个相应的文件信息区,用来寄存被关上文件的相干信息(文件名、文件大小、文件地位等)。这些信息是保留在一个构造体中的,该构造体的申明就是FILE类型。 FILE *fptr; //文件指针 fptr = fopen("runoob.txt", "r")) //fopen关上一个文件,返回一个 FILE 指针 //fptr 当初就指向 runoob.txt文件的文件信息区。文件的关上和敞开在关上文件时,都会返回一个FILE* 的指针变量指向该文件,这样就建设了指针和文件的关系。留神:关上文件后,必须敞开文件,并且将定义的文件指针赋值为NULL。ANSIC规定:应用 fopen 函数来关上文件,应用 fclose 函数来敞开文件FILE *fopen(const char *filename, const char *mode) //关上文件函数//filename:字符串,示意要关上的文件名称//mode :字符串,示意文件的拜访模式,//返回值 :关上胜利返回一个 FILE 指针。否则返回 NULLint fclose(FILE *stream) //敞开文件函数//如果胜利敞开,则该办法返回零。如果失败,则返回 EOF。mode 文件拜访模式可选的值:文件的程序读写fgetc :字符读取函数(实用于所有流)fputc :字符写入函数(写入单个字符)fgets :文本行读取函数(从文件中读取一整行数据)fputs :文本行写入函数fscanf :格式化读取函数(从文件中读取数据)fprintf :格式化写入函数(向文件中写入数据)fread :二进制读取(实用于文件)fwrite :二进制写入(实用于文件)scanf/fscanf/sscanf和printf/fprintf/sprintf区别scanf :格式化的输出函数(输出就是读取,程序向控制台读取数据)printf :格式化的输入函数(输入就是写入,程序向控制台写入数据)fscanf :针对所有输出流的格式化输出函数fprintf :针对所有输入流的格式化输入函数sscanf :把一个字符串转换为格式化的数据sprinft :把一个格式化数据转换成字符串指定文件的地位读写fseek重定位指针依据文件指针的地位(whence)和偏移量(offset)来重定位文件指针(stream)int fseek(FILE *stream, long int offset, int whence)stream : 这是指向 FILE 对象的指针。offset : 这是绝对 whence 的偏移量,以字节为单位。whence : 指定文件指针的初始地位 SEEK_SET :文件的结尾SEEK_CUR :文件指针的以后地位SEEK_END :文件的开端#include <stdio.h>int main (){ FILE *fp; fp = fopen("file.txt","w+"); //创立一个用于写入的空文件 fputs("This is runoob.com", fp); //向文件中写入内容 fseek( fp, 7, SEEK_SET ); //重定位文件指针 fputs(" C Programming Langauge", fp); //向重定位后的地位写入数据 fclose(fp); //敞开文件 return(0);}//运行后果:This is C Programming Langaugeftell查找以后文件指针地位long int ftell(FILE *stream)stream :以后文件指针返回值 :返回以后文件指针相当于文件起始地位的偏移量rewind设置指针地位为文件起始地位void rewind(FILE *stream)函数作用:使文件指针stream指向文件的起始地位。被谬误应用的feof函数这个函数不能用来判断文件是否读取完结。而是用来在文件读取完结后,判断是哪种形式导致的文件读取完结(是文件读取失败还是文遇到文件结尾而完结的)文件缓冲区零碎会主动在内存中为每一个正在应用的文件开拓一块文件缓冲区(是在内存中开拓的)从程序向磁盘写入数据时,数据会先传输到缓冲区,当缓冲区填充斥后,再一起传输到硬盘中。从硬盘读取数据到程序时,数据也会先传输到缓冲区,当缓冲区填充斥后,再一起传输到内存中。fclose在敞开文件时,也会将缓冲区残余的数据放到硬盘中。

June 24, 2022 · 1 min · jiezi

关于c:动态内存管理

动静开拓内存malloc开拓内存#include <stdlib.h>void *malloc(size_t size)size :须要开拓的内存空间的大小,以字节为单位。返回值 :返回一个指向开拓的内存空间的指针(void*类型,须要其余类型时应用强制类型转换即可)如果申请失败,则返回 NULL。free开释空间void free(void *ptr)函数作用:开释之前调用 calloc、malloc 或 realloc 所调配的内存空间。ptr:指针指向一个要开释内存的内存块。个别在开释空间时,同时也会将该空间的指针赋值为NULL,防止它成为野指针。如果不开释申请的内存空间,在程序完结时,会由操作系统主动回收。calloc开拓内存malloc 和 calloc 之间的不同点是:calloc 会将申请的空间初始化为0,而malloc 是随机值。void *calloc(size_t nitems, size_t size)nitems :要被调配的元素个数。size :元素的大小。如果申请失败,则返回 NULL。realloc从新分配内存void *realloc(void *ptr, size_t size)ptr :须要从新分配内存的内存块的指针。 该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果为空指针,则会调配一个新的内存块。size : 内存块的新的大小,以字节为单位。 如果大小为 0,且 ptr 指向一个已存在的内存块,则 ptr 所指向的内存块会被开释,并返回一个空指针。留神: 如果源内存前面的空间足够大,则realloc会在源空间前面追加分配内存。如果源内存前面的空间不够大,则realloc会在其余空间分配内存,并且将原来空间的值顺次拷贝过来,而后将原来的空间开释掉。常见的动态内存谬误对NULL指针的解援用操作int main(){ int* p = (int*)malloc(1000); *p = 10; //如果内存调配失败,malloc返回NULL,这里就会出错 return 0;}解决办法:进行NULL检测(判断malloc(1000)是否等于NULL)对动静开拓空间的越界拜访int* p = (int*)malloc(1000);for (int i = 0;i<1000;i++){ *(p + i) = i; //这里当i超过250后,就会呈现越界拜访}对非动静开拓内存的开释int a = 10;int* p = &a;free(p); //a是局部变量,不能用free开释,由零碎主动开释p = NULL;对动静开拓的空间只开释一部分int* p = (int*)malloc(100);for (int i = 0; i < 50; i++){ p++;}free(p); //此时指针p曾经指向开拓的空间两头局部了,只能开释指针之后的局部p = NULL;对同一块内存屡次开释int* p = (int*)malloc(100);free(p); p = NULL;free(p); //屡次开释,程序会出错。p = NULL;

June 23, 2022 · 1 min · jiezi

关于c:通讯录小项目实现增删改查

main.c文件#define _CRT_SECURE_NO_WARNINGS 1#include "contact.h"void test(SUM* pc){ /*char arr[] = "222"; change(pc,arr); print(pc);*/ int i = 0; char arr[name_MAX]; printf("请输出指令:"); while (1) { scanf("%d", &i); switch (i) { case ADD_1: ADD(pc); printf("请再次输出指令:"); break; case delet_2: printf("请输出要删除的联系人姓名:"); scanf("%s", arr); delet(pc, arr); printf("请再次输出指令:"); break; case change_3: printf("请输出要批改的联系人姓名:"); scanf("%s", arr); change(pc, arr); printf("请再次输出指令:"); break; case search_4: printf("请输出要搜寻的联系人姓名:"); scanf("%s", arr); print_one(pc, search(pc, arr)); printf("请再次输出指令:"); break; case print_5: print(pc); printf("请再次输出指令:"); break; case print_one_6: printf("请输出要显示的联系人姓名:"); scanf("%s", arr); print_one(pc, search(pc, arr)); printf("请再次输出指令:"); break; default: printf("输出有误!请从新输出:"); break; } } return;}int main(){ //构造体初始化 SUM Data = { .people = {{"111","444","777"},{"222","555","888"},{"333","666","999"}}, .size = 3 }; test(&Data); return 0;}contact.c文件#define _CRT_SECURE_NO_WARNINGS 1#include "contact.h"//减少联系人void ADD(SUM* const pc){ printf("请输出姓名:"); scanf("%s", &(pc->people[pc->size].name)); printf("请输出单位:"); scanf("%s", &(pc->people[pc->size].danwei)); printf("请输出号码:"); scanf("%s", &(pc->people[pc->size].tele)); (pc->size)++; return;}//搜寻联系人,依据姓名查找,返回对应的下标int search(SUM* const pc, const char * arr){ for (int i = 0;i<pc->size;i++) { if (strcmp(((pc->people)[i].name), arr) == 0) { return i; //找到了,返回对应下标 } } return -1; //-1示意没找到}//删除联系人void delet(SUM* const pc, const char *arr){ int a = search(pc,arr); for (a;a<(pc->size-1);a++) { pc->people[a] = pc->people[a + 1]; } (pc->size)--; return;}//打印联系人void print(SUM* const pc){ for (int i = 0; i < pc->size; i++) { printf("%s ", (pc->people)[i].name); printf("%s ", (pc->people)[i].danwei); printf("%s ", (pc->people)[i].tele); printf("\n"); } return;}//打印某一个联系人void print_one(SUM* const pc, const int i){ printf("%s ", (pc->people)[i].name); printf("%s ", (pc->people)[i].danwei); printf("%s ", (pc->people)[i].tele); printf("\n"); return;}//改void change(SUM* const pc, const char* arr){ int a = search(pc, arr); printf("请输出姓名:"); scanf("%s",pc->people[a].name); printf("请输出单位:"); scanf("%s", pc->people[a].danwei); printf("请输出号码:"); scanf("%s", pc->people[a].tele); return;}contact.h文件#pragma once#include <stdio.h>#include <string.h>#define name_MAX 20#define danwei_MAX 20#define tele_MAX 12#define people_MAX 100#define ADD_1 1#define delet_2 2#define change_3 3#define search_4 4#define print_5 5#define print_one_6 6typedef struct Contact{ char name[name_MAX]; char danwei[danwei_MAX]; char tele[tele_MAX];}Contact;typedef struct SUM{ Contact people[people_MAX]; int size;}SUM;void ADD(SUM* const pc);void delet(SUM* const pc, const char* arr);void change(SUM* const pc, const char* arr);int search(SUM* const pc, const char* arr);void print(SUM* const pc);void print_one(SUM* const pc, const int i);

June 23, 2022 · 2 min · jiezi

关于c:自定义类型结构体等

构造体构造体定义方法定义方法一: struct MyStruct //定义构造体,定义的构造体在内存中是不占空间的{ int a; char b; short c;}; //没有创建对象int main(void){ //应用构造体,创立一个构造体对象,创建对象时才会占用内存空间 struct MyStruct a = {10,'b',4}; //能够在创立时就初始化,也能够在之后赋值 struct MyStruct* sp = &a; //构造体指针 a.a = 10; (*sp).b = 'b'; sp->c = 4;}定义方法二: struct MyStruct{ int a; char b; short c;}s1,s2,s3; //s1,s2,s3 是创立的构造体对象,在定义构造体的同时创建对象//s1,s2,s3 是全局变量 int main(void){ s1.a = 10; //这里能够间接应用构造体对象}定义方法三: typedef struct MyStruct //相当于对这个构造体重命名为 Stu{ int a; char b; short c;}Stu; int main(void){ Stu s1; //应用重命名,进行创建对象。}构造体作为参数时函数传参时,参数是须要压栈的如果传递一个构造体对象时,间接传递构造体实参,在函数那边会压栈一个同样大小的内存空间(创立构造体形参),会导致系统开销增大,从而导致性能升高。所以传递构造体参数时,尽量传递构造体的指针(地址)匿名构造体类型留神:如果两个匿名构造体的成员一样,然而在编译器看来也是不同的构造体类型。struct //没有申明构造体的名称{ int a; char b; short c; }x; //定义了一个构造体的对象//这种申明构造体办法,只能在申明时定义构造体对象,之后不能在定义对象(没有构造体名称)struct { int a; char b; short c; }p; //p和x是不同的构造体类型。构造体的自援用struct Node{ int date; struct Node* next; //用指针指向下一个同类构造体的地址。 //struct Node n; //在构造体中创立本人类型的对象 //这种用法是谬误的,会呈现套娃的状况,内存会无限大,零碎报错}构造体内存对齐先看示例:struct X { int a; char b; short c; }; struct P { char a; int b; char c short d; struct X st;}; struct P a;printf("%d\n",sizeof(p)); //输入后果为 20构造体对齐规定第一个成员,寄存在构造体变量偏移量为0的地址处(即构造体变量的首地址处)其余成员要对齐到某个数(对齐数)的整数倍的地址处。 ...

June 22, 2022 · 2 min · jiezi

关于c:字符串和内存函数

字符操作函数strlen()求字符串长度#include <string.h>size_t strlen(const char *str)str :要计算长度的字符串的首地址。size_t :这是unsigned int类型,是无符号的。留神 :必须读取到 \0 才算完结,然而返回的长度不包含结尾字符 \0。char arr1[] = "abcd";char arr2[] = {'a','b','c','d'};int a = strlen(arr1); //a的值为4int c = strlen(arr2); //c的值无奈确认,因为数组前面没有\0,所以strlen要始终计算到有 \0的中央才完结//所以C的值可能会很大字符串拷贝strcpy()#include <string.h>char *strcpy(char *dest, const char *src)把 src 所指向的字符串复制到 dest。该函数返回一个指向最终的指标字符串 dest 的指针(即返回dest的地址)留神:源字符串 src 必须以 \0 结尾,否则程序会解体这个函数会将源字符串中的 \0 也拷贝过来。留神:指标dest空间的值必须可变,能力放下源字符串。char* arr1 = "abcde";char arr2[] = "qwer";strcpy(arr1,arr2); //这种用法是谬误的,程序会解体// 因为arr1 是常量字符串,是不可更改的,所以会解体。strncpy()char *strncpy(char *dest, const char *src, size_t n)n :指定要从 src 中拷贝的字符个数。当源字符串 src 中没有 n 个字符时,任然会拷贝 n 个字符(残余的用 '\0' 填充)字符串追加strcat()#include <string.h>char *strcat(char *dest, const char *src)作用:将src中的字符串追加到 dest 字符串前面。dest :指向指标数组,该数组蕴含了一个 C 字符串,且足够包容追加后的字符串。src :指向要追加的字符串,该字符串不会笼罩指标字符串。返回值:返回一个指针,指向dest。这种办法追加字符串,能够追加本人。留神: ...

June 22, 2022 · 2 min · jiezi

关于c:函数指针

函数指针函数指针:指向函数的指针,函数名就相当于一个函数指针。函数指针的定义int add(int a,int b){ return a+b;}int main(){ printf("%p", add); printf("%p", &add); //两个输入后果雷同,add和&add都是失去函数的地址 int (*pf)(int, int) = add; //定义函数指针 //(*pf)示意变量pf是一个指针,(int, int)示意函数的参数类型,int 示意函数的返回值}函数指针的应用int (*pf)(int, int) = add; //定义函数指针int ret = (*pf)(2,3);//(2,3)示意传递的参数,(*pf)解援用函数,调用函数,留神这个括号不能省略。int ret = pf(2,3); //pf其实就相当于add。简单函数指针类型解读(*(void(*)())0)();//首先最内层:(*)示意它是一个指针//其次:void(*)() 这是一个定义函数指针的变量类型,返回值为void,无传参。//(void(*)())0 变量类型被放在括号中,示意强制类型转换,将0转化为函数指针,这示意0地址处寄存的是一个函数地址//*(void(*)())0 解援用这个函数指针,调用函数//(*(void(*)())0)() 最初的括号示意函数传参。//这句程序的作用是:调用0地址处的函数void (*add(int,void(*)(int)))(int);//首先最内层:void(*)(int) 示意一个函数指针类型//其次:add(int,void(*)(int)) ;add示意函数名,(int,void(*)(int))示意这个函数的参数//当去掉add(int,void(*)(int))之后,只剩下void (*)(int),而void (*)(int)就是函数的返回类型//所以这句程序的意思:定义一个函数,函数名为add,传参为(int,void(*)(int)),返回值为void (*)(int)型//其实就相当于:void (*)(int) add(int,void(*)(int)) //然而留神下面这个写法是错的,只是能够这样了解上述程序。//能够应用另外一种办法实现上述程序typedef void(*pf_t)(int) ; //重定义类型,将void(*)(int)类型用pf_t代替pf_t add(int, pf_t); //这句成果和上述程序雷同。函数指针数组int (*p[3])(int,int) = {test1,test2,test3}; //定义函数指针数组p[3]。int ret = p[1](3,5); //应用函数指针数组指向函数指针数组的指针int (*pf[4])(int, int); //函数指针数组//pf先与[4]联合示意它是一个数组int (*(*p)[4])(int, int) = &pf; //指向函数指针数组的指针//p先与*号联合,示意它是一个指针int ret = (*p)[1](3,4); //指向函数指针数组的指针的应用//(*p)先解援用失去函数指针数组,(*p)就相当于pf,[1]示意应用第哪个函数,(3,4)示意传参。C库排序函数qsort()它不仅只能排序数组,还能够排序构造体等void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))//base -- 指向要排序的数组的第一个元素的指针。//nitems -- 要排序数组中元素的个数.//size -- 数组中每个元素的大小,以字节为单位//compar -- 用来比拟两个元素的函数,这个函数须要程序员本人依据理论状况写//compar 函数只须要比拟第一个参数和第二个参数的大小并返回即可//返回值为正,则示意正序排列//返回值为负,则示意反序排列//返回值为0, 示意不排序示例:输入后果:15 20 24#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>#include <stdlib.h>struct Stu{ char name[10]; int age; double score;};int compar(const void* e1, const void* e2){ return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;}void main(){ struct Stu arr[3] = { {"zhangsan",20,55.5},{"lishi",24,57.0},{"wangwu",15,34.2} }; int sz = sizeof(arr) / sizeof(arr[0]); //计算要排序数组中元素的个数 qsort(arr, sz, sizeof(arr[0]), compar); for (int i = 0; i < 3; i++) { printf("%d\n", arr[i].age); }}

June 20, 2022 · 1 min · jiezi

关于c:数组与指针二

数组和指针传参一维数组传参int arr[10] = {0};test(arr); //实参传递的是数组的首元素首地址//形参写成数组的模式 void test(int brr1[10]) //办法一void test(int brr1[]) //办法二,形参局部能够省略数组大小。void test(int brr1[100]) //办法三,也能够将数组大小写得很大,然而不倡议//形参的[]中的数字并没有意义//int brr1[],变量brr1就是int* 类型,理论形参还是个指针,跟上面的指针形参是一样的。//形参写成指针的模式void test(int *p1);指针数组传参int* arr2[10] = {0};test2(arr2); //arr2是二重指针类型int**。void test2(int* brr2[10]);void test2(int* brr2[]);void test2(int** p2); //形参为二重指针二维数组传参int arr3[3][5] = {0};test3(arr3); //arr3是int(*)[5]类型,即一维数组指针类型,传递的是第一行数组的地址void test3(int brr3[3][5]);void test3(int brr3[][5]); //行能够不写,然而列必须写对。void test3(int (*p3)[5]); //留神这个[]的5必须写//形参为指针模式时,类型也要为数组指针类型int(*)[5]test3(&arr); //传递的是整个二维数组的地址,int(*)[3][5]类型,即二维数组指针类型。void test3(int(*p)[3][5]);一重指针传参int arr4[10] = {1,2,3,4,5,6,7,8,9,10};int* p4 = arr; //p4指向 数组首元素1的地址。test(p4);void test(int* ptr); //形参为指针模式,传递一重指针。int arr4[10] = {1,2,3,4,5,6,7,8,9,10};int* p4 = arr; //p4指向 数组首元素1的地址。test(p4);void test(int* ptr); //形参为指针模式,传递一重指针。二重指针传参int a = 10;int* pa = &a;int** ppa = &pa;test5(ppa); //实参为二重指针void test5(int** ptr); //形参也要为二重指针

June 20, 2022 · 1 min · jiezi

关于c:C语言中数据的存储

整数在内存的存储形式符号位用0示意正,1示意负。整数在内存中是以补码的模式保留的(负数的源反补码雷同,正数的源反补码不同)留神:变量类型在读取时会有一个整形晋升的问题 整形晋升在存储变量时是没有的,只在读取时存在例如:char类型的数,输入的用%d整形输入。整形晋升时,有符号类型依据首位进行补位,无符号类型补0。整形晋升后,留神负数的源反补码雷同。int main(){ char b = 229; //存储时:229是负数,源反补码都雷同 //0000 0000 0000 0000 0000 0000 1110 0101 负数首位为0,其余位补0 //b内存中存储的是:1110 0101 //读取时,char类型打印为整型,整型晋升 //%d 示意有符号整形,首位为符号位,1110 0101首位为1,正数 //如果是打印 %u 打印无符号整形,所有位都为数值位,源反补码雷同。 //char类型为有符号类型,依据首位决定补什么 //补码:1111 1111 1111 1111 1111 1111 1110 0101 首位为1,全副补1 //反码:1111 1111 1111 1111 1111 1111 1110 0100 补码减一 //源码:1000 0000 0000 0000 0000 0000 0001 1011 取反//输入的值: -27 printf("%d",b); return 0;}大小端字节序存储以字节为单元进行存储。0x12345678 十六进制位 12是最高位字节的数据,78是最低位字节的数据大端存储: 低位 12 34 56 78 高位 把高位字节数据寄存在低位处小端存储: 低位 78 56 34 12 高位 把低位字节数据寄存在低位处浮点型在内存中的存储留神:浮点数在内存中可能不能准确保留,所以个别不必 == 号进行比拟,个别是用差值,看是否在肯定范畴内。存储浮点数时整数和浮点数在内存中的存储形式是有差别的。依据国内IEEE754的规范:任意二进制浮点数都能够示意成下列模式。浮点数的计数形式:(-1)^S*M*2^E(-1)^S示意符号位,S为0,则为负数;为1,则为正数M示意有效数字的,大于1,小于2 (用二进制示意的)2^E示意指数位。内存中存储的就是S、E、M三个数据(对应32位float类型)[bit0]1bit存储S,[bit1-bit8]8bit存储E,[bit9-bit31]23bit存储M。(对应64位double类型)[bit0]1bit存储S,[bit1-bit11]11bit存储E,[bit9-bit63]52bit存储M。留神:计算机外部保留M时,默认这个数的第一位总是1,所以能够省略,只保留小数点后的位数。 ...

June 19, 2022 · 1 min · jiezi

关于c:字符指针与数组指针

内存中地址调配办法内存中地址调配是以字节为单位的即:每一个字节都有惟一一个地址例如: int a = 0x12345678;//如果a的地址是 0xffff4444//如果是小端存储 低地址 44 44 ff ff 高地址//那么以char类型解援用 0xffff4445 地址的数据,失去的是0x44 。字符指针char* p1 = "abcde";char* p2 = "abcde"; 上述两个变量定义初始化,相当于创立一个字符串常量abcde,而后将这个常量别离赋值给不同的指针,所以两个指针指向同一个地址当定义两个雷同的常量字符串时,因为字符串abcde是常量字符串,不能被更改所以在内存中是不会被创立两份的,只创立一份,两个变量共用。所以,指针p1和指针p2都会指向同一个地址char arr1[] = "abcde";char arr2[] = "abcde";这里是用abcde去初始化两个不同的数组,所以arr1不等于arr2。数组指针int (*p)[10];//定义数组指针留神:* p这里必须打括号,因为[]的优先级高于星号 ,所以必须加上括号保障p先与星号联合。它指向一个大小为10个int型的数组。数组名和&数组int arr[10] = {0};printf("%p\n",arr);printf("%p\n",arr[0]);printf("%p\n",&arr);//三个输入后果雷同//然而arr代表的是数组首元素地址,代表一个int元素的大小,它是int*类型。//&arr代表的是数组的地址,代表整个数组的大小,它是数组指针类型int (*)[10]//它们代表的范畴不同int* a = arr;int (*p)[10] = &arr; p是一个指针,只占4个字节,指向一个数组(指向的是数组而不是数组的首元素)char* arr[5];p = &arr; //指针p的类型为:char* (*p)[5]//(*p)示意p是一个指针//[5]示意指向的是大小为5的数组//char* 示意指向的数组是char*型int* arr[10]; //arr[0] 是int*型,arr是int**型int* (*p)[10] = &arr;//p 是数组指针,指向的是arr整个数组,范畴是整个数组//*p解援用,解进去的是数组首元素的地址,相当于arr(int**类型)//*(*p) 解进去是数组首元素,相当于arr[0] (int*类型)数组指针在二重数组中的利用#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>int print(int(*p)[5]){ for (int i = 0; i < 3; i++) { for (int j = 0; j < 5; j++) { printf("%d ", *(*(p + i) + j)); } printf("\n"); } return 0;}int main(){ int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} }; print(arr); return 0;}

June 19, 2022 · 1 min · jiezi

关于c:C语言的算数转换

算数转换当执行算术运算时,如果操作对象的类型不同,就会产生数据类型转换。转换规则: 朝着精度更高、长度更长的方向转换保无符号规定:当运算符两边别离是signed 有符号类型和unsigned无符号类型时,产生算术转换,将signed有符号类型转换为无符号类型。例如:下列输出后果为 大于#include <stdio.h>int i ; //全局变量未初始化,默认为0int main(){ i--; //i为有符号类型,i = -1 if (i > sizeof(i)) { printf("大于"); } else { printf("小于"); }}在if语句判断时,产生了数据类型的转换 i为-1二进制为1000 0000 0000 0000 0000 0000 0000 0001补码为:1111 1111 1111 1111 1111 1111 1111 1111算数转换,当初零碎认定i为unsigned int型,无符号类型均为负数,源反补码雷同所以当初i的源码也为1111 1111 1111 1111 1111 1111 1111 1111所以在if语句判断这里,i是大于4的(sizeof(i) = 4)留神:i的理论值并没有产生扭转,只是在运算时,解析办法变了。

June 19, 2022 · 1 min · jiezi

关于c:安全目标

通信安全由许多不同的但互相关联的个性形成,这些个性广泛划分为三个次要类别: 保密性音讯完整性端点认证上面咱们挨个解释阐明: 1、保密性在思考齐全时,首先想到的可能就是保密性。保密性的意思就是对无关的人窃密。 举例说明:政府监听你的电话时,就是对你的保密性构成威胁。监听这种伎俩其实是一种被动攻打,如果监听者开始模拟你的声音和对方交换时这就形成主动攻击。个别咱们会通过一些伎俩避免或者扰乱窃听者. 比方:特务走进洗手间关上所有水龙头来扰乱窃听者时,就是需要保密性。2、音讯完整性音讯完整性,根本思维就是咱们要确信本人所收到的音讯就是发送者发送的音讯。 例如: 现代人们通过书信往来信息,尽管笔记很难从信中去除,然而能够减少一些笔记,或者间接找一个笔记模仿者从新写,而后再交给收信方,《水浒传》中就有这样的案例。在古代,通信音讯在网络中传输都是0101的比特位,看上去都很类似,所以在传输过程中摆弄起来音讯就很不便,攻击者去除、拷贝或者随便减少一些数据进去,而后被接收者接管,接收者却齐全不晓得。3、端点认证通过端点认证所要达到的目标其实就是要晓得通信中发送者就是咱们通信的端点。没有端点认证,要提供保密性和音讯完整性就十分艰难。 举例说明:如果咱们收到了一份来自Alice的音讯,但无奈确定该音讯是由Alice而不是攻击者发送的话,那么音讯的完整性对咱们来说毫无意义。当咱们向Bob发送一份机密消息,如果咱们实际上是将机密消息发送给了攻击者的话,对咱们来说就没有什么意义可言了。留神:端点认证能够是非对称的形式提供。当你给

June 16, 2022 · 1 min · jiezi

关于c:盲签名算法的原理与C语言实现

0x01 概述盲签名(Blind Signature) 是由Chaum,David提出的一种数字签名形式,其中音讯的内容在签名之前对签名者是不可见的(盲化)。通过盲签名失去的签名值能够应用原始的非盲音讯应用惯例数字签名验证的形式进行公开验证。盲签名能够无效的爱护隐衷,其中签名者和音讯作者不同,在电子投票系统和数字现金零碎中会被应用。 盲签名经常被类比成上面的场景:Alice想让Bob在本人的文件上签名,然而不心愿Bob看到文件内容,于是Alice在文件上方叠放了一张复写纸,而后将文件和复写纸放入信封密封起来交给Bob。Bob再拿到信封后验证了Alice的身份后,间接在密封好的信封上签字,这样尽管Bob是对密封后的信封签字,然而Alice拿到签名后的信封后,拆开信封就能够拿到通过Bob签字的文件。 0x02 RSA盲签名计划盲签名是一种音讯在签名之前就被盲化解决的数字签名计划,盲签名能够应用很多公钥加密计划来实现。这里只介绍最简略的一种实现,基于RSA加密算法的盲签名计划。假如音讯的持有者Alice心愿对音讯$m$应用盲签名计划进行签名,Bob是签名私钥的控制者,他们两方应该执行以下步骤: Alice抉择一个随机数$k$作为盲化因子Alice对原始的音讯进行计算,$m' = m k^e (mod \ n)$ 并把计算后(盲化)的音讯 $m'$发送给BobBob计算 $s' = (m')^d (mod \ n)$ 并把计算后的签名值 $s'$ 发送给AliceAlice计算 $s = s'k^{-1} (mod \ n)$,$s$ 就是Bob对原始音讯 $m$的数字签名证实: $(m')^d \equiv (m k^e)^d \equiv m^d k \ (mod \ n) $ $(m')^d k^{-1} = (m k^e)^d k^{-1} = m^d k^{e d} k^{-1} = m^d k k^{-1} \equiv m^d$ 0x03 C语言实现因为须要应用大数运算,能够应用你相熟的任何语言实现,也能够用任意成熟的大数运算库实现。这里我应用了mbedTLS的大数运算库。 //首先应用盲化银子blind_factor对原始的音讯m进行盲化,生成盲化音讯blind_messageint blindsignature_hide_message(mbedtls_mpi* m, mbedtls_mpi* blind_factor, mbedtls_mpi* e, mbedtls_mpi* n, mbedtls_mpi* blind_message){ int ret; mbedtls_mpi r; mbedtls_mpi_init(&r); // r = blind_factor ^ e mod n if ((ret = mbedtls_mpi_exp_mod(&r, blind_factor, e, n, NULL) ) != 0) { printf("Hide message: mbedtls_mpi_mod_init failed ret=%8X\r\n", ret); goto EXIT; } // m1 = m * r if ((ret = mbedtls_mpi_mul_mpi(blind_message, m, &r)) != 0) { printf("Hide message: mbedtls_mpi_mul_mpi failed ret=%08X\r\n", ret); goto EXIT; } // blind_message = m1 mod n if ((ret = mbedtls_mpi_mod_mpi(blind_message, blind_message, n)) != 0) { printf("Hide message: mbedtls_mpi_mod_mpi failed ret=%08X\r\n", ret); goto EXIT; }EXIT: mbedtls_mpi_free(&r); return 0;}//对盲化的音讯进行盲签名,过程同一般rsa签名一样int blindsignature_sign(mbedtls_mpi* blind_message, mbedtls_mpi* d, mbedtls_mpi* n, mbedtls_mpi* s){ int ret; mbedtls_mpi r; //s = m ^d mod n if ((ret = mbedtls_mpi_exp_mod(s, blind_message, d, n, NULL)) != 0) { printf("Blind signature: mbedtls_mpi_exp_mod failed ret=%08X\r\n", ret); goto EXIT; }EXIT: return 0;}//对签名后果blind_signature,应用blind_factor去盲化,失去签名值signatureint blindsignature_unblind_sign(mbedtls_mpi* blind_signature, mbedtls_mpi* blind_factor, mbedtls_mpi* n, mbedtls_mpi* signature){ int ret; mbedtls_mpi inv_blind_factor; mbedtls_mpi_init(&inv_blind_factor); if ((ret = mbedtls_mpi_inv_mod(&inv_blind_factor, blind_factor, n)) != 0) { printf("Unblind signature: mbedtls_mpi_inv_mod failed ret=%08X\r\n", ret); goto EXIT; } if ((ret = mbedtls_mpi_mul_mpi(signature, &inv_blind_factor, blind_signature)) != 0) { printf("Unblind signature: mbedtls_mpi_mul_mpi failed ret=%08X\r\n", ret); goto EXIT; } if ((ret = mbedtls_mpi_mod_mpi(signature, signature, n)) != 0) { printf("Unblind signature: mbedtls_mpi_mod_mpi failed ret=%08X\r\n", ret); goto EXIT; }EXIT: mbedtls_mpi_free(&inv_blind_factor); return 0;}0x04 总结RSA盲签名的代码、调用示例程序都曾经上传,能够间接检出测试,没有认真测试验证可能有各种问题,如果遇到问题,能够给我提issues。 ...

June 15, 2022 · 2 min · jiezi

关于c:CPT109-C-语言应用

CPT109 C Programming and Software Engineering 1 – ASSESSMENT 2Assessment Number 2Contribution to Overall Marks 50%Issue Date 08/11/2021Submission Deadline 06/12/2021 at 00:01Assessment OverviewThis assessment aims to test your ability to design a modular program which makes use offiles and structures. Application of the software development process (SDP) is also underassessment; the five steps required for your SDP report are: Problem specification: formulate the problem.Analysis: determine the inputs, outputs, variables, etcAlgorithm Design: define the list of steps (the algorithm) needed to solve the problem.Implementation: the C code has to be submitted as a separate file (.c).Just indicate here the name of the file. DO NOT paste your code into your report.Testing: explain how you have tested and verified your C program.Things to note:Submit only what is required.Include clear comments in your code to make it easy to understand.Use the C90 standard.ALL programs MUST compile and run in Visual Studio 2013.ExerciseThe game of hangman is a popular children’s word guessing game aimed at improvingspelling and general knowledge. A secret word is chosen (usually related to a chosen topice.g. a country or a fruit or vegetable) and the player tries to work out what the word is byguessing letters. Each time a player correctly guesses a letter in the word, then the lettersshould be filled in at their appropriate location in the word (see below). Note that the letterscan be guessed in any order. If the player guesses a letter incorrectly, then the hangman’sgallows (See Figure 1a) are constructed one line at a time for each wrong letter till the playerdies after 8 wrong guesses. A possible text-based version of the hangman’s gallows is shownin Figure 1b. Example game:Secret word entered by player 1 is: GuangzhouDisplayed on the screen is: Player 2 guesses: GDisplayed on the screen is: Figure 1a Hangman Picture Figure 1b Possible text-based drawingThe secret word should be either entered by a second user or randomly selected by theprogram from a file of words provided. Program users should create a unique passwordprotected account which will record their win/lose record, and which can be viewed.Program Requirements Allow users to create an account by selecting a username and password. The accountshould be saved in a file (unique to each user), which will contain a structure with thepassword and the win/lose history. Once a user is logged in they should be able to:Start a new gameReview their game historyClear their game historyLogout On starting a new game, there should be a choice either to play with a random secretword chosen from a data file (the filename should be provided) or for another user toenter a secret word. The player should guess letter one at a time. After each guess either the appropriate blankor blanks of the secret word are filled, or the next section of the picture is included, andboth the current word state and the current hangman picture are displayed. If the player completes the word before the hangman picture is complete, they win, if thepicture is complete first then they lose. All variables used must be local.Programming Suggestions/IdeasThe following points are only to provide you with ideas of how to implement the requiredfunctionality. They do not represent the “best” or only ways to implement the functions. All player accounts are structure variables and will be stored in a unique file i.e. one filefor each player account. Create new accounts by creating a new file with the usernameselected. The login process can be achieved by trying to open a file, if successful thestructure stored in the file can be copied into the program memory. When the player logsout only this one structure needs to be written back to the file. Try to create your own functions to simplify the programming task, for example use onefunction to draw the hangman picture. Consider how your program should function when there is an invalid input. You can design your own figure (it is your interpretation of the game). Consider the playability, how can you make the user interaction more interesting forexample add your own rule such as do not allow vowel letters (a, e, i, o ,u), or maybeonly 1 vowel letter is allowed. You may wish to display a list of the wrongly guessedletters as a reminder to the playerSubmissionYour assessment should be submitted electronically through the Learning Mall Online(LMO). Feedback and your grade will also be given through LMO.Software Development Process (SDP) report (5 steps) named: studentID_A2.pdfSourcecode (.c) file named: studentID_A2_1.cData file: data.txtThis is the file containing the words to be used when playing the game against the computerSubmission should be a single compressed file containing at least 3 files:1234567_A2_1.c1234567_A2.pdfdata.txt1234567_A2.zipCompressed folder can be of type .zip, .rar or .7zIf you have multiple program files please use the following naming convention: Sourcecode files (.c) you should number these accordingly e.g. 1234567_A2_2.c. Header files (.h (and associated .c file), name these: 1234657_A2_H1.h(1234567_A2_H1.c) if there are more than one number them accordingly (i.e. H1, H2..).MarkingOverall Report Quality 10%Problem Specification 10%Analysis 10%Algorithm Design 10%Implementation 40%Robustness 10%Testing 10%Please refer to the file “CPT109 Marking Guidelines for Assignment 2” on LearningMall for details on marking descriptions.You are responsible for ensuring that your C code will run in Visual Studio 2013. If it doesnot without documentary explanation you may get a 0 mark for your implementation.There will be a 5% deduction for incorrectly named files in your submission.Important notes:University late submission policy will be applied.University Academic Integrity policy will be applied rigorously. Plagiarism and collusionwill not be tolerated.You can find information relating to both of these in ebridge. ...

June 1, 2022 · 5 min · jiezi

关于c:CC-单元自动化测试解决方案实践

vivo 互联网服务器团队 - Li QingxinC/C++ 开发效率始终被业内开发人员诟病,单元测试开发效率也是如此,以至于开发人员不愿花工夫来写单元测试。那么咱们是不是能够通过改善编写单元测试的效率来晋升我的项目的测试用例覆盖率? 本文次要介绍如何利用GCC插件来实现晋升C/C++开发者的单元效率工具解决方案,心愿对大家在晋升单元测试效率上有所启发。 一、动机 上图展现了C/C++单元测试的根本流程,在日常开发过程中写单元测试是一项比拟大工程量的事件,C/C++ 目前单元测试代码都须要本人手动写,而且对于一些公有办法打桩就更加麻烦。 目前业内无开源的自动化测试框架或者工具,倒是有一些商业的主动测试工具,下图展现了咱们自动化测试工具及单元测试库: 即便开源界有gtest等测试库的反对,咱们依然须要编写大量的单元测试用例代码。对于一些private、protected的类办法,编写单元测试用例的效率就更低,须要手动打桩(mock)。同时咱们剖析测试用例发现,存在很多边界的用例,它们基本上都是很固定或者有肯定模式,比方int 最大最小值等。 如何改善编写单元测试的效率,晋升C/C++同学开发效率以及程序品质?咱们能够通过提取源文件中的函数、类等信息,而后生成对应的单元测试用例。主动生成用例时须要依赖函数的申明、类的申明等信息,那么咱们应该如何获取这些信息呢? 例如:如下的函数定义: void test(int arg) {}咱们心愿可能从下面的函数定义中失去函数的返回值类型、函数名称、函数参数类型、函数作用域。通常咱们能够通过以下几种形式失去: 1.1 办法1:应用正则表达式无奈C/C++ 格局比较复杂可能尽管可能应用多种组合来获取对应的函数申明等信息: void test(int arg){}void test1(template<template<string>> arg,...){}void test2(int(*func)(int ,float,...),template<template<string>> arg2){}那么就须要写一系列的正则表达式: 提取函数名称、参数名:[z-aA-Z_][0-9]+提取函数返回值:^[a-zA-Z_]关键词提取进去了,然而他有一个很大的问题:怎么判断文件中书写的代码是合乎C/C++语法形容呢? 1.2 办法2:应用flex/bison 剖析c/c++源码文件这当然是一种很好的形式,然而工作量微小,相当于实现一个具备词法、语法分析器繁难版本的编译器,而且要适配不同的语法格局,尽管bison能够解决上述的如何判断语法是否正确问题,然而依然很简单。 1.3 办法3:利用编译曾经生成的AST 来生成代码通常咱们理解到的GCC编译的过程是以下四个阶段: 源文件->预处理->编译->汇编→链接但实际上GCC为了反对更多的编程语言、不同的CPU架构做了很多的优化,如下图所示: 上图展现了GCC解决源码及其他优化过程,在前端局部生成的Generic 语言是gcc编译过程中为源码生成的一种与源码语言无关的形象语法表现形式(AST)。既然GCC编译过程中生成了AST树,那么咱们能够通过GCC插件来提取GCC 前端生成的形象语法树要害信息比方函数返回值、函数名称、参数类型等。总体难度也很高,一方面业内可参考资料很少,只能通过剖析GCC的源码来剖析AST语法树上的各个节点形容。 本文所形容的自动化生成单元测试用例的解决方案(咱们称之为TU:Translate Unit,后文统称为TU)就是基于办法3来实现的,上面咱们先来看看咱们的自动化测试用例解决方案的成果展现。 二、成果展现2.1 业务代码零批改, 间接应用TU生成边界用例 在该用例中咱们不须要批改任何业务代码就可能为业务代码生成边界测试用例,而且函数参数可边界值实现全排列,大大降低用例脱漏危险。大家可能发现这种没有做任何批改生成的用例是没有断言的,尽管没有断言,它依然可能帮忙发现单元是否会存在边界值引起coredump。 那么如果想要给他加上断言、mock函数,是否没有方法呢?通过C++11 [[]] 新的属性语法,只须要在办法申明或者定义时增加下依据TU的格局增加断言即可,对业务逻辑无侵入。 2.2 应用注解tu::case生成用户自定义用例很多状况下默认生成的边界测试用例还不能笼罩到外围逻辑,所以咱们也提供tu::case 来给用户自定义本人的测试用例及断言。比方有一个int foo (int x,long y) 办法,当初想新增一个测试用例返回值123,函数实参1,1000,那么只有在函数申明前退出,以下代码即可: [[tu::case("NE","123","1","1000")]] 2.3 应用注解tu::mock 主动生成mock办法开发过程中咱们也常须要对某个办法进行mock(即对原有办法设置一个长期代替办法并且调用形式保持一致),比方某个函数拜访Redis、DB这种状况下进行单元测试往往须要对这些办法进行mock,不便其余函数调用进行单元测试,为了不便进行单元测试咱们往往会对其进行mock,所以为了不便开发人员进行疾速的mock,所以咱们提供了tu::mock 的注解帮忙开发同学疾速的定义注解,而后TU会主动生成对应的mock函数。例如:当初给foo_read 办法mock一个函数,让mock的函数返回10: 三、TU实现计划3.1 AST 是什么?GENERIC、GIMPLE和RTL三者形成了gcc两头语言的全副,它们以GIMPLE为外围,由GENERIC承上,由RTL启下,在源文件和指标指令之间的鸿沟之上构建了一个三层的过渡。 ...

May 31, 2022 · 1 min · jiezi

关于c:Redis源码解读跳跃表

Redis 中的跳跃表构造 每个节点都有各自的分层,后退节点,后退节点,键以及分值。 后退节点即用来从跳跃表尾部从后向前遍历。后退节点有两局部:后退指针,以及后退的步长。这个步长能够用来计算排位,比方在查找某个节点过程中,将两头的跨度加起来,就能够失去它在跳跃表中的排位。跳跃表节点定义: typedef struct zskiplistNode { sds ele; double score; struct zskiplistNode *backward; // 后退节点 struct zskiplistLevel { struct zskiplistNode *forward; // 后退节点 unsigned long span; } level[];} zskiplistNode;跳跃表节点外部有一个对于层数的柔性数组,代替了传统的 up、down 指针。 跳跃表定义: typedef struct zskiplist { struct zskiplistNode *header, *tail; // 首尾节点 unsigned long length; // 元素个数 int level; // 层高} zskiplist;咱们再察看下面的 head 节点,head 节点不存放数据,并且层高固定为 32 层,32 层曾经满足对于 2 ^ 64 个元素查找的效率了,所以跳跃表最高也就是 32 层。 创立、开释跳跃表创立跳跃表节点创立一个指定层数的跳跃表节点,sds 字符串 ele 将会被该节点援用。sds 字符串即是跳跃表节点的键 ...

May 29, 2022 · 6 min · jiezi

关于c:error-conflicting-types-for-xxx-in-c

一、问题形容#include <stdio.h>#define MAXLINE 1000/* maximum input line length */int getline(char lines[], int maxline);void copy(char to[], char from[]);int main(void){ int len; // current line length int max; // maximum lenght seen so far char line[MAXLINE]; // current input line char longest[MAXLINE]; // longest line max = 0; while ((len = getline(line, MAXLINE)) > 0) if ( len > max) { max = len; copy(longest, line); } if (max > 0) printf("%s", longest); return 0}int getline(char s[], int lim){ int c, i; for(i = 0; i < lim -1 && (c = getchar()) != EOF && C != '\n'; ++i) s[i] += c; if (c == '\n') { s[i] = c; ++i; } return i;}void copy(char to[], char from[]){ int i; i = 0; while ((to[i] = from[i]) != '\0') ++i;}运行以上代码的时候呈现谬误提醒:error: conflicting types for 'getline'; have 'int(char *, int)'。代码来源于《C Programming Language》。 ...

May 28, 2022 · 2 min · jiezi

关于c:C程序设计-07-函数

若程序性能较多,规模较大,将所有的程序写在一个 main 主函数中,会使得主函数庞杂,浏览和保护艰难大。于是提出模块化程序设计: 在设计一个较大的程序时,往往将它分为若干个程序模块,每个模块包含一个或多个函数(function),每个函数实现一个特定的性能。一个 C 程序可由一个 main 函数和若干个其余函数形成,程序的执行是从 main 函数开始的。函数间能够互相调用,但其余函数不能调用 mian 函数,一个函数能够被一个或多个函数调用屡次。所有函数都是平行的、互相独立的,函数不能嵌套定义。从用户应用的角度看,函数分为:库函数和用户自定义的函数。 从函数模式上看,函数分为:无参函数和有参函数。 一、定义函数C 语言要求程序中所有用到的函数,必须先定义后应用。定义函数应包含以下几个内容: 函数的名字。函数的类型,即函数返回值的类型。函数的参数名和参数类型(无参数函数不须要)。函数的性能。对于 C 编译系统提供的库函数,是由编译系统当时定义好的,只需应用 #include 指令引入到程序文件中即可应用。 1. 定义无参函数定义无参函数的个别模式有两种: // 模式1类型名 函数名(){ 函数体}// 模式2类型名 函数名(void){ 函数体}模式 2 中括号内 void 示意“空”,即函数没有参数。 定义函数时,如果函数无类型,即无函数值,能够应用 void 代替类型名。这时,执行函数后,不会把任何值带回 main 函数中。 2. 定义有参函数定义有参函数的办法为: 类型名 函数名(形式参数表列){ 函数体}例如,定义一个求两个数中最大值的函数: int max(int x, int y){ int z; z = x > y ? x : y; return(z);}数组元素的作用与变量相当,因而,数组元素也能够作为函数实参,其用法与变量雷同。此外,数组名也能够作为实参和形参。形参数组能够不指定数组大小(高维数组只能疏忽第一维)。 float average(float array[], int n){ float aver, sum = array[0]; int i; for(i = 1; i < n; i++) sum = sum + array[i]; aver = sum / n; return aver;}须要留神,应用数组名作为函数实参时,不是吧数组元素的值传递给形参,传递的是数组的第一个元素的地址,这样两个数组就占用同一段内存单元,当形参数组中各元素值发生变化,实参数组元素值也会发生变化。这与变量作函数参数的状况不同。 ...

May 16, 2022 · 3 min · jiezi

关于c:Redis源码解读字典

[toc] 四个数据结构dictEntrydictEntry 的构造如下(Redis 7.0): typedef struct dictEntry { void *key; // 键 union { void *val; uint64_t u64; int64_t s64; double d; } v; // 值 struct dictEntry *next; /* Next entry in the same hash bucket.即下一个节点 */ void *metadata[]; /* An arbitrary number of bytes (starting at a * pointer-aligned address) of size as returned * by dictType's dictEntryMetadataBytes(). */} dictEntry;能够比照 《Redis 设计与实现》中的 dictEntry 构造,发现联合结构 v 中多了一个 double 的浮点数示意,metadata 是一块任意长度的数据,具体的长度由 dictType 中的 dictEntryMetadataBytes() 返回,作用相当于 privdata ...

May 16, 2022 · 11 min · jiezi

关于c:基于QT5的文件读取程序的实现

目录一、文件读写操作QFile1.1 头文件1.2 外部函数二、UI设计三、代码3.1 mainwindow.h3.2 mainwindow.c四、成果 一、文件读写操作QFileQT自带了一个文件操作的类->QFile ,试验中也是着重 QFile 的操作 1.1 头文件#include<QFile>1.2 外部函数这些函数没必要都去记住,咱们只须要记住简略的例如open()、readLine()、atEnd()、close() 等罕用的函数即可 首先咱们new 一个 QFile 对象的时候有四种构造方法,通常来说咱们传入 文件的路径名 就好了而后咱们要调用open()函数,这个函数是通知操作系统咱们通过什么样的形式关上,例如只读关上、只写关上、可读可写关上……,这个和咱们在C语言中的文件关上函数是相似的,咱们在QIODevice看到一个枚举类型的 OpenModeFlag打开方式 enum OpenModeFlag { NotOpen = 0x0000, ReadOnly = 0x0001, WriteOnly = 0x0002, ReadWrite = ReadOnly | WriteOnly, Append = 0x0004, Truncate = 0x0008, Text = 0x0010, Unbuffered = 0x0020, NewOnly = 0x0040, ExistingOnly = 0x0080 };这些就是文件关上的一些模式了,能够依据本人的需要选用,咱们这里既然是文件的读取显示操作,那么只须要读取,于是咱们的打开方式就是:QIODevice::ReadOnly 而后就是对这个文件从头到尾读取,在以前咱们学的C语言中有一个文件完结标记EOF,个别这个EOF是 − 1 -1 −1 然而这里的QFile 提供了一个函数atEnd()如果当咱们读到了文件开端,那么就会返回一个true 例如: QFile file("in.txt");if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return; while (!file.atEnd()) { QByteArray line = file.readLine(); process_line(line);}最初咱们通过file.close()敞开数据流就好了 ...

May 15, 2022 · 2 min · jiezi

关于c:C程序设计-06-数组

为了无效解决大批量数据,引入数组(array): 数组是一组有序数据的汇合。数组中各数据的排列是有法则的,下标(subscript)代表数据在数组中的序号。用一个数组名和下标来惟一确定数组中的元素。数组中的每一个元素都属于同一数据类型。不同数据类型的数据不能放入同一个数组。一、一维数组一维数组是数组中最简略的,只需用一个下标就能惟一确定其中的元素。 1. 定义一维数组定义一维数组的个别模式为: 类型说明符 数组名[常量表达式];阐明: 数组定义时须要指定数组中元素的个数,方括号中的常量表达式用来示意元素的个数,即数组的长度。常量表达式能够蕴含常量和符号常量,但不能时变量,C 语言不容许对数组的长度作动静定义。2. 一维数组的初始化在定义数组的同时能够给数组中的元素赋值,称为数组的初始化。 定义数组时对全副元素初始化:int a[5] = {1, 2, 3, 4, 5};只给一部分元素初始化:int a[5] = {1, 2, 3};花括号内只提供了 3 个初始值,示意给前三个元素赋值,零碎主动为前面两个元素赋值为 0。 若对数组初始化时提供的数据个数与数组长度雷同,能够不指定数组长度:int a[] = {1, 2, 3, 4, 5};定义数组时未被初始化的数组,如果是整数型数组,零碎主动将其初始化为 0;如果是字符型数组,初始化为\0;如果是指针型数组,初始化为NULL,即空指针。 3. 援用一维数组应用数组名和下标援用数组中的元素: 数组名[下标];留神:下标是从 0 开始的,只能援用数组元素而不能一次整体调用整个数组全副元素的值。 #include <stdio.h>int main(){ int a[5], i, j, t; for (i = 0; i < 5; i++) scanf("%d", &a[i]); for (i = 0; i < 5; i++) { for (j = 0; j < 5 - i; j++) { if (a[j] > a[j + 1]) { t = a[j]; a[j] = a[j + 1]; a[j + 1] = t; } } } for (i = 0; i < 5; i++) printf("%d\t", a[i]); return 0;}二、二维数组二维数组常称为矩阵(matrix),能够将其直观写成行(row)和列(column)的排列模式。 ...

May 13, 2022 · 2 min · jiezi

关于c:C程序设计-05-循环语句

一、while语句while语句个别模式为: while (表达式) 语句其中表达式为循环条件,语句为循环体。while的特点为:先判断循环条件,后执行循环体。 #include <stdio.h>int main(){ int n, result = 1; scanf("%d", &n); while (n > 1) { result = result * n; n--; } printf("%d", result); return 0;}二、do...while语句do...while语句的个别模式为: do 语句while (表达式)该语句的特点是:先执行循环体,后判断循环条件。 #include <stdio.h>int main(){ int n, result = 1; scanf("%d", &n); do { result = result * n; n--; } while (n > 0); printf("%d", result); return 0;}三、for语句相比while语句和do...while...语句,for语句更加灵便,不仅能够用于循环次数曾经确定的状况,也能够用于循环次数不确定而只给出了循环完结条件的状况。其个别模式为: for (表达式1; 表达式2; 表达式3) 语句其中三个表达式的作用顺次为: 表达式1:设置初始条件,只执行一次,能够为多个变量设置初始值,可省略。表达式2:循环条件,可省略。表达式3:循环的调整,执行完循环体后才执行,可省略。#include <stdio.h>int main(){ int n, result = 1; scanf("%d", &n); for (; n > 0; n--) result = result * n; printf("%d", result); return 0;}C99 规范容许在表达式1中定义变量并初赋值,但定义变量的作用域仅限于for循环内,在循环外不可调用该变量。 ...

May 13, 2022 · 1 min · jiezi

关于c:C程序设计-04-选择语句

C 语言有两种抉择语句: if语句:实现两个分支的抉择构造。switch语句:实现多分支的抉择构造。一、if抉择语句if语句的个别模式: if (表达式) 语句1 [else 语句2]表达式能够是关系表达式、逻辑表达式、数值表达式。if语句能够嵌套: if (表达式) 语句1else if (表达式2) 语句2else if (表达式3) 语句3...else 语句nif语句无论写成几行都是一个整体,属于一个语句。else局部是另一个语句。else语句是可选的,但不能独自应用,必须和if语句配套应用。 二、关系运算符和关系表达式C 语言中用来比拟两个数据的符号称为关系运算符,共 6 个: 优先级较高:< <= > >=优先级较低:== !=关系运算符的优先级低于算数运算符、高于赋值运算符。关系表达式是用关系运算符将两个数值或数值表达式连接起来的式子,如a+b>c。关系表达式的值是一个逻辑值,即“真”或“假”。C 语言中,用“1”示意“真”,用“2”示意“假”。 三、逻辑运算符与逻辑表达式C 语言中有三种逻辑运算符: &&:逻辑与 AND,双目运算符(要求有两个运算对象)\:逻辑或 OR,双目运算符!:逻辑非 NOT,单目运算符(只有一个运算对象)逻辑运算符的优先秩序为: !最高,&&次之,||最小。&&和||低于关系运算符,!高于算术运算符。用逻辑运算符将关系表达式或其余逻辑量连接起来的式子就是逻辑表达式。 四、条件运算符和条件表达式条件运算符由两个符号?和:形成,须要三个操作对象,是 C 语言中惟一的三目运算符。条件表达式的个别模式为: 表达式1 ? 表达式2 : 表达式3其执行过程为:若表达式1为真,则取表达式2的值;否则取表达式3的值。表达式2和表达式3能够是数值表达式、赋值表达式、函数表达式。条件运算符的优先级大于赋值运算符。 五、switch抉择语句if语句只有两个分支可选,多分支抉择应用if语句的嵌套时,程序简短、可读性低。C 语言提供switch语句实现多分支抉择。 switch(表达式){ case 常量1: 语句1 case 常量2: 语句2 ...... case 常量n: 语句n default: 语句n+1}阐明: 其中的表达式值必须是整数类型(包含字符型)。如果表达式的值与case标签中的常量相等,则执行对应的语句;若没有与表达式绝对应的case值,则执行default语句。default语句为可选语句。case语句的程序不影响执行后果,每一个case常量必须互不雷同。若表达式的值与每一个case匹配,则执行完该case前面的语句后,不再进行判断,从此case标签开始执行上面的所有语句。因而通常在case前面加break语句跳出switch。#include <stdio.h>int main(){ char c = getchar(); switch (c) { case 'a': case 'A': printf("A\n"); break; case 'b': case 'B': printf("B\n"); break; } return 0;}Reference: ...

May 13, 2022 · 1 min · jiezi

关于c:C程序设计-03-输入输出

一、C 语句1. C 语句分类C 语句分为以下 5 类: 管制语句 条件语句:if()...else...循环语句:for()...循环语句:while()...循环语句:do...while()完结本次循环语句:continue终止执行 switch 或循环语句:break多分支抉择语句:switch从函数返回语句:return转向语句(结构化程序中根本不必):goto函数调用语句表达式语句:如赋值表达式。空语句:只有一个分号,作为流程的转折点或循环语句的循环体。复合语句:用 {} 把一些语句括起来。2. 赋值语句复合赋值运算a += 3; // a = a+3;x *= y+8; // x = x*(y+8);应用复合赋值运算符,一是能够简化精炼程序,二是能够进步编译效率,生成品质较高的指标代码。 赋值过程中的类型转换浮点型赋值给整型:舍弃小数局部。整型赋值给单、双精度浮点型:数值不变。双精度浮点型赋值给单精度浮点型:只取 6~7 位有效数字,当双精度数值大小超过单精度数值范畴时会出错。占字节多的整型赋值给占字节少的整型或字符型:只会将其低字节局部赋值给新变量,产生失真。失真不属于语法错误,编译系统不会提醒,要留神防止!!!赋值语句与赋值表达式$$赋值语句 = 赋值表达式 + 分号\ ;$$ 赋值表达式时 C 语言的特点之一,区别于其余语言。一个表达式能够蕴含在其余表达式中,赋值表达式也不例外: if((b=a)>0) c=b;// 相当于先把 a 赋值给 b,再判断 b 是否大于 0二、数据的输入输出1. 输入输出基本概念所谓输入输出是以计算机的主机为主体而言的。C 语言自身不提供输入输出函数,这样做能够使编译系统简化、通用性强、可移植性好。C 语言函数库提供一批规范的输入输出函数,以规范的输入输出设施(个别为终端设备)为输入输出对象: putchar输入字符getchar输出字符printf格局输入scanf格局输出puts输入字符串gets输出字符串要在程序文件结尾用预处理指令# include引入无关头文件。# include指令还有一种模式: #include "studio.h"这两种预处理指令的区别是: 应用尖括号时,编译系统从寄存 C 编译系统的子目录中去找要蕴含的文件,称为规范形式。应用双引号时,编译系统当初用户的当前目录中寻找要蕴含的文件,若找不到,再按规范形式找。双引号内能够是文件的具体门路。为提高效率,应用零碎库函数时尽量应用规范形式。2. printf输出函数printf是格式化输入函数,用来向终端(或零碎隐含指定的输出设备)输入若干个任意类型的数据。其个别格局为: printf(格局管制, 输出表列);输出表列是须要输入的数据,能够是常量、变量或表达式。格局管制是用双引号括起来的字符串,称为格局管制字符串或格局字符串,包含两局部信息: 格局申明:由%和格局字符组成,作用是将输入的数据转换为指定格局。一般字符:须要在输入时原样输入的字符。格局字符包含: 格局字符含意d输入有符号的十进制数ld输入长整型lld输入双长整型c输入一个字符s输入字符串f输入实数(单精度、双精度、长双精度)e或E以指数模式输入实数u输入无符号(unsigned)型十进制数g或G以f或e格局中较短的一个格局输入浮点数o按八进制模式输入整数x或X按十六进制模式输入整数局部格局字符应用时能够在格局申明中指定输入数据的域宽,即所占的列数。原输入内容长度小于域宽时,默认在左侧加空格。如: %5d输入数据占 5 列。%m.nf输入数据占 m 列,其中小数为 n 列。原输入数据过长时采取四舍五入的办法解决。党 n 为 0 时,不输入小数和小数点。%-m.nf与%m.nf作用类似,但数据长度小于 m 时,数据向左靠,右端补空格。尽管输入数据的域宽能够管制,但要留神数据的有效性。float型数据只能保障 6 位有效数字,double为 15 位。并不是能输入的数据都是准确的。 ...

May 13, 2022 · 1 min · jiezi

关于c:C程序设计-02-数据类型

一、常量与变量1. 常量整形常量实型常量 十进制小数模式指数模式:\(12.34e3\)(代表\(12.34\times 10^3\))字符常量 一般字符:用单引号示意,单引号里只能有一个字符。字符变量以 ASCII 代码的模式贮存转义字符 转义字符字符值输入后果\\a正告 alert产生视觉或声音信号\\b退格 backspace将光标以后地位后退一个字符\\f换页 form feed将光标地位移到下一页结尾\\n换行将光标地位移到下一行结尾\\r回车 carriage return将光标地位移到本行结尾\\t程度制表符将光标地位移到下一个 Tab 地位\\v垂直制表符将光标地位移到下一个垂直制表符对齐点\\o或 \\oo或 \\ooo(其中o代表一个八进制数字)与该八进制码对应的 ASCII 字符 \\xh[h...](其中 h代表一个十六进制数字)与该十六进制码对应的 ASCII 字符 字符串:用双引号示意符号变量:用 #define 指令,指定用一个符号代表一个常量 #define PI 3.1416符号常量不是变量!符号常量不占用内存,只是作为一个长期符号,代表一个值,在预编译后这个符号就不存在了,一次不能对符号变量从新赋值。为与变量名区别,习惯上符号常量用大写字母示意。 2. 变量变量必须先定义后应用。变量名理论是以一个名字代表的存储地址。编译时,零碎给每一个变量名调配对应的内存地址。从表变量中取值,实际上是通过变量名找到对应的内存地址,从该存储单元中读取数据。 3. 常变量C99 规范容许应用常变量,办法是定义变量时在后面加一个 const,该变量存在期间其值不能扭转。 常变量与常量: 常变量具备变量的根本属性:有类型,占存储单元,只是不容许扭转值。常变量是有名字的不变量,常量是无名字的不变量。常变量与符号变量: 符号变量是预编译指令,它只是用符号常量代表一个字符串,在预编译时仅进行字符替换,编译后符号常量就不存在了(被值代替),符号常量的名字不调配存储单元。串并联占用存储单元,有变量值,只是不能扭转。从应用上看,常变量具备符号变量的长处,而且应用更不便,有常变量时能够不应用符号常量。但有些编译系统还未实现 C99 的性能,不能应用常变量。4. 标识符用来对常量名、函数、数组、类型等命名的无效字符序列统称为标识符(identifier)。标识符就是一个对象的名字。 C 语言规定标识符只能由字母、下划线、数字组成,且第一个字符必须为字母。大小写字母是两个不同的字符。习惯上变量名应用小写字母。 二、数据类型类型是指对数据调配存储单元的安顿,包含存储单元的长度(占多少字节)一级数据的存储形式。不同的类型调配不同的长度和贮存模式。计算机进行的计算不是形象的理论值的计算,而是用工程的办法实现的计算,在许多状况下只能失去近似的后果。C99 容许应用的类型包含:根本类型和枚举类型的变量都是数值,统称为算术类型(arithmetic type)。算术类型和指针类型的变量都是用数字来示意的,统称为纯量类型(scalar type)。枚举类型是程序中用户自定义的整数类型。数组类型和构造体类型统称为组合类型(aggregate type)。共用体类型不属于组合类型,因为在同一时间内只有一个成员具备值。 1. 整形C 规范没有规定各种类型数据占用的存储单元长度,这是由编译系统自行决定的。如 Turbo C 2.0 为每个 int 调配 2 个字节(16 个二进位),而 Visual C++ 调配 4 个字节(32 个二进位)。C 规范只要求 long 型数据长度不短于 int 型,short 型不长于 int 型,long long 型最长。能够应用 sizeof(int) 来查看类型或变量的长度。将一个程序移植到另一个零碎时,要留神因为编译系统的不同引起的数据溢出。存储单元存储整数的办法是:应用整数的补码(complement)。 ...

May 13, 2022 · 2 min · jiezi

关于c:Linux网络开发必学教程18网络通讯框架的完善

问题:如何扩大之前的通信框架,使其反对 UDP 通信,进而成为一个欠缺的网络通讯框架?UDP 通信扩大 UDP 通信实体概要设计每个 UDP Point 位置对等(因为不用被动发动连贯),可通过 ip 地址和 port 号进行通信UDP Point 数据收发单位为: Message 或 Byte在承受口设计上,与 TcpClient 保持一致(框架接口一致性)指标:封装原生 socket 细节,关注 UDP 通信逻辑 UDP 通信实体接口设计typedef void UdpPoint;UdpPoint *UdpPoint_New(int port);UdpPoint *UdpPoint_From(int fd);void UdpPoint_Del(UdpPoint *point);int UdpPoint_SendMsg(UdpPoint *point, Message *msg, const char *remote, int port);int UdpPoint_SendRaw(UdpPoint *point, const char *buf, int length, const char *remote, int port);Message *UdpPoint_RecvMsg(UdpPoint *point, char *remote, int *port);int UdpPoint_RecvRaw((UdpPoint *point, const char *buf, int length, char *remote, int *port);int UdpPoint_Available(UdpPoint *point);void UdpPoint_SetData(UdpPoint *point, void *data);void *UdpPoint_GetData(UdpPoint *point);int UdpPoint_SetOpt(UdpPoint *point, int levle, int optname, const void *optval, unsigned int optlen);int UdpPoint_GetOpt(UdpPoint *point, int levle, int optname, void *optval, unsigned int *optlen);要害代码实现因为 UDP 是以数据报形式进行通信(非数据流形式,报文间有显著边界)因而,不能间接通过 MParser_ReadFd(...) 解析出音讯必须先将报文残缺接管到内存中,再进行从内存中解析出音讯即通过 MParser_ReadMeme(...) 间接实现音讯解析对于上述的补充UDP 套接字的收发报文要用 sendto 和 recvfrom(能够类比 TCP 套接字的 connect 和 accept),参数外面会标识要发往的对端,或者要接管的对端的 IP 地址和端口; ...

May 12, 2022 · 5 min · jiezi

关于c:浙大版C语言程序设计第四版何钦铭颜晖-第12章-文件-课后习题答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 一、选择题 1.以下语句的输入后果是( )。 printf("%d,%d,%d", NULL, '\0', EOF);A.0,0,1 B.0,0,-1 C. NULL, ,EOF D. 1,0, EOF 答:B 解析: NULL等于0'\0'也是等于0EOF等于-1 2.缓冲文件系统的文件缓冲区位于( )。 A.磁盘缓冲区中 B.磁盘文件中 C.内存数据区中 D.程序文件中 答:C 解析: 文件缓冲区是用以临时寄存读写期间的文件数据而在内存区预留的肯定空间 3.定义 FILE *fp; 则文件指针 fp 指向的是( )。 A.文件在磁盘上的读写地位 B.文件在缓冲区上的读写地位 C.整个磁盘文件 D.文件类型构造 答:D 解析: 语句 FILE *fp; ,定义了一个 FILE 构造指针, FILE 是 C 语言为了具体实现对文件的操作而定义的一个蕴含文件操作相干信息的构造类型。 4.若以 “a+” 形式关上一个已存在的文件, 则以下叙述正确的是( )。 A.文件关上时,原有文件内容不被删除,地位指针移到文件开端,可执行增加和读操作 B. 文件关上时,原有文件内容不被删除,地位指针移到文件结尾,可执行重写和读操作 C.文件关上时,原有文件内容被删除,只可执行写操作 D.以上各种说法都不正确 答:A 解析: "a+" 的关上模式,关上文本文件进行读/写/追加。 5.以下可作为函数 fopen() 中第一个参数的正确格局是( )。 ...

May 12, 2022 · 6 min · jiezi

关于c:Redis-源码解读sds

“实在”的 sdshdr 构造在 《Redis 设计与实现》中,提到 sds 的实现构造 sdshdr 是这样的: struct sdshdr { // 记录buf数组已应用字节的数量 // 等于SDS所保留字符串的长度 int len; // 记录buf数组中未应用的字节数 int free; // 字节数组,用于保留字符串 char buf[];};这可能是 Redis 以前的版本是这样的,笔者查看的源码是 7.0 在 Redis 7.0 中,sdshdr (在 sds.h 中)构造是这样的: /* Note: sdshdr5 is never used, we just access the flags byte directly. * However is here to document the layout of type 5 SDS strings. */struct __attribute__ ((__packed__)) sdshdr5 { unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ char buf[];};struct __attribute__ ((__packed__)) sdshdr8 { uint8_t len; /* used */ uint8_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[];};struct __attribute__ ((__packed__)) sdshdr16 { uint16_t len; /* used */ uint16_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[];};struct __attribute__ ((__packed__)) sdshdr32 { uint32_t len; /* used */ uint32_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[];};struct __attribute__ ((__packed__)) sdshdr64 { uint64_t len; /* used */ uint64_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[];};依据字符串长度的不同,用来寄存它的 sdshdr 类型也是不同的 ...

May 12, 2022 · 12 min · jiezi

关于c:浙大版C语言程序设计第四版何钦铭颜晖-第11章-指针进阶-课后习题答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 一、选择题 1.上面程序段的运行后果是( )。 int x[5] = {2, 4, 6, 8, 10}, *p, **pp;p = x;pp = &p;printf("%d", *(p++));printf("%d\n", **pp);A.4 4 B.2 4 C.2 2 D.4 6 答:B 解析: 题目中先定义了 int 类型的数组 x,又定义两个指针。 而后 p = x,示意将 x 的基地址赋值给 p,所以 p 指向数组中第一个元素。 第一次打印 *(p++),获取 p 指向的元素,打印 2, 而后指针地位向后挪动一个地位。 因为 pp = &p,示意将 p 的地址赋值给 pp,所以 pp 指向 p,p 通过上次打印时的 ++,曾经向后肯定一个,所以第二个打印 **pp,打印的就是 4。 2.对于以下变量定义,正确的赋值是( )。 int *p[3], a[3];A. p=a B. *p=a[0] C. p=&a[0] ...

May 11, 2022 · 10 min · jiezi

关于c:Linux网络开发必学教程17深入-UDP-数据收发-下

问题: UDP 是否还有其余一对多的数据发送形式?UDP 通信中的多播多播是向特定组中的所有主机传输数据的办法,多播也称之为组播多播数据传输的特点:多播发送者针对特定的多播组,只发送 1 次数据,组内主机均可接管到数据主机退出特定组,即可接管该组中的多播数据多播组可在 IP 地址范畴内任意增加关键问题:如何收发多播数据多播组是一个 D 类地址 (224.0.0.0 - 239.255.255.255)"退出多播组"可了解为 UDP 网络程序进行的申请如:申请接管发往 239.234.111.222 的多播数据即:设置属性 (IPPROTO_IP, IP_ADD_MEMBERSHP)发送多播数据的形式,与发送一般 UDP 数据的形式雷同准备操作:设置属性,如:(IPPROTO_IP, IP_MULTICAST_TTL)注意事项退出同一个多播组的主机不肯定在同一个网络中因而,必须设置多播数据的最多转发次数(TTL)TTL(即:Time To Live) 是决定数据传输间隔的次要因素TTL 用整数示意,并且每通过 1 个路由就缩小 1当 TTL 变为 0 时,数据无奈持续传递,只能销毁多播程序设计:发送端IP_MULTCAST_TTL: 用于设置多播数据的”最远传输间隔“,默认 1IP_MULTICAST_IF: 用于设置多播数据从哪一个网络接口(网卡)发送进来,默认:0.0.0.0默认 0.0.0.0 状况下操作系统会自主抉择应用哪个网络接口,但在[多网卡主机]的[理论工程利用]中,最好手工指定!!IP_MULTCAST_LOOP: 用于设置多播数据是否发送回本机,默认1 (1,发送回本机)remote.sin_family = AF_INET;remote.sin_addr.s_addr = inet_addr("224.1.1.168");remote.sin_port = htons(8888);setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));do { len = sizeof(remote); r = sendto(sock, buf, strlen(buf), 0, (struct sockaddr*)&remote, len); sleep(1);}while(r > 0);多播程序设计:接收端IP_ADD_MEMBRESHIP: 用于申请加入多播组,参数为:多播组和本机地址struct ip_mreq { // group address struct in_addr inmr_multiaddr; // local host address struct in_addr imr_interface} ...

May 10, 2022 · 3 min · jiezi

关于c:哥德巴赫猜想的验证

首先得申明一句,自己文学业余出身,数学的确不好,能够说齐全零根底,因而这篇博客的代码花了靠近一下午的工夫(并不是代码有多难,而是本人数学太差,所以得查半天材料钻研) 什么是哥德巴赫猜想 (以下内容来自百度百科) 哥德巴赫1742年在给欧拉的信中提出了以下猜测:任一大于2的整数都可写成三个质数之和 [1] 。然而哥德巴赫本人无奈证实它,于是就写信求教赫赫有名的大数学家欧拉帮忙证实,然而始终到死,欧拉也无奈证实。 [2] 因现今数学界曾经不应用“1也是素数”这个约定,原初猜测的古代陈说为:任一大于5的整数都可写成三个质数之和。(n>5:当n为偶数,n=2+(n-2),n-2也是偶数,能够合成为两个质数的和;当n为奇数,n=3+(n-3),n-3也是偶数,能够合成为两个质数的和)欧拉在回信中也提出另一等价版本,即任一大于2的偶数都可写成两个质数之和。今日常见的猜测陈说为欧拉的版本。把命题"任一充沛大的偶数都能够示意成为一个素因子个数不超过a个的数与另一个素因子不超过b个的数之和"记作"a+b"。1966年陈景润证实了"1+2"成立,即"任一充沛大的偶数都能够示意成二个素数的和,或是一个素数和一个半素数的和"。今日常见的猜测陈说为欧拉的版本,即任一大于2的偶数都可写成两个素数之和,亦称为“强哥德巴赫猜想”或“对于偶数的哥德巴赫猜想”。从对于偶数的哥德巴赫猜想,可推出:任何一个大于7的奇数都能被示意成三个奇质数的和。后者称为“弱哥德巴赫猜想”或“对于奇数的哥德巴赫猜想”。若对于偶数的哥德巴赫猜想是对的,则对于奇数的哥德巴赫猜想也会是对的。2013年5月,巴黎低等师范学院研究员哈洛德·贺欧夫各特发表了两篇论文,发表彻底证实了该猜测。 **说了这么多,咱们总结一句话,那就是:咱们要在2000以内的不小于4的正偶数都可能合成为两个素数之和(即验证歌德巴赫猜想对2000以内的正偶数成立)** 思路既然晓得题目要求,咱们接下来就要设计算法了首先,咱们本人定义一个函数,咱们假如函数名字叫fun,将素数过滤出来 int fun(int n){ int i; if(n==2) return 1; /*n是2,返回1*/ if(n%2==0) return 0; /*n是偶数,不是素数,返回0*/ for(i=3; i<=sqrt(n); i+=2) if(n%i==0) return 0; /*n是奇数,不是素数,返回0*/ return 1; /*n是除2以外的素数返回1*/}有了素数的判断,接下来,咱们就能够设计主函数了。因为是用户输出,所以为了避免“淘气的用户乱输出”导致报错,所以咱们思考下空值的状况,以及非偶数的状况,另外,通过退出ok来管制输入。残缺代码如下; #include<math.h>#include<stdio.h>int fun(int n){ int i; if(n==2) return 1; /*n是2,返回1*/ if(n%2==0) return 0; /*n是偶数,不是素数,返回0*/ for(i=3; i<=sqrt(n); i+=2) if(n%i==0) return 0; /*n是奇数,不是素数,返回0*/ return 1; /*n是除2以外的素数返回1*/}int main(){ int n, i, ok; while(scanf("%d",&n)!=EOF) { ok=0; /*进入循环前先置标记位*/ for(i=2; i<=n/2; i++) { if( fun(i) ) if( fun(n-i) ) { printf("%d %d\n", i, n-i); /*i和n-i都是素数,则打印*/ ok=1; } if(i!=2) i++; if(ok) break; /*已打印出所须要的输入后果,跳出循环*/ } } return 0;

May 10, 2022 · 1 min · jiezi

关于c:浙大版C语言程序设计第四版何钦铭颜晖-第10章-函数与程序结构-课后习题答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 一、选择题 1.对于以下递归函数,调用f(4),其返回值为( )。 int f(int n){ if (n) return f(n - 1) + n; else return n;}A.10 B.4 C.0 D.以上均不是 答:A 解析: 递归函数的调用。 第一次调用函数 f,参数为 4,执行 if 语句,返回 f(3)+4, 第二次调用函数 f,参数为 3,执行 if 语句,返回 f(2)+3, 第三次调用函数 f,参数为 2,执行 if 语句,返回 f(1)+2, 第四次调用函数 f,参数为 1,执行 if 语句,返回 f(0)+1, 第五次调用函数 f,参数为 0,执行 else 语句,返回 0。 而后再一层一层将return 的后果返回。最终失去的就是 0 +1+2+3+4 = 10。 2.执行下列程序段后,变量 i 的值为( )。 #define MA(x, y) (x*y)i=5;i=MA(i, i+1)-7;A.30 ...

May 10, 2022 · 10 min · jiezi

关于c:Linux网络开发必学教程16深入-UDP-数据收发-上

问题:如何进行一对多的 UDP 数据发送?UDP 通信中的播送播送是向同一网络中的所有主机传输数据的办法播送类型 间接播送:IP 地址中除网络地址外,其余主机地址均设置为 1本地播送:无需晓得网络,应用 255.255.255.255 作为 IP 地址应用区别 本地播送数据不通过路由器寻址,间接发送到本地主机本地播送利用案例:DHCPDHCP (动静主机配置协定)是一个局域网的网络协议(基于 UDP 协定)本地主机可主动取得服务器调配的 IP 地址和子网掩码DHCP 采纳 客户端 / 服务器 模型,地址的动态分配由网络主机驱动工作形式:DHCP 服务器接管到来自网络主机的地址申请时,会向网络主机发送相干的地址配置信息,以实现网络主机地址信息的动静配置 准备筹备 socket 属性设置(option)socket 的实质是对本机网络资源的一种标识socket 自身有各种属性(不同的连贯,属性可能不同)通过 setsockopt() / getsockopt() 可存取指定 socket 的属性值socket 属性的扭转可造成 socket 数据收发行为的扭转TCP 编程中设计的用法 setsockopt() / getsockopt() 属性存取函数#include <sys/types.h>#include <sys/socket.h>int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);若无谬误产生返回 0; 否则返回 SOCKET_ERROR 谬误。 ...

May 9, 2022 · 2 min · jiezi

关于c:Linux网络开发必学教程15UDP-数据收发实战

问题:如何应用 UDP 进行数据收发?再论 UDP 协定UDP 是无连贯的(不牢靠的,无应答音讯,数据包无序号标识)UDP 是面向数据包的,对应用层数据既不合并也不拆分(保留数据包边界)UDP 没有拥塞管制,网络呈现的拥塞不会使源主机的发送速率升高UDP 反对一对一,一对多,多对一和多对多的交互通信UDP 音讯头开销小,只有 8 个字节(TCP 音讯头共 20 个字节) UDP 和 IP 的区别UDP 是建设于 IP 之上的数据传输协定IP 负责将 UDP 数据包从源主机传输到指标主机UDP 则将应用层数据投递到指标 socket (端口号)UDP 简直残缺 “继承” 了 IP 传输的个性通信两端无交互,无流控,无超时重发,不具备可靠性UDP 收发数据#include "sys/socket.h"ssize_t send(int sock, // socket 文件描述符 void *buf, // 须要发送的数据 size_t nbytes, // 须要发送的数据量 int flags, // 发送选项 struct sockaddr *to, // 接管地址信息 socklen_t addrlen); // to 参数长度ssize_t recvfrom(int sock, // socket 文件描述符 void *buf, // 保留接收数据的地址 size_t nbytes, // 可接管的最大数据量 int flags, // 接管选项 struct sockaddr *from, // 接管地址信息 socklen_t *addrlen); // 指向保留 from 参数长度的变量地址UDP 编程模式 ...

May 9, 2022 · 2 min · jiezi

关于c:浙大版C语言程序设计第四版何钦铭颜晖-第9章-结构-课后习题答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 一、选择题 1.以下定义构造变量的语句中,谬误的是( )。 A. struct student { int num; char name[ 20];} s; B. struct { int num; char name[ 20] ;} s; C. struct student { int num; char name[ 20] ;} ; student s; D. struct student { int num; char name [ 20] ; } ; struct student s; 答:C 解析: 构造变量名能够在定义构造后独自定义。也能够跟在构造后间接定义,间接写构造变量名即可。 2.如果构造变量 s 中的生日是 “1984 年11月11日”,下列对其生日的正确赋值是( )。 struct student{ int no; char name[20]; char sex; struct { int year; int month; int day; }birth;}s;A. year= 1984; month=11; day=11; ...

May 9, 2022 · 7 min · jiezi

关于c:Linux网络开发必学教程14数据收发的扩展用法-下

MSG_PEEK (数据窥探)应用 MSG_PEEK 选项可能获取接收缓冲区数据的拷贝recv() 专用选项,可用于数据预接管指定 MSG_PEEK 选项时,不会清空缓冲区可用于获取接收缓冲区种的数据量(字节数)当接收缓冲区中没有数据时,MSG_PEEK 也会导致线程阻塞 上面的代码输入什么?为什么?static char c_temp[1024 * 2] = {0};char buf[32] = {0];sleep(1);r = recv(client, c_temp, sizeof(c_temp), MSG_PEEK);c_temp[r] = 0;printf("r = %d\n", r);printf("c_temp = %s\n", c_temp);r = recv(client, buf, sizeof(buf), 0);buf[r] = 0;printf("r = %d\n", r);printf("buf = %s\n", buf);client.c#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <unistd.h>#include <string.h>int main(){ int sock = {0}; struct sockaddr_in addr = {0}; int len = 0; char *test = "Delpin-Tang"; sock = socket(PF_INET, SOCK_STREAM, 0); if (sock == -1) { printf("socket error\n"); return -1; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(8888); if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) { printf("connect error\n"); return -1; } printf("connect success\n"); len = send(sock, test, strlen(test), 0); getchar(); close(sock); return 0;}server.c#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <unistd.h>#include <string.h>int main(){ int server = 0; struct sockaddr_in saddr = {0}; int client = 0; struct sockaddr_in caddr = {0}; socklen_t asize = 0; int len = 0; char buf[32] = {0}; int r = 0; server = socket(PF_INET, SOCK_STREAM, 0); if (server == -1) { printf("server socket error\n"); return -1; } saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl(INADDR_ANY); saddr.sin_port = htons(8888); if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) { printf("server bind error\n"); return -1; } if (listen(server, 1) == -1) { printf("server listen error\n"); return -1; } printf("server start success\n"); while (1) { asize = sizeof(caddr); client = accept(server, (struct sockaddr*)&caddr, &asize); if (client == -1) { printf("client accept error"); return -1; } printf("client: %d\n", client); do { r = recv(client, buf, sizeof(buf), MSG_PEEK); if (r > 0) { buf[r] = 0; printf("r = %d\n", r); printf("data: %s\n", buf); r = recv(client, buf, sizeof(buf), 0); buf[r] = 0; printf("r = %d\n", r); printf("data: %s\n", buf); } else { printf("no data in receive buf\n"); // 留神这里!(如果未打印示意阻塞) } }while (r > 0); close(client); } close(server); return 0;}输入:server start successclient: 4r = 11data: Delpin-Tangr = 11data: Delpin-TangMSG_DONTWAIT (立刻收发模式)数据收发时不阻塞,立刻返回sned() : 如果无奈将数据送入发送缓冲区,那么间接返回谬误 (比方:发送缓冲器 1024 字节大小,欲想发送 2048 字节时)recv() : 如果接收缓冲区中没有数据,那么间接返回谬误send() / recv() 返回值:-1, 谬误产生0, 对端调用 close 敞开n, 发送 / 接管 的数据量上面的代码输入什么?为什么?printf("connect success\n");sleep(1);test = "D.T.software";send(sock, test, strlen(test), 0);sleep(2);test = "quit";send(sock, test, strlen(test), 0); ...

May 8, 2022 · 7 min · jiezi

关于c:数据与C

变量与常量为了可能更加不便的应用数据,程序员会将在程序运行期间会扭转或赋值的数据应用变量进行保留。常量则是事后定义好,在程序运行期间不会扭转的固定值 变量和常量就如同是一个盒子,能够用来装货色(数据)。在计算机中,数据是寄存在内存中的,存放数据的内存空间程序员为了不便当前的应用,都会起一个好记的名字。这个名称也由字母、数字和下划线组成,必须要以字母和下划线结尾。因为C语言是对大小写敏感的,所以大写字母和小写字母是不同的,也就是变量名abc和Abc是两个不同的变量。 数据类型不同的数据类型有不同的含意,有的数据类型示意整数,有的示意字符,有的示意浮点数。常量能够是任何的数据类型,通过常量的值辨认(100是整数,123.45是浮点数)。而变量则须要指定数据类型。在C语言中有很多种数据类型,从最后的K&R给出的7个数据类型关键字,再到C90增加的2个新的关键字,到最初的C99增加的3个关键字 最后K&R给出的关键字C90规范增加的关键字C99规范增加的关键字intsigned_Boollongvoid_Complexshort _Imaginaryunsigned char float double int、long、short、unsigned和C90新增加的signed关键字用于示意整数类型,unsigned示意无符号数,signed则示意有符号数,整数类型的例子:unsigned short int 和 long long int char关键字用于寄存字母和其余字符(如:$、%等),char也能够用来示意较小的整数 float、double和long double示意浮点数 _Bool示意布尔类型(true或false) _Complex和_Imaginary别离示意复数和虚数 存储大小不同的数据类型能够寄存的数据大小是不同的,可能寄存的数据越多,值越大。 数据类型存储大小char1字节int2或4字节()short2字节long4字节float4字节double8字节long double16字节在C语言中,能够通过sizeof运算符查看数据类型存储字节的大小 #include<stdio.h>int main(){ printf("char 的存储大小: %d\n", sizeof(char)); printf("short 的存储大小: %d\n", sizeof(short)); printf("int 的存储大小: %d\n", sizeof(int)); printf("long 的存储大小: %d\n", sizeof(long)); printf("float 的存储大小: %d\n", sizeof(float)); printf("double 的存储大小: %d\n", sizeof(double)); printf("long double 的存储大小: %d\n", sizeof(long double)); return 0;}运行后果: 这里应用到的printf()函数,前面会进行解说,目前只须要晓得printf()是用来打印内容到屏幕上的就能够了。 变量的定义C语言提供了很多种数据类型,在定义变量时须要指定变量的数据类型,如整数能够应用int类型,小数能够应用float类型等,上面将开始介绍如何定义变量。 定义变量定义变量的语法:数据类型 变量名; 举个例子,上面的程序用于计算两个整数的和 #include<stdio.h>int main(){ int num1; //定义一个变量num1,用于寄存第一个数 int num2; //定义一个变量num2,用于寄存第二个数 int sum; //定义一个变量sum,用于寄存两个数的和 num1 = 100; //将整数100赋值给变量num1 num2 = 200; sum = num1 + num2; //计算num1与num2相加,并将值赋值给sum变量 printf("num1 + num2 = %d\n", sum); // 将sum的值打印到屏幕 return 0;}运行后果: ...

May 8, 2022 · 3 min · jiezi

关于c:浙大版C语言程序设计第四版何钦铭颜晖-第8章-指针-课后习题答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 一、选择题 1.下列语句定义 px 为指向 int 类型变量的指针,正确的是( )。 A. int x, *px=x; B.int x, *px=&x;C. int *px=&x, x;D.int x, px=x; 答:B 解析:先定义变量,再定义指针,定义指针应用 *。为指针赋值为某个变量的地址时应用 & 符。 2.以下选项中,对根本类型雷同的指针变量不能进行运算的运算符是( )。 A. =B. ==C. +D. - 答:C 解析: 选项 A :“=(赋值)”是对于类型雷同的两个指针变量之间惯例运算。 选项 B: “==(比拟相等)”比拟两个指针变量是否雷同。 选项 C:“+” 运算是不能够的,因为指针变量是一种非凡的变量,指针变量的值寄存的是所指向变量的地址,两个地址相加并不能保障后果为一个无效的地址值,因此在 C 语言中指针变量相加是非法的。 选项 D:“-(减法)”运算两个雷同指针变量相减能够取得在之间相隔的同类型元素个数(在某个类型的数组中的利用)。 3.下列程序的输入后果是( )。 void f(int *p){ *p = 5;}int main(void){ int x = 10, *px = &x; f(px); printf("%d#", (*px)++); printf("%d\n", x); return 0;}A.5#6B.6#6C.10#11D.11#11 ...

May 7, 2022 · 9 min · jiezi

关于c:Linux网络开发必学教程13数据收发的扩展用法-上

write() 和 send() 都能够收发数据,有什么区别?send 能够应用 flags 指定可选项信息,其中 0 示意默认发送行为send 当 flags 为 0 时,会期待发送缓冲区数据清空之后才将数据放入发送缓冲器而后返回write 不能指定可选项信息,同时不会阻塞read() 和 recv() 都能够接收数据,有什么区别?recv 能够应用 flags 指定可选项信息,其中 0 示意默认接管行为recv 当 flags 为 0 时,会期待接收缓冲区有数据之后才将数据从接收缓冲区中取出而后返回read 不能指定可选项信息,同时不会阻塞数据收发选项#include <sys/socket.h>ssize_t send(int socketfd, const void *buf, size_t nbytes, int flags);ssize_t recv(int socketfd, void *buf, size_t nbytes, int flags);flags - 收发数据时指定可选项信息,其中 0 为默认收发行为 flags 选项信息 (局部)可选项含意sendrecvMSG_OOB用于传输带外数据(Out Of Band Data),即:紧急数据(优先发送)√√MSG_PEEK验证接收缓冲区是否存在数据(有什么数据) √MSG_DONTROUTE数据传输过程不通过路由表,在本地局域网中寻找目的地√ MSG_DONTWAIT非阻塞模式,数据收发时立刻返回√√MSG_WAITALL在接管到申请的全副数据之前,不提前返回 √MSG_MORE有更多数据须要发送,批示内核期待数据√ ...... 留神: 不同的操作系统对上述可选项的反对不同,理论工程开发时,须要当时对指标零碎中反对的可选项进行调研MSG_OOB (带外数据,紧急数据)原生定义应用与一般数据不同的的通道独立传输的数据带外数据优先级比一般数据高(优先传输,对端优先接管)TCP 中的带外数据因为原生设计的限度,TCP无奈提供真正意义上的带外数据TCP 中仅能通过传输协定音讯头中的标记,传输紧急数据,且长度仅1字节TCP 带外数据实现原理 URG 指针指向紧急音讯的下一个地位,即:URG 指针指向地位的前一个字节存储了紧急音讯接收端优先接管紧急数据,并将其存储到非凡缓冲区,之后再接管一般数据紧急数据:0x03一般数据:0x01,0x02TCP 带外数据处理策略因为 TCP 设计为流式数据,因而,无奈做到真正的带外数据被标记的紧急数据可被提前接管,进入非凡缓冲区(仅一字节) ...

May 7, 2022 · 4 min · jiezi

关于c:简单谈谈C语言数据类型转换的安全问题

在c语言的赋值类型转换中,有两种转换形式,分为隐形转换和显性转换。 什么是隐性转换,举个简略的demo(当然了,理论遇到的必定比这简单太多) int a = 3; int b = 0;a = b;printf("%d", a);在这里,a的值应该为几,没错,曾经不再是之前的数字,而是变成了b赋予的值,也就是说,咱们这两行代码曾经将a赋予的3变成了b赋予的0,咱们将这种零碎“偷偷摸摸”批改的称之为隐性转换。 这种隐性转换,能够对b的值作出批改,看起来是不是很不便,然而,咱们上面再举一个例子,咱们假如a的值为100000,b的值为1, int a = 1000000; short int b = 0; b = a; printf("%d", b);这种状况下,我这边运行的后果如下: 所以不难看出数据呈现了失落,这是因为,a,b的值过大。因而成为了某些程序员代码中bug的一部分。说完隐性转换,再说说显性转换,举一个简略的例子: int a = 100; double b = 0; b = a; printf("%d", (int)b);这里实际上就是显性转换,显性转换,顾名思义,就是我明晓得会这样,成心这么去设定操作,这里有几个容易失误的中央,那就是输入时肯定须要用%d和(int),对它进行强制。否则输入后果就是浮点型。 好啦,这篇博客就写到这里,如果有其余疑难,欢送评论区评论。

May 6, 2022 · 1 min · jiezi

关于c:浙大版C语言程序设计第四版何钦铭颜晖-第7章-数组-课后习题答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 一、选择题1.假设 int 类型变量占用两个字节,则以下定义的数组 a 在内存中所占字节数是( )。 int a[10]={10,2,4};A. 20B.10C.6D.3 答:A 解析:题目中,依据 int a[10] ,示意定义了数组的长度是 10 ,每个变量占用两个字节,一共就是 20 个字节。 2.若有定义:int a[2][3] ;以下选项中对数组元素正确援用的是( )。A. a[2][0]B. a[2][3]C. a[0][3]D. a[1>2][1] 答:D 解析: 题目中定义了二维数组 a[2][3] ,那么该数组示意一个 2 行 3 列的矩阵,行的下标(第一个下标)的取值范畴就是 0,1,列的下标(第二个下标)的取值范畴就是 0,1,2。这里是有选项 D,a[1>2][1],实际上是 a[0][1],下标的数值没有越界。 3.以下程序段的输入后果是( )。 int aa[4][4]={{1,2,3,4},{5,6,7,8},{3,9,10,2},{4,2,9,6}};int i, s=0;for(i=0; i<4; i++) s+=aa[i][3];printf("%d\n", s);A.11B.19C.13D.20 答:D 解析: 题目中定义的是二维数组,4X4 的矩阵。 1 2 3 45 6 7 83 9 10 24 2 9 6循环中 i 的值示意行,从 0 取到 3,而列的下标固定是 3,所以示意累加最初一列的值。4+8+2+6 = 20。 ...

May 6, 2022 · 9 min · jiezi

关于c:Linux网络开发必学教程12TCP通讯框架服务端设计

问题:如何设计与客户端对应的服务端?TCP 通信框架设计 服务端负责监听连贯状态 Connect : 产生通信客户端(TcpClient), 并给出事件告诉Close : 给出事件告诉,并销毁客户端负责监听数据通信状态,并给出事件告诉服务端事件设计EVT_CONN: 客户端连贯服务端时触发,并创立 TcpClient 用于通信EVT_DATA: 客户端数据达到服务端时触发,应用 TcpClient 读取数据EVT_CLOSE: 客户端断开服务时触发,相干 TcpClient 将销毁 问题:服务端如何晓得什么时候进行事件回调告诉?服务端通过 select 机制触发事件回调! 服务端接口设计typedef void TcpServer;typedef void (*Listener)(TcpClient*, int);enum { EVT_CONN, EVT_DATA, EVT_CLOSE};TcpServer *TcpServer_New();int TcpServer_Start(TcpServer *server, int port, int max);void TcpServer_Stop(TcpServer *server);void TcpServer_SetListener(TcpServer *server, Listener listener);int TcpServer_IsValid(TcpServer *server);void TcpServer_DoWork(TcpServer *server);void TcpServer_Del(TcpServer *server);服务端要害代码实现 - 初始化typedef struct tcp_server { int fd; int valid; Listener cb; TcpClient *client[FD_SIZE];}Server;TcpServer *TcpServer_New(){ Server *ret = malloc(sizeof(Server)); if (ret) { int i = 0; ret->fd = -1; ret->valid = 0; ret->cb = NULL; } return ret;}服务端要害代码实现 - 事件监听FD_ZERO(&reads);FD_SET(s->fd, &reads);max = s->fd;while (s->valid) { rset = reads; timeout.tv_sec = 0; timeout.tv_usec = 5000; num = select(max+1, &rset, 0, 0, &timeout); if (num > 0) { max = SelectHandler(s, &rset, &reads, num, mac); }}服务器要害代码实现 - 连贯事件 & 数据事件if (index == s->fd) { // 连贯事件 struct sockaddr_in caddr = {0}; socklen_t asize = sizeof(caddr); index = accept(s->fd, (struct sockaddr*)&addr, &asize); if (index > -1) { FD_SET(index, reads); ret = (index > max) ? index : max; s->client[index] = TcpClient_From(index); event = EVT_CONN; }} else { // 数据事件 event = EVT_DATA;}服务器要害代码实现 - 断开事件 & 事件告诉if (s->cb) { if (TcpClient_IsValid(s->client[index])) { s->cb(s->client[index], event); // EVT_CONN & EVT_DATA 事件告诉 } else { if (s->client[index]) { s->cb(s->client[index], EVT_CLOSE); // 断连事件告诉 TcpClient_Del(s->client[index]); s->client[index] = NULL; FD_CLR(index, reads); } }}编程试验tcp_server.h#ifndef TCP_SERVER_H#define TCP_SERVER_H#include "tcp_client.h"typedef void TcpServer;typedef void (*Listener)(TcpClient*, int);enum { EVT_CONN, EVT_DATA, EVT_CLOSE};TcpServer *TcpServer_New();int TcpServer_Start(TcpServer *server, int port, int max);void TcpServer_Stop(TcpServer *server);void TcpServer_SetListener(TcpServer *server, Listener listener);int TcpServer_IsValid(TcpServer *server);void TcpServer_DoWork(TcpServer *server);void TcpServer_Del(TcpServer *server);#endiftcp_server.c#include "tcp_server.h"#include "tcp_client.h"#include <sys/types.h>#include <sys/socket.h>#include <sys/select.h>#include <netinet/in.h>#include <netinet/tcp.h> #include <arpa/inet.h>#include <unistd.h>#include <malloc.h>#define FD_SIZE 1024typedef struct tcp_server { int fd; int valid; Listener cb; TcpClient *client[FD_SIZE];}Server;TcpServer *TcpServer_New(){ Server *ret = malloc(sizeof(Server)); if (ret) { int i = 0; ret->fd = -1; ret->valid = 0; ret->cb = NULL; for (i=0; i<FD_SIZE; ++i) { ret->client[i] = NULL; } } return ret;}int TcpServer_Start(TcpServer *server, int port, int max){ Server *s = (Server*)server; if (s && !s->valid) { struct sockaddr_in saddr = {0}; s->fd = socket(PF_INET, SOCK_STREAM, 0); s->valid = (s->fd != -1); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl(INADDR_ANY); saddr.sin_port = htons(port); s->valid = s->valid && (bind(s->fd, (struct sockaddr*)&saddr, sizeof(saddr)) != -1); s->valid = s->valid && (listen(s->fd, max) != -1); } return s->valid;}void TcpServer_Stop(TcpServer *server){ Server *s = (Server*)server; if (s) { int i =0; s->valid = 0; close(s->fd); for (i=0; i<FD_SIZE; ++i) { TcpClient_Del(s->client[i]); s->client[i] = NULL; } }}void TcpServer_SetListener(TcpServer *server, Listener listener){ Server *s = (Server*)server; if (s) { s->cb = listener; }}int TcpServer_IsValid(TcpServer *server){ return server ? ((Server*)server)->valid : 0;}static int SelectHandler(Server *s, fd_set *rset, fd_set *reads, int num, int max){ int ret = max; int i =0; for (i=0; i<=max; ++i) { if (FD_ISSET(i, rset)) { int index = i; int event = -1; if (index == s->fd) { struct sockaddr_in caddr = {0}; socklen_t asize = sizeof(struct sockaddr_in); index = accept(s->fd, (struct sockaddr*)&caddr, &asize); if (index > -1) { FD_SET(index, reads); ret = (index > max) ? index : max; s->client[index] = TcpClient_From(index); event = EVT_CONN; } } else { event = EVT_DATA; } if (s->cb) { if (TcpClient_IsValid(s->client[index])) { s->cb(s->client[index], event); } else { if (s->client[index]) { s->cb(s->client[index], EVT_CLOSE); } TcpClient_Del(s->client[index]); s->client[index] = NULL; FD_CLR(index, reads); } } } } return ret;}void TcpServer_DoWork(TcpServer *server){ Server *s = (Server*)server; if (s && s->valid) { int max = 0; int num = 0; fd_set reads = {0}; fd_set rset = {0}; struct timeval timeout = {0}; FD_ZERO(&reads); FD_SET(s->fd, &reads); max = s->fd; while (s->valid) { rset = reads; timeout.tv_sec = 0; timeout.tv_usec = 10000; num = select(max + 1, &rset, 0, 0, &timeout); if (num > 0) { max = SelectHandler(s, &rset, &reads, num, max); } } }}void TcpServer_Del(TcpServer *server){ TcpServer_Stop(server); free(server);}测试:server.c#include <stdio.h>#include <string.h>#include <malloc.h>#include "tcp_server.h"void EventListener(TcpClient *client, int evt) { if (evt == EVT_CONN) { printf("Connect: %p\n", client); } else if (evt == EVT_DATA) { Message *m = TcpClient_RecvMsg(client); if (m) { char *s = TcpClient_GetDate(client); if (m->index == 0) { s = malloc(m->total + 1); TcpClient_SetData(client, s); } strcpy(s+m->index, m->payload); if ((m->index + 1) == m->total) { printf("Data: %s\n", s); free(s); } free(m); } } else if (evt == EVT_CLOSE) { printf("close: %p\n", client); }}int main(){ TcpServer *server = TcpServer_New(); if (server) { int r = TcpServer_Start(server, 8888, 20); if (r) { TcpServer_SetListener(server, EventListener); TcpServer_DoWork(server); } } return 0;}输入:Connect: 0x5602eb035690Data: D.T.Softwareclose: 0x5602eb035690

May 5, 2022 · 4 min · jiezi

关于c:Linux网络开发必学教程11TCP通讯框架客户端设计

问题:有了协定和协定解析器之后,能够干嘛?TCP 通信框架设计 客户端 以协定音讯为根本单位收发数据同时反对字节为根本单位收发数据服务端 负责监听链接,并产生通信客户端负责监听数据通讯状态,并给出告诉 职责意义客户端用于进行理论的双向数据通信 数据发送 & 数据接管 (协定音讯)服务端仅用于监听和回调告诉 事件类型:连贯,数据,断开事件回调:void (*Listener)(TcpClient *client, int event);客户端接口设计typedef void TcpClient;TcpClient *TcpClient_New();TcpClient *TcpClient_From(int fd);int TcpClient_SendMsg(TcpClient *client, Message *msg);int TcpClient_SendRaw(TcpClient *client, char *buf, int length);Message *TcpClient_RecvMsg(TcpClient *client);int TcpClient_RecvRaw(TcpClient *client, char *buf, int length);int TcpClient_Connect(TcpClient *client, char *ip, int port);int TcpClient_IsValid(TcpClient *client);void TcpClient_Close(TcpClient *client);void TcpClient_Del(TcpClient *client);void TcpClient_SetData(TcpClient *client, void *data);void *TcpClient_GetDate(TcpClient *client);编程试验:客户端设计与实现message.h#ifndef MESSAGE_H#define MESSAGE_Htypedef struct message { unsigned short type; unsigned short cmd; unsigned short index; unsigned short total; unsigned int length; unsigned char payload[];}Message;Message *Message_New(unsigned short type, unsigned short cmd, unsigned short index, unsigned short total, unsigned char *payload, unsigned int length);int Message_Size(Message *m);Message *Message_N2H(Message *m);Message *Message_H2N(Message *m);#endifmessage.c#include "message.h"#include <malloc.h>#include <string.h>#include <arpa/inet.h>Message *Message_New(unsigned short type, unsigned short cmd, unsigned short index, unsigned short total, unsigned char *payload, unsigned int length){ Message *ret = malloc(sizeof(Message) + length); if (ret) { ret->type = type; ret->cmd = cmd; ret->index = index; ret->total = total; ret->length = length; if (payload) { memcpy(ret + 1, payload, length); } } return ret;}int Message_Size(Message *m){ int ret = 0; if (m) { ret = sizeof(Message) + m->length; } return ret;}Message *Message_N2H(Message *m){ if (m) { m->type = ntohs(m->type); m->cmd = ntohs(m->cmd); m->index = ntohs(m->index); m->total = ntohs(m->total); m->length = ntohl(m->length); } return m;}Message *Message_H2N(Message *m){ if (m) { m->type = htons(m->type); m->cmd = htons(m->cmd); m->index = htons(m->index); m->total = htons(m->total); m->length = htonl(m->length); } return m; }msg_parser.h#ifndef MSG_PARSER_H#define MSG_PARSER_H#include "message.h"typedef void MParser;MParser *MParser_New();Message *MParser_ReadMem(MParser *parser, unsigned char *mem, unsigned int length);Message *MParser_ReadFd(MParser *parser, int fd);void MParser_Reset(MParser *parse);void MParser_Del(MParser *parse);#endifmsg_parser.c#include <malloc.h>#include <string.h>#include <arpa/inet.h>#include <unistd.h>#include "msg_parser.h"typedef struct msg_parser { Message cache; int header; int need; Message *msg;}MsgParser;static void InitState(MsgParser *p){ p->header = 0; p->need = sizeof(p->cache); free(p->msg); p->msg = NULL;}static int ToMidState(MsgParser *p){ p->header = 1; p->need = p->cache.length; p->msg = malloc(sizeof(p->cache) + p->need); if (p->msg) { *p->msg = p->cache; } return !!p->msg;}static Message *ToLastState(MsgParser *p){ Message *ret = NULL; if (p->header && !p->need) { ret = p->msg; p->msg = NULL; } return ret;}static int ToRecv(int fd, char *buf, int size){ int retry = 0; int i = 0; while (i < size) { int len = read(fd, buf + i, size - i); if (len > 0) { i += len; } else if (len < 0) { break; } else { if (retry++ > 5) { break; } usleep(200 * 1000); } } return i;}MParser *MParser_New(){ MsgParser *ret = calloc(1, sizeof(MsgParser)); InitState(ret); return ret;}Message *MParser_ReadMem(MParser *parser, unsigned char *mem, unsigned int length){ Message *ret = NULL; MsgParser *p = (MsgParser*)parser; if (!p || !mem || !length) { return ret; } if (!p->header) { int len = (p->need < length) ? p->need : length; int offset = sizeof(p->cache) - p->need; memcpy((char*)&p->cache + offset, mem, len); if (p->need == len) { Message_N2H(&p->cache); mem += p->need; length -= p->need; if (ToMidState(p)) { ret = MParser_ReadMem(p, mem, length); } else { InitState(p); } } else { p->need -= len; } } else { if (p->msg) { int len = (p->need < length) ? p->need : length; int offset = p->msg->length - p->need; memcpy(p->msg->payload + offset, mem, len); p->need -= len; if (ret = ToLastState(p)) { InitState(p); } } } return ret;}Message *MParser_ReadFd(MParser *parser, int fd){ Message *ret = NULL; MsgParser *p = (MsgParser*)parser; if (fd == -1 || !p) { return ret; } if (!p->header) { int offset = sizeof(p->cache) - p->need; int len = ToRecv(fd, (char*)&p->cache + offset, p->need); if (len == p->need) { Message_N2H(&p->cache); if (ToMidState(p)) { ret = MParser_ReadFd(p, fd); } else { InitState(p); } } else { p->need -= len; } } else { if (p->msg) { int offset = p->msg->length - p->need; int len = ToRecv(fd, p->msg->payload + offset, p->need); p->need -= len; } if (ret = ToLastState(p)) { InitState(p); } } return ret;}void MParser_Reset(MParser *parse){ MsgParser *p = (MsgParser*)parse; if (p) { InitState(p); }}void MParser_Del(MParser *parse){ MsgParser *p = (MsgParser*)parse; if (p) { free(p->msg); free(p); }}tcp_client.h#ifndef TCP_CLIENT_H#define TCP_CLIENT_H#include "message.h"typedef void TcpClient;TcpClient *TcpClient_New();TcpClient *TcpClient_From(int fd);int TcpClient_SendMsg(TcpClient *client, Message *msg);int TcpClient_SendRaw(TcpClient *client, char *buf, int length);Message *TcpClient_RecvMsg(TcpClient *client);int TcpClient_RecvRaw(TcpClient *client, char *buf, int length);int TcpClient_Connect(TcpClient *client, char *ip, int port);int TcpClient_IsValid(TcpClient *client);void TcpClient_Close(TcpClient *client);void TcpClient_Del(TcpClient *client);void TcpClient_SetData(TcpClient *client, void *data);void *TcpClient_GetDate(TcpClient *client);#endiftcp_client.c#include "tcp_client.h"#include "msg_parser.h"#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netinet/tcp.h> #include <arpa/inet.h>#include <unistd.h>#include <malloc.h>typedef struct tcp_client { int fd; MParser *parser; void *data;}Client;TcpClient *TcpClient_New(){ return TcpClient_From(-1);}TcpClient *TcpClient_From(int fd){ Client *ret = malloc(sizeof(Client)); if (ret) { ret->fd = fd; ret->parser = MParser_New(); ret->data = NULL; } return (ret && ret->parser) ? ret : (free(ret), NULL);}int TcpClient_SendMsg(TcpClient *client, Message *msg){ int ret = 0; Client *c = (Client*)client; if (c && msg) { int len = Message_Size(msg); char *data = (char*)Message_H2N(msg); ret = (send(c->fd, data, len, 0) != -1); Message_N2H(msg); } return ret;}int TcpClient_SendRaw(TcpClient *client, char *buf, int length){ int ret = 0; Client *c = (Client*)client; if (c && buf) { ret = send(c->fd, buf, length, 0); } return ret;}Message *TcpClient_RecvMsg(TcpClient *client){ Message *ret = NULL; Client *c = (Client*)client; if (c) { ret = MParser_ReadFd(c->parser, c->fd); } return ret;}int TcpClient_RecvRaw(TcpClient *client, char *buf, int length){ int ret = 0; Client *c = (Client*)client; if (c && buf) { ret = recv(c->fd, buf, length, 0); } return ret;}int TcpClient_Connect(TcpClient *client, char *ip, int port){ int ret = TcpClient_IsValid(client); Client *c = (Client*)client; if (!ret && ip && ((c->fd = socket(PF_INET, SOCK_STREAM, 0)) != -1)) { struct sockaddr_in addr = {0}; addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(ip); addr.sin_port = htons(port); ret = (connect(c->fd, (struct sockaddr*)&addr, sizeof(addr)) != -1); } return ret;}int TcpClient_IsValid(TcpClient *client){ int ret = 0; Client *c = (Client*)client; if (c) { struct tcp_info info = {0}; int l = sizeof(info); getsockopt(c->fd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t*)&l); ret = (info.tcpi_state == TCP_ESTABLISHED); } return ret;}void TcpClient_Close(TcpClient *client){ Client *c = (Client*)client; if (c) { close(c->fd); c->fd = -1; MParser_Reset(c->parser); }}void TcpClient_Del(TcpClient *client){ Client *c = (Client*)client; if (c) { TcpClient_Close(c); MParser_Del(c->parser); free(c); } }void TcpClient_SetData(TcpClient *client, void *data){ Client *c = (Client*)client; if (c) { c->data = data; }}void *TcpClient_GetDate(TcpClient *client){ void *ret = NULL; Client *c = (Client*)client; if (c) { ret = c->data; } return ret;}测试文件:client.c#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <malloc.h>#include "message.h"#include "tcp_client.h"int main(){ int i = 0; char *test = "D.T.Software"; Message *pm = NULL; TcpClient *client = TcpClient_New(); if (client && TcpClient_Connect(client, "127.0.0.1", 8888)) { printf("connect success\n"); for (i=0; i<strlen(test); ++i) { char buf[2] = {0}; buf[0] = test[i]; pm = Message_New(128, 129, i, strlen(test), buf, 2); TcpClient_SendMsg(client, pm); free(pm); } } getchar(); TcpClient_Del(client); return 0;}测试文件:server.c#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netinet/tcp.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <malloc.h>#include "msg_parser.h"#include "tcp_client.h"int main(){ int server = 0; struct sockaddr_in saddr = {0}; struct sockaddr_in caddr = {0}; socklen_t asize = 0; int client = 0; server = socket(PF_INET, SOCK_STREAM, 0); if (server == -1) { printf("server socket error\n"); return -1; } saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl(INADDR_ANY); saddr.sin_port = htons(8888); if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) { printf("server bind error\n"); return -1; } if (listen(server, 1) == -1) { printf("server listen error\n"); return -1; } printf("server start success\n"); while (1) { TcpClient *c = NULL; struct tcp_info info = {0}; int l = sizeof(info); asize = sizeof(caddr); client = accept(server, (struct sockaddr*)&caddr, &asize); if (client == -1) { printf("client accept error\n"); return -1; } c = TcpClient_From(client); printf("client: %d\n", client); printf("addr: %p\n", c); do { Message *m = TcpClient_RecvMsg(c); if (m) { printf("payload = %s\n", m->payload); free(m); } } while (TcpClient_IsValid(c)); printf("client socket is closed\n"); TcpClient_Del(c); } close(server); return 0;}输入: ...

May 4, 2022 · 6 min · jiezi

关于c:浙大版C语言程序设计第四版何钦铭颜晖-第6章-回顾数据类型和表达式-课后习题答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 一、选择题 1.已知字符 'A' 的 ASCII 码是 65,别离对应八进制数 101 和十六进制数 41,以下( )不能正确示意字符'A'。 A. 'A' B. '\101' C. '\x41' D. '\0x41' 答:D 解析: 十六进制示意字符用 \x 结尾。 2.设 a 为整型变量,不能正确表白数学关系: 10<a<15 的 C 语言表达式是( )。 A.10<a<15 B. !(a<= 10lla>= 15) C. a>10 && a<15 D. !(a<= 10)&&!(a>= 15) 答:A 解析: 在 C 语言中,不能像选项 A 中 10<a<15,这样写。 3.执行以下程序段后,变量 c 的值是( )。 int a=10, b=20, c;c=(a%2==0)? a:bA.0 B.5 C.10 D.20 答:C 解析: ...

May 4, 2022 · 7 min · jiezi

关于c:Linux网络开发必学教程10应用协议解析模块下

问题:如何通过 socket 文件描述符实时解析协定数据?深度思考从文件描述符是否可能获取足够的数据?(是否肯定等到数量足够(如:音讯头12字节),能力开始解析)数据量足够 读取 12 字节解析音讯头读取数据填充 payload (length)数据量有余 无奈获取音讯头所需数据(如何解决?解析状态如何切换?)无奈获取 payload 残缺数据(如何解决?是否可追加?)解决方案策略:尽力获取数据,实时解析即使以后获取 1 字节,也可依据状态进行解析反对不同数据源屡次接力解析(从内存或文件描述符交替获取数据)充分利用解析器状态信息是实现解决方案的要害解析器状态切换 状态切换函数static void InitState(MsgParser *p) { p->header = 0; p->need = sizeof(p->cache); free(p->msg); p->msg = NULL;}static int ToMidState(MsgParser *p){ p->header = 1; p->need = p->cache.length; p->msg = malloc(sizeof(p->cache) + p->need); if (p->msg) { *p->msg = p->cache; } return !!p->msg;}static Message *ToLastState(MsgParser *p){ Message *ret = NULL; if (p->header && !p->need) { ret = p->msg; p->msg = NULL; } return ret;}从文件描述符中获取数据static int ToRecv(int fd, char *buf, int size){ int retry = 0; int i = 0; while (i < size) { int len = read(fd, buf + i, size - i); if (len > 0) { i += len; } else { if (retry++ > 5) { break; } usleep(200 * 10000); } } return i;}从文件描述符中实时解析音讯头if (!p->header) { int offset = sizeof(p->cache) - p->need; int len = ToRecv(fd, (char*)&p->cache + offset/* 计算寄存地位并读取音讯头数据 */, p->need); if (len == p->need) { ntoh(&p->cache); if (ToMidState(p)) { ret = MParser_ReadFd(p, fd); } } else { p->need -= len; }}从文件描述符中获取 payload 数据if (p->msg) { int len = ToRecv(fd, p->msg->payload, p->need); p->need -= len;}/* 尝试切换到最终状态,如果胜利,则可取得协定音讯;之后切换到初始状态 */if (ret = ToLastState(p)) { InitState(p);}编程试验:从文件描述符解析协定音讯message.h#ifndef MESSAGE_H#define MESSAGE_Htypedef struct message { unsigned short type; unsigned short cmd; unsigned short index; unsigned short total; unsigned int length; unsigned char payload[];}Message;Message *Message_New(unsigned short type, unsigned short cmd, unsigned short index, unsigned short total, unsigned char *payload, unsigned int length);#endifmessage.c#include "message.h"#include <malloc.h>#include <string.h>Message *Message_New(unsigned short type, unsigned short cmd, unsigned short index, unsigned short total, unsigned char *payload, unsigned int length){ Message *ret = malloc(sizeof(Message) + length); if (ret) { ret->type = type; ret->cmd = cmd; ret->index = index; ret->total = total; ret->length = length; if (payload) { memcpy(ret + 1, payload, length); } } return ret;}msg_parser.h#ifndef MSG_PARSER_H#define MSG_PARSER_H#include "message.h"typedef void MParser;MParser *MParser_New();Message *MParser_ReadMem(MParser *parser, unsigned char *mem, unsigned int length);Message *MParser_ReadFd(MParser *parser, int fd);void MParser_Reset(MParser *parse);void MParser_Del(MParser *parse);#endifmsg_parser.c#include <malloc.h>#include <string.h>#include <arpa/inet.h>#include <unistd.h>#include "msg_parser.h"typedef struct msg_parser { Message cache; int header; int need; Message *msg;}MsgParser;static void InitState(MsgParser *p){ p->header = 0; p->need = sizeof(p->cache); free(p->msg); p->msg = NULL;}static int ToMidState(MsgParser *p){ p->header = 1; p->need = p->cache.length; p->msg = malloc(sizeof(p->cache) + p->need); if (p->msg) { *p->msg = p->cache; } return !!p->msg;}static Message *ToLastState(MsgParser *p){ Message *ret = NULL; if (p->header && !p->need) { ret = p->msg; p->msg = NULL; } return ret;}static void ntoh(Message *m){ m->type = ntohs(m->type); m->cmd = ntohs(m->cmd); m->index = ntohs(m->index); m->total = ntohs(m->total); m->length = ntohl(m->length); }static int ToRecv(int fd, char *buf, int size){ int retry = 0; int i = 0; while (i < size) { int len = read(fd, buf + i, size - i); if (len > 0) { i += len; } else if (len < 0) { break; } else { if (retry++ > 5) { break; } usleep(200 * 1000); } } return i;}MParser *MParser_New(){ MsgParser *ret = calloc(1, sizeof(MsgParser)); InitState(ret); return ret;}Message *MParser_ReadMem(MParser *parser, unsigned char *mem, unsigned int length){ Message *ret = NULL; MsgParser *p = (MsgParser*)parser; if (!p || !mem || !length) { return ret; } if (!p->header) { int len = (p->need < length) ? p->need : length; int offset = sizeof(p->cache) - p->need; memcpy((char*)&p->cache + offset, mem, len); if (p->need == len) { ntoh(&p->cache); mem += p->need; length -= p->need; if (ToMidState(p)) { ret = MParser_ReadMem(p, mem, length); } else { InitState(p); } } else { p->need -= len; } } else { if (p->msg) { int len = (p->need < length) ? p->need : length; int offset = p->msg->length - p->need; memcpy(p->msg->payload + offset, mem, len); p->need -= len; if (ret = ToLastState(p)) { InitState(p); } } } return ret;}Message *MParser_ReadFd(MParser *parser, int fd){ Message *ret = NULL; MsgParser *p = (MsgParser*)parser; if (fd == -1 || !p) { return ret; } if (!p->header) { int offset = sizeof(p->cache) - p->need; int len = ToRecv(fd, (char*)&p->cache + offset, p->need); if (len == p->need) { ntoh(&p->cache); if (ToMidState(p)) { ret = MParser_ReadFd(p, fd); } else { InitState(p); } } else { p->need -= len; } } else { if (p->msg) { int offset = p->msg->length - p->need; int len = ToRecv(fd, p->msg->payload + offset, p->need); p->need -= len; } if (ret = ToLastState(p)) { InitState(p); } } return ret;}void MParser_Reset(MParser *parse){ MsgParser *p = (MsgParser*)parse; if (p) { InitState(p); }}void MParser_Del(MParser *parse){ MsgParser *p = (MsgParser*)parse; if (p) { free(p->msg); free(p); }}测试一:test.c#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include "msg_parser.h"int main(){ MParser *p = MParser_New(); char buf[] = {0x00, 0x01, 0x00, 0x02, 0x00}; char another[] = {0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04}; char data[] = {0x11, 0x12, 0x13, 0x14}; Message *m = MParser_ReadMem(p, buf, sizeof(buf)); int i = 0; if (!m) { printf("parse again...\n"); m = MParser_ReadMem(p, another, sizeof(another)); } if (!m) { printf("parse again again...\n"); m = MParser_ReadMem(p, data, sizeof(data)); } printf("m = %p\n", m); if (m) { printf("type = %d\n", m->type); printf("cmd = %d\n", m->cmd); printf("index = %d\n", m->index); printf("total = %d\n", m->total); printf("length = %d\n", m->length); for (i=0; i<m->length; ++i) { printf("0x%02x ", m->payload[i]); } printf("\n"); free(m); } MParser_Del(p); return 0; }输入:parse again...parse again again...m = 0x555e21dd56a0type = 1cmd = 2index = 3total = 4length = 40x11 0x12 0x13 0x14测试2:client.c#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <malloc.h>#include "message.h"static void hton(Message *m){ m->type = htons(m->type); m->cmd = htons(m->cmd); m->index = htons(m->index); m->total = htons(m->total); m->length = htonl(m->length); }int main(){ int sock = 0; struct sockaddr_in addr = {0}; int i = 0; char *test = "D.T.Software"; Message *pm = NULL; sock = socket(PF_INET, SOCK_STREAM, 0); if (sock == -1) { printf("socket error\n"); return -1; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(8888); if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) { printf("connect error\n"); return -1; } printf("connect success\n"); for (i=0; i<strlen(test); ++i) { char buf[2] = {0}; buf[0] = test[i]; pm = Message_New(128, 129, i, strlen(test), buf, 2); hton(pm); send(sock, pm, sizeof(Message) + 2, 0); free(pm); } close(sock); return 0;}server.c#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netinet/tcp.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <malloc.h>#include "msg_parser.h"int main(){ int server = 0; struct sockaddr_in saddr = {0}; int client = 0; struct sockaddr_in caddr = {0}; socklen_t asize = 0; int len = 0; char buf[32] = {0}; int r = 0; MParser *parser = MParser_New(); server = socket(PF_INET, SOCK_STREAM, 0); if (server == -1) { printf("server socket error\n"); return -1; } saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl(INADDR_ANY); saddr.sin_port = htons(8888); if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) { printf("server bind error\n"); return -1; } if (listen(server, 1) == -1) { printf("server listen error\n"); return -1; } printf("server start success\n"); while (1) { struct tcp_info info = {0}; int l = sizeof(info); asize = sizeof(caddr); client = accept(server, (struct sockaddr*)&caddr, &asize); if (client == -1) { printf("client accept error\n"); return -1; } printf("client: %d\n", client); do { getsockopt(client, IPPROTO_TCP, TCP_INFO, &info, (socklen_t*)&l); Message *m = MParser_ReadFd(parser, client); if (m) { printf("type = %d\n", m->type); printf("cmd = %d\n", m->cmd); printf("index = %d\n", m->index); printf("total = %d\n", m->total); printf("length = %d\n", m->length); printf("payload = %s\n", m->payload); printf("\n"); free(m); } } while (info.tcpi_state == TCP_ESTABLISHED); printf("client socket is closed\n"); close(client); } close(server); MParser_Del(parser); return 0;}输入:server start successclient: 4type = 128cmd = 129index = 0total = 12length = 2payload = Dtype = 128cmd = 129index = 1total = 12length = 2payload = .type = 128cmd = 129index = 2total = 12length = 2payload = Tclient socket is closed有了协定和协定解析器之后,能够干嘛?

May 4, 2022 · 6 min · jiezi

关于c:Linux网络开发必学教程9应用协议解析模块上

问题:如何在代码层面封装协定细节?如何将接收缓冲区中的数据解析为 Message ?深度思考数据是否可能解析成为 Message ?数据量足够 如果数据量足够,是否可能解析不止一个 Message?如何解决残余数据 (属于下一个 Message)数据量有余 是否达到协定最小长度(12 字节)?如何解决数据量超过最小长度,但不足以创立一个 Message 的状况?初步的解决方案定义一个模块用于从字节流解析 Message可 从指定内存 或 从指定文件描述符 读取并解析当至多存在 12 个字节时开始解析 首先解析协定中的头信息和数据区长度(length)依据数据区长度持续从字节流读取数据(payload)当协定数据解析实现时,创立 Message 并返回,否则,返回 NULL协定解析模块的初步设计解析器接口定义typedef void MParser;MParser *MParser_New();Message *MParser_ReadMem(MParser *parser, unsigned char *mem, unsigned int length);Message *MParser_ReadFd(MParser *parser, int fd);void MParser_Reset(MParser *parser);void MParser_Del(MParser *parser);解析器数据结构typedef struct msg_parser { Message cache; // 缓存已解析的音讯头 int header; // 标识音讯头是否解析胜利 int need; // 标识还剩多少字节能力实现解析 Message *msg; // 解析中的协定音讯(半成品)}MsgParser;条件:内存长度至多间断 12 个字节memcpy(&p->cache, mem, p->need);p->cache.type = ntohs(p->cache.type); // 从网络字节序转换为本机字节序p->cache.cmd = ntohs(p->cache.cmd);p->cache.index = ntohs(p->cache.index);p->cache.total = ntohs(p->cache.total);p->cache.length = ntohs(p->cache.length);mem += p->need;length -= p->need;p->header = 1;p->need = p->cache.length;从内存中读取 payload 中的数据(可读取屡次)if (!p->msg) { // 胜利创立音讯头之后, 创立 Message p->msg = malloc(sizeof(p->cache) + p->need); if (p->msg) { *p->msg = p->cache; }}if (p->msg) { unsigned int len = (p->need < length) > p->need : length; unsigned int offset = p->msg->length - p->need; memcpy(p->msg->payload + offset, mem, len); p->need -= len;}编程试验:协定解析模块初步设计msg_parser.h#ifndef MSG_PARSER_H#define MSG_PARSER_H#include "message.h"typedef void MParser;MParser *MParser_New();Message *MParser_ReadMem(MParser *parser, unsigned char *mem, unsigned int length);Message *MParser_ReadFd(MParser *parser, int fd);void MParser_Reset(MParser *parse);void MParser_Del(MParser *parse);#endifmsg_parser.c#include <malloc.h>#include <string.h>#include <arpa/inet.h>#include <unistd.h>#include "msg_parser.h"typedef struct msg_parser { Message cache; int header; int need; Message *msg;}MsgParser;MParser *MParser_New(){ MsgParser *ret = calloc(1, sizeof(MsgParser)); MParser_Reset(ret); return ret;}Message *MParser_ReadMem(MParser *parser, unsigned char *mem, unsigned int length){ Message *ret = NULL; MsgParser *p = (MsgParser*)parser; if (!p || !mem || !length) { return ret; } if (!p->header) { if (p->need <= length) { memcpy(&p->cache, mem, p->need); p->cache.type = ntohs(p->cache.type); p->cache.cmd = ntohs(p->cache.cmd); p->cache.index = ntohs(p->cache.index); p->cache.total = ntohs(p->cache.total); p->cache.length = ntohl(p->cache.length); mem += p->need; length -= p->need; p->header = 1; p->need = p->cache.length; ret = MParser_ReadMem(parser, mem, length); } } else { if (!p->msg) { p->msg = malloc(sizeof(p->cache) + p->need); if (p->msg) { *p->msg = p->cache; } } if (p->msg) { unsigned int len = (p->need < length) ? p->need : length; unsigned int offset = p->msg->length - p->need; memcpy(p->msg->payload, mem, len); p->need -= len; } if (!p->need) { ret = p->msg; p->msg = NULL; MParser_Reset(p); } } return ret;}Message *MParser_ReadFd(MParser *parser, int fd){ Message *ret = NULL; return ret;}void MParser_Reset(MParser *parse){ MsgParser *p = (MsgParser*)parse; if (p) { p->header = 0; p->need = sizeof(p->cache); free(p->msg); p->msg = NULL; }}void MParser_Del(MParser *parse){ MsgParser *p = (MsgParser*)parse; if (p) { free(p->msg); free(p); }}test.c#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include "msg_parser.h"int main(){ MParser *p = MParser_New(); char buf[] = {0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04}; char data[] = {0x11, 0x12, 0x13, 0x14}; Message *m = MParser_ReadMem(p, buf, sizeof(buf)); int i = 0; if (!m) { printf("parse again...\n"); m = MParser_ReadMem(p, data, sizeof(data)); } printf("m = %p\n", m); if (m) { printf("type = %d\n", m->type); printf("cmd = %d\n", m->cmd); printf("index = %d\n", m->index); printf("total = %d\n", m->total); printf("length = %d\n", m->length); for (i=0; i<m->length; ++i) { printf("0x%02x ", m->payload[i]); } printf("\n"); free(m); } MParser_Del(p); return 0; }思考:如何通过 socket 文件描述符实时解析协定数据?

May 3, 2022 · 3 min · jiezi

关于c:浙大版C语言程序设计第四版何钦铭颜晖-第5章-函数-课后习题答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 一、选择题 1.在 C 语言程序中,若对函数类型未加显式阐明,则函数的隐含类型为( )。 A. void B. double C. char D. int 答:D 解析:在不返回后果的函数定义中,void 不能省略;否则,函数类型被默认定义为 int 。 2.以下正确的说法是( )。 A.实参加其对应的形参独特占用一个存储单元 B.实参加其对应的形参各占用独立的存储单元 C.只有当实参加其对应的形参同名时才占用一个独特的存储单元 D.形参是虚构的,不占用内存单元 答:B 解析:依照 C 语言的规定,在参数传递过程中,将实参的值复制给形参。所以他们各自占用独立的存储单元。 3.以下不正确的说法是( )。 A.实参能够是常量、变量或表达式 B.实参能够是任何类型 C.形参能够是常量、变量或表达式 D.形参应与对应的实参类型统一 答:B 解析:实参和形参一一对应,数量应雷同,程序应统一。实参能够是常量、变量或表达式。 4.在函数调用 Fume(exp1, exp2+exp3, exp4*exp5) 中,实参的数量是( )。 A.3 B.4 C.5 D.语法错误 答:A 解析:参数应用逗号宰割,所以题目中是3个参数。 5.下列程序的输入后果是( )。 fun(int a, int b, int c){ c = a * b;}int main(void){ int c; fun(2, 3, c); printf("%d\n", c); return 0;}A.0 ...

April 29, 2022 · 7 min · jiezi

关于c:Linux网络开发必学教程8应用协议设计与实现

问题:上面的代码输入什么?为什么?printf("connect success\n");send(sock, "A", 1, 0);send(sock, "B", 1, 0);send(sock, "C", 1, 0);close(sock);do { r = recv(client, buf, sizeof(buf), 0); if (r > 0) { printf("Recv: %s\n", buf); }}while (1);close(client);残缺代码 client.c#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <unistd.h>#include <string.h>int main(){ int sock = 0; struct sockaddr_in addr = {0}; int len = 0; char buf[128] = {0}; char input[32] = {0}; int r = 0; sock = socket(PF_INET, SOCK_STREAM, 0); if (sock == -1) { printf("socket error\n"); return -1; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(8888); if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) { printf("connect error\n"); return -1; } printf("connect success\n"); send(sock, "A", 1, 0); send(sock, "B", 1, 0); send(sock, "C", 1, 0); close(sock); return 0;}残缺代码:server.c#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <unistd.h>#include <string.h>int main(){ int server = 0; struct sockaddr_in saddr = {0}; int client = 0; struct sockaddr_in caddr = {0}; socklen_t asize = 0; int len = 0; char buf[32] = {0}; int r = 0; server = socket(PF_INET, SOCK_STREAM, 0); if (server == -1) { printf("server socket error\n"); return -1; } saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl(INADDR_ANY); saddr.sin_port = htons(8888); if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) { printf("server bind error\n"); return -1; } if (listen(server, 1) == -1) { printf("server listen error\n"); return -1; } printf("server start success\n"); while (1) { asize = sizeof(caddr); client = accept(server, (struct sockaddr*)&caddr, &asize); if (client == -1) { printf("client accept error\n"); return -1; } printf("client: %d\n", client); do { r = recv(client, buf, sizeof(buf), 0); if (r > 0) { printf("Receive: %s\n", buf); } } while (r > 0); close(client); } close(server); return 0;}输入server start successclient: 4Receive: ABC小常识发送缓冲区 ...

April 29, 2022 · 3 min · jiezi

关于c:Linux网络开发必学教程7TCP-与-UDP

TCP/IP 分层构造 应用层:各个应用程序能够定义(应用)各种这样的协定传输层:确保收回的数据可能达到目标主机,实现数据传输网络层:填写数据包地址,抉择数据传输门路数据链路层:交融不同连贯形式的链路,屏蔽网络差别物理层:具体连贯形式,有线,无线,光纤...TCP/IP 工作形式 TCP/IP层次结构的特点下层依赖邻接上层的能力,上层只为间接邻接下层服务下层不晓得上层的工作机制,上层不论下层传输的数据内容不做跨层服务,层次结构中的角色缺一不可 深刻了解网络层(IP层)IP 寻址:IP 地址属于网络层地址,用于标识网络上的主机路由管制:控制数据如何达到主机(如:须要通过哪些路由器转发)无连贯:数据包依据 IP 地址在网络上传递(无需与指标主机建设连贯)Mac 地址:数据链路层所应用的硬件地址Mac 地址与网络无关,出厂时写入到网络设备中当主机从网络上每收到一个数据帧时,首先检查数据中的 MAC 地址。如果是发往本机的数据帧则收下,之后进行其余的解决;否则就将此帧抛弃,不再进行其余的解决。IP 地址和 MAC 地址IP 地址是动静的,不属于某个具体的硬件 (MAC 地址隶属于具体硬件)IP 地址是网络层应用的地址(用于跨网络投递数据包)MAC 地址是数据链路层应用的地址(用于确定指标网络中接收数据的主机)路由器中记录了本网络中主机 IP 地址与 MAC 地址的映射关系(ARP协定实现)IP 路由管制为了将数据发给指标主机,所有主机都保护着一张路由表路由表记录了 IP 数据包下一步应该发给哪个路由器 IP 数据转发IP 包转发用的是 ”尽力服务“ 策略 ”尽力服务“ 指 ”会致力“, 但不保障后果转发时会通过附加信息检查数据合法性,但出现异常不会进行重发以包为单位进行转发,不保障达到(收回之后,石沉网海)TCP/IP 网络层次结构是否能提供牢靠数据传输?传输控制协议 (Transmission Control Protocol)TCP 在协定实现上提供牢靠数据传输 TCP 不存在 ”数据包“ 的概念,实现了流式传输 (数据如流水,无头无尾)TCP 外部有服务状态,可能准确晓得数据是否曾经发送胜利,是否被接管...TCP 在行为上可进行阻塞管制(网络环境变差时,可能调整数据发送速度)TCP 连贯建设 问:三次交互完结后,建设连贯,为什么是三次?答:避免旧的反复连贯引起连贯凌乱问题比方在网络环境比较复杂的状况,客户端可能会间断发送屡次申请。如果只设计成两次握手的状况,服务端只能一接管申请,而后返回申请信息,也不晓得客户端是否申请胜利。这些过期申请的话就会造成网络连接的凌乱。所以设计成三次握手的状况,客户端在接管到服务端SEQ+1的返回音讯之后,就会晓得这个连贯是历史连贯,所以会发送报文给服务端,通知服务端。所以TCP设计成三次握手的目标就是为了防止反复连贯。而后能够设计成四次握手?五次握手?不能够?答案是也是能够的,不过为了节俭资源,三次握手就能够符合实际状况,所以就没必要设计成四次握手、五次握手等等状况 TCP 的天生缺点 (DDoS攻打)客户端收到 SYN,ACK 之后,不再回复最初的 ACK 音讯这将导致服务端耗费资源,但并不会理论进行通信当多个傀儡客户端同时对服务端进行 ”连贯申请“,服务端资源将耗尽 TCP 连贯断开 问:四次交互完结后,连贯断开,为什么是四次?答:因为TCP是全双工通信的第一次挥手:当被动方发送断开连接的申请(即FIN报文)给被动方时,仅仅代表被动方不会再发送数据报文了,但被动方仍能够接收数据报文。第二次挥手:被动方此时有可能还有相应的数据报文须要发送,因而须要先发送ACK报文,告知被动方“我晓得你想断开连接的申请了”。这样被动不便不会因为没有收到应答而持续发送断开连接的申请(即FIN报文)第三次挥手:被动方在解决完数据报文后,便发送给被动方FIN报文;这样能够保障数据通信失常牢靠地实现。发送完FIN报文后,被动方进入LAST_ACK阶段(超时期待)。第四挥手:如果被动方及时发送ACK报文进行连贯中断的确认,这时被动方就间接开释连贯,进入可用状态。 UDP 的特点:齐全继承网络层工作形式无需连贯,间接指定 IP 地址和端口即可发送数据监听固定端口,只有有数据,通通接管不论网络状况,只有有数据通通可发送不关怀数据是否达到UDP 的应用场合对数据不敏感,须要实时性的场合(如:直播,实时游戏)网络环境比拟好的场合(如:物联网家居)须要深度定制协定的场合(如:”不丢包的“UDP协定)TCP 与 UDP 的区别TCP: 瓶口到嘴上了吗?瓶口到嘴上了吗?瓶口到嘴上了吗?好,给你喝水。UDP:给你给你都给你,我懒得管你喝不喝失去。 ...

April 28, 2022 · 1 min · jiezi

关于c:Linux网络开发必学教程6Window-下的网络编程

socket 接口已普遍存在于古代操作系统中Windows 下的 socket 编程接口与 Linux 中简直雷同不同之处 返回类型不同(句柄类型)句柄不是文件描述符,Window 中并不是所有接文件 (因而 windows 下对于 socket 无奈应用 send、recv)Windows 下 socket() 的用法SOCKET s = {0};s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // IPPROTO_TCP 明确指明创立 TCP 协定的套接字if (s == INVALID) { // 创立套接字时出错,返回 INVALID_SOCKET ERROR("..."); return -1;}Windows 网络编程接口#include <winsock2.h> 函数原型性能形容SOCKET socket(int af, int type, int protocal);创立套接字,为网络连接做筹备int connect(SOCKET s, const struct sockaddr *addr, int len);连贯指定地址的近程设施int send(SOCKET s, const char *buf, int len, int flags);发送数据到近程设施int recv(SOCKET s char *buf, int len, int flags);接管近程设施发回的数据int closesocket(SOCKET s);敞开连贯,销毁套接字int bind(SOCKET s, const struct sockaddr *addr, int len);将套接字与指定地址进行关联int listen(SOCKET s, int backlog);将套接字推入监听状态,期待连贯SOCKET accept(SOCKET s, struct sockaddr *addr, int len);接管客户端连贯int shutdown(SOCKET s, int howto);敞开连贯,进行发送和接管closes 与 shutdown(Linux 下也存在) 的区别:shoutdown 不开释 socket 资源几点细微差别通过 WSAStartup() 初始化零碎环境(最先调用)socket(), accept() 谬误返回 INVALID_SOCKET (不可默认为 -1)bind(), listen() 谬误返回 SOCKET_ERROR (不可默认为 -1)connect(), send(),recv() 谬误返回 SOCKET_ERROR (不可默认为 -1)通过 WSACleanup() 革除零碎环境(最初调用)Windows 网络编程的非凡阐明在工程属性中设置链接 ws2_32.lib定义变量 WSADATA wd抉择 socket 版本并初始化 WSAStartup(MAKEWORD(2, 2), &wd) ...

April 28, 2022 · 5 min · jiezi

关于c:浙大版C语言程序设计第四版何钦铭颜晖-第4章-循环结构-课后习题答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 一、选择题 1.以下程序段( )不能实现求 s = 1+2+...+n-1。 A. int i, n, s=0;scanf("%d", &n);for(i=1; i<n; i++){ s=s+i;}B. int i,n,s=0;scanf("%d",&n);for(i=1; i<=n-1;++i){ s=s+i;}C. int i,n, s≈0;scanf("%d", &n);for(i=n-1;i>0;i--){ s=s+i;}D. int i,n,s=0;scanf("%d",&n);for(i=n-1;i>0;++i){ s=s+i;}答:D 解析: 选项 A、B、C 的代码都能够实现题目要求。然而选项 D 的代码执行起来是个死循环,i 的值从 n-1 开始,而后++i,循环的完结条件是 i>0,i 的值越加越大,始终大于 0,条件永远成立。实现的并不是从 1 累加到 n-1。 2.输出65 14 <Enter>,以下程序段的输入后果为( )。 int m, n;scanf("%d%d", &m,&n);while(m!=n) { while(m>n) m=m-n; while(n>m) n=n-m;}printf( "m=%d\n", m);A. m=3B. m=2C. m=1D. m=0 答:C 解析: m 的初始值为 65,n 的初始值为 14。第一个while 的条件 m!=n,是成立的。执行外面的循环体。 ...

April 28, 2022 · 11 min · jiezi

关于c:Linux网络开发必学教程5基于多路复用的服务端

问题:应用 select() 函数能够扩大服务端性能吗? 如果能够,具体怎么实现? 目前服务端的瓶颈剖析服务端大多数时候处于期待状态,无奈施展主机(设施)的最大性能 while (1) { // 阻塞,期待客户端连贯 client = accept(server, (struct sockaddr*)&caddr, &asize); printf("client: %d\n", client); do { // 阻塞,期待客户端数据 r = recv(client, buf, sizeof(buf), 0); if (r > 0) { printf("Receive: %s\n", buf); if (strcmp(buf, "quit") != 0) { len = send(client, buf, r, 0); } else { break; } } } while (r > 0); close(client);}解决方案:阻塞变轮询通过 select() 函数首先监听服务端 server_fd, 指标事件为 “连贯”(读)当事件产生(客户端连贯),则调用 accept() 承受连贯将 client_fd 退出监听范畴,指标事件为“数据接管”(读)循环查看各个被监听的文件描述符是否有事件产生实现形式 ...

April 27, 2022 · 3 min · jiezi

关于c:浙大版C语言程序设计第四版何钦铭颜晖-第3章-分支结构-课后习题答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 一、选择题 1.有一函数 $$y = \begin{cases}1 & (x \gt 0) \\ 0 & (1 = 0) \\-1 & (x \lt 0)\end{cases}$$ 以下程序段中谬误的是( )。 A. if(x>0)y=1;else if(x==0)y≈0;else y=-1;B. y=0;if(x>0)y=1;else if(x<0)y=-1;C. y=0;if(x>=0);if(x>0)y=1;else y=-1;D. if(x>=0) if(x>0)y=1; else y=0;else y=-1;答:C 解析:依据函数, x 大于 0 ,y 的值为 1 。x 等于 0,y 的值为 0,x 小于 0,y 的值为 -1。选项 A,B,D 代码均正确。 2.对于变量定义: inta, b=0; 下列叙述中正确的是( )。A. a 的初始值是 0,b 的初始值不确定B. a 的初始值不确定,b 的初始值是 0C. a 和 b 的初始值都是 0D.a 和 b 的初始值都不确定 ...

April 27, 2022 · 6 min · jiezi

关于c:Linux网络开发必学教程4尝鲜-seclect-多路复用

问题:如何加强服务端能力,同时反对多个客户端?Linux 的设计哲学:所有皆文件 Linux 中的文件是什么?侠义: 文件系统中物理意义上的文件(逻辑上关联的数据汇合)狭义: 设施,通道,内存,。。。Linux 治理的所有对象了解文件描述符文件描述符是一个非负整数,实质是一个句柄所有对用户(程序员)通明的资源标识都能够看作句柄用户应用文件描述符(句柄)与内核交互内核通过文件描述符操作对应资源的数据结构所有皆文件的意义对立各种设施的操作形式(open,read,write,close)如: IO 设施(命令行,显示器)网络设备(网卡)...编程试验:以文件形式操作命令行#include <stdio.h>#include <unistd.h>int main(){ int iofd = 0; char s[] = "D.T.SoftWare\n"; int len = 0; write(iofd, s, sizeof(s)); len = read(0, s, 5); s[len] = 0; printf("%s\n", s); return 0;}输入: book@100ask:~/Desktop$ ./a.out D.T.SoftWare1234512345book@100ask:~/Desktop$ ...book@100ask:~/Desktop$ ./a.out D.T.SoftWare1234567812345 // 留神这里为什么只输入了 12345book@100ask:~/Desktop$ 678 // 留神这里为什么输入 678678: command not found答:在 a.out 应用程序中输出了"12345678",但应用程序只读取了 5 个字符,即"12345"。当应用程序完结,a.out所在终端获得所有权,失去 "678", 并尝试将其当作命令解析事件相干函数的分类阻塞式函数 函数调用后须要期待某个事件产生后才会返回非阻塞式函数 函数调用后可能及时返回(仅标记期待的事件)事件产生后以回调形式传递阻塞 VS 轮询轮询指依序拜访每一个相干设施是否须要服务的形式轮询可用于解决阻塞函数导致程序无奈继续执行的问题 神奇的 select() 函数select() 用于监督指定的文件符是否产生事件可通过轮询的形式检测指标文件(事件产生则标记发生变化)依据事件类型做出具体解决(如:读数据)int select(int maxfd, // maxfd = n(最大的文件描述符 ) + 1,标记监听的描述符范畴 [0 - maxfd-1] fd_set *readset, // 查看可读性 fd_set *writeset, // 查看可写性 fd_set *exceptset, // 查看异样 const struct timeval *timeout); // 期待 IO 的时长select() 函数的应用步骤 ...

April 26, 2022 · 2 min · jiezi

关于c:浙大版C语言程序设计何钦铭颜晖-第2章-用C语言编写程序-课后习题答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 一、选择题 1.改过下列程序中( )处谬误后,程序的运行后果是在屏幕上显示短句“ Welcome to You!"。 #include <stdio.h>int main(void){ printf(Welcome to You! \n") return 0;}A.1 B.2 C.3 D.4 答案:B 解析: printf() 函数是零碎提供的库函数,在系统文件stdio.h中申明。 printf() 函数的格局为: printf(格局管制字符串,输入参数1,...,输入参数n);所以,printf里的字符串要加双引号。 printf语句开端要以分号完结。 2.C语言表达式( )的值不等于1。 A. 123 / 100 B. 901%10 C.76%3 D.625%5 答案:D 解析: 选项A:123/100 的后果是 1 。123 除以 100,商 1 余 23 ,这里取商。 选项B:901%10 的后果是 1 。901除以10,商 90 余 1 ,这里取余数。 选项C:76%3 的后果是 1 。76 除以 3 ,商 25 余 1,这里取余数。 选项D:625%5 的后果是 0 。625 除以 5 ,商 125 余 0 ,这里取余数。 ...

April 26, 2022 · 5 min · jiezi

关于c:Linux网络开发必学教程3深入浅出-IP-地址

问题:网络编程接口中一些参数的意义是什么?sock = socket(PF_INET, SOCK_STREAM, 0);socket 参数详解int socket(int domain, int type, int protocal);参数意义domain套接字中应用的协定族信息type套接字数据传输类型信息prorocol设施间通信应用的协定信息socket() 中的 domain 参数(协定族)PF_INET → IPv4 互联网协议族PF_INET6 → IPv6 互联网协议族PF_LOCAL → 本地通信的协定族PF_PACKET → 底层数据收发协定PF_IPX → Novell 专用协定(互联网分组替换协定)...留神:不同协定中的地址表现形式可能不同,网络编程时地址类型必须和协定类型匹配socket() 中的 type 和 protocol 参数type : 用于指定协定类型 SOCK_STREAM : 流式数据 (TCP)SOCK_UGRAM : 报文式数据(UDP)protocol :用于指定协定族合乎类型的具体协定 domain 和 type 简直能够惟一确定一种协定,因而,这个参数通常为 0即:0 代表 domain 和 type 指定后的默认协定对于端口号和 IP 地址端口号是一个 2 字节数据(无符号)0 - 1024 作为特定端口被预约义(调配给特定应用程序)IP 地址是一个 4 字节无符号地址族 (可分为 5 类地址) 深刻解析 IP 地址IP 地址分为 网络标识 和 主机标识 两局部网络标识:标识网络主机(设施)所在的网络主机标识:标识网络主机(设施)的具体地址 ...

April 25, 2022 · 2 min · jiezi

关于c:Linux网络开发必学教程2服务端编程初体验

客户端/服务端 编程模式服务端长期保留于网络(公开本人的 IP 地址),并期待客户端连贯客户端发动连贯动作,并期待服务端回应特点: 服务端无奈被动连贯客户端客户端只能依照预约义的形式(协定)连贯服务端服务端编程模式1. 筹备网络连接2. 绑定端口3. 进入端口监听状态4. 期待连贯 服务端外围工作:绑定 & 监听 & 接管绑定:int bind(int sock, struct sockaddr *addr, socklen_t addrlen);监听:int listen(int sock, int backlog);接管:int accept(int sock, struct sockaddr *addr, socklen_t addrlen);深度分析服务端服务端 socket 只用于接管连贯,不进行理论通信当接管到连贯时,accept() 函数返回与客户端通信的 socket服务端 socket 产生用于通信的客户端 socket所以,socket 到底是什么玩意?如何了解?深刻了解 socket() 函数socket() 是什么? socket() 是一个多功能函数socket() 返回的又是什么? socket() 的返回值是用于通信的资源标识符socket() 还能做什么? socket() 可提供不同类型的通信性能(本地过程间通信)编程试验:服务端编程初体验#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <unistd.h>#include <string.h>int main(){ int server = 0; struct sockaddr_in saddr = {0}; int clinet = 0; struct sockaddr_in caddr = {0}; socklen_t asize = 0; int len = 0; char buf[32] = {0}; int r = 0; server = socket(PF_INET, SOCK_STREAM, 0); if (server == -1) { printf("server socket error\n"); return -1; } saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl(INADDR_ANY); saddr.sin_port = htons(8899); if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) { printf("server bind error\n"); return -1; } if (listen(server, 1) == -1) { printf("server listen error\n"); return -1; } printf("server start success\n"); asize = sizeof(caddr); clinet = accept(server, (struct sockaddr*)&caddr, &asize); if (clinet == -1) { printf("client accept error\n"); return -1; } printf("client: %d\n", clinet); len = 0; do { int i = 0; r = recv(clinet, buf, sizeof(buf), 0); if (r > 0) { len += r; } for (i=0; i<r; ++i) { printf("%c", buf[i]); } } while (len < 64); printf("\n"); send(clinet, "hello word!", 12, 0); sleep(1); close(clinet); close(server); return 0;}INADDR_ANY => "0.0.0.0", 示意本机的连贯全副承受(如,本机有多个网卡进而有多个 IP 时)客户端/服务端 编程的外围模式服务端长时间运行(死循环)接管客户端的申请客户端连贯后向服务端发送申请(协定数据) ...

April 25, 2022 · 3 min · jiezi

关于c:浙大版C语言程序设计第四版何钦铭颜晖-第1章-引言-课后习题答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 题目1:对C语言来说,下列标示符中哪些是非法的,哪些是不非法的? total,_debug, Large&Tall, Counter1, begin_答: 非法的: total、_debug、 Counter1、 begin_ 。不非法的: Large&Tall。解析: 一、什么是标识符?在 C 语言中,用来示意变量,函数,数据类型,语句等等这些,所应用的符号,就被称作标识符。 二、C 语言中对标识符的规定:1、C 语言的标识符,必须由字母,数字,下划线组成,其中第一个字符必须是字母或者下划线。 2、在 C 语言中,是辨别大小写的。 三、在 C 语言中,最次要的标识符是保留字和用户自定义的标识符。 1、保留字,也叫做关键字,是 C 语言规定的,并且有特定含意 和 有专门用处的标识符。 次要与和数据类型和语句无关。 2、用户自定义标识符。 就是用户本人定义的,个别用于变量名,数据类型名,函数名,符号常量名等等。 题目2: 改写 1.4 节中的流程图 1.2, 求 1一100 中能被 6 整除的所有整数的和。 <img src="https://img.chengxuka.com/WX20220401-163018@2x.png" alt="WX20220401-163018@2x" style="zoom:50%;" /> 解析: 对于 1.4 节中的流程图 1.2,是求 1-100 偶数和。流程图如下: <img src="https://img.chengxuka.com/WX20220421-152331@2x.png" style="zoom:50%;" /> 其实两道题的流程思路差不多。 题目3:改写 1.4 节中的程序,求 1-100 中能被 6 整除的所有整数的和,并在编程环境中验证该程序的运行后果。 解: 答案代码: #include <stdio.h>int main(void){ int i, sum = 0; for (i = 1; i <= 100; i++) if (i % 6 == 0) sum = sum + i; printf("sum=%d\n", sum); return 0;}运行后果: ...

April 25, 2022 · 1 min · jiezi

关于c:Linux网络开发必学教程1网络编程核心概念与模式

问题:如何进行网络编程?网络编程的实质应用操作系统提供的接口函数,使得应用程序具备收发网络数据的能力 网络接口在代码层面是操作系统提供的函数 网络编程只是一系列零碎函数的花式玩法应用程序通过网络接口应用操作系统的联网能力 网络编程是特定畛域(网络)的 C 语言程序设计协定:为进行数据通讯而预约义的数据规定地址:网络通讯中的用于标识设施的整数值(“xxx.xxx.xxx.xxx” 4字节整形值可示意,单为了更容易记忆,转换为字符串)端口号 设施为收发数据而指定的数值,用于示意具体连贯可了解为:设施中用于网络通讯的数据通道如:一台电脑往往只领有一个 IP 而又有多个应用程序,此时就应用端口进行辨别角色 服务端:期待连贯设施客户端:发动连贯的是恶被 ps : 一台设施可同时作为客户端和服务端 网络常识充电站网址就是 IP 地址吗? URL 是什么,域名又是什么? 网址不是 IP 地址,是指网络信息资源的地址(如:具体网页的地址),即:URL域名是 IP 地址的名别,多个域名能够指向同一个 IP 地址域名 → DNS → IP 地址协定肯定是看不懂的二进制数据吗? 协定是一种约定,即:事后定义的规定协定能够基于文本定义,也能够基于二进制定义小端系统:采纳小端模式(little-endian)的零碎,即:数据低字节放在内存低地址中0x12345678 int 4字节低地址 |78|56|34|12| 高地址 大端系统:采纳大端模式(big-endian)的零碎,即:数据低字节放在内存高地址中0x12345678 int 4字节低地址 |12|34|56|78| 高地址 网络字节序:网址字节程序采纳大端模式,所以,在小端系统中须要做字节转换网络编程模式1. 筹备连贯2. 连贯近程设施3. 收发数据4. 敞开丽娜姐 初探网络编程接口#include <sts/types.h>#include <sys/socket.h> 函数原型性能形容int socket(int domain, int type, int protocal);创立套接字,为网络连接做筹备int connect(int socket, struct sockaddr *addr, socklen_t len);连贯指定地址的近程设施ssize_t send(int fd, const void *buf, size_t n, int flags);发送数据到近程设施ssize_t recv(int fd, void *buf, size_t n, int flags);接管近程设施发回的数据int close(int fd);敞开连贯,销毁套接字编程试验:网络编程初体验#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <unistd.h>#include <string.h>int main(void){ int sock = 0; struct sockaddr_in addr = {0}; char *tosend = "GET /index.html HTTP/1.1\nHOST: www.dt4sw.com\nUser-Agent: TEST\nConnection: close\n\n"; int len = 0; char buf[128] = {0}; int r = 0; sock = socket(PF_INET, SOCK_STREAM, 0); if (sock == -1) { printf("socket error\n"); return -1; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("47.99.217.175"); addr.sin_port = htons(80); if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) { printf("connected error\n"); return -1; } printf("connect success\n"); len = send(sock, tosend, strlen(tosend), 0); printf("send bytes = %d\n", len); len = 0; do { int i = 0; r = recv(sock, buf, sizeof(buf), 0); if (r > 0) { len += r; } for (i=0; i<r; ++i) { printf("%c", buf[i]); } } while (r > 0); printf("\n"); printf("recv bytes = %d\n", len); return 0;}输入: ...

April 24, 2022 · 2 min · jiezi

关于c:c-语言-struct的内存对齐原则

如何计算得悉struct内存大小,这就要从内存对齐准则说起: 内存对齐第一准则构造体中元素是依照定义程序一个个放到内存中去的,但并不是严密排列的.每一个元素都认为内存是以它本人的大小来划分的,因而元素搁置地位肯定是元素内存宽度的整数倍上开始(从构造体首地址上向后找,找到第一个闲暇的残缺内存) struct X { char a; //[0] int b;//[4,7] double c;//[8,15]} S1;例如此例,a存入内存首地址第0个字节 存入b时,它先从构造体首地址查找,发现第一个4字节的空间被a占了一个,于是找下一个四字节空间,从第4个字节开始写入,到第7个字节完结. 存入c时,它先从构造体首地址以字节的大小查找,发现第一个8字节的空间被a、b占用,于是找一个8字节空间,于是从8字节写入到15字节完结 内存对齐第二准则构造体占用内存大小,满足内存大小必须为占用最大内存元素的内存大小的整数倍 struct X { char a; //[0] double b; //[8,15] int c;//[16,20]}S2;计算sizeof(S2)得24这是为什么呢,明明是只有20字节,这阐明必须满足最大元素的整数倍,所以留了最初4个字节是空白 留神:如果构造体里是个复合构造,比如说数组,那么会以数组元素内存宽度来做内存排布,如: struct label { int l_flags; union { void *l_ptr; long l_long; } l_perpolicy[N];};l_perpolicy是一个占用8*N内存大小的数组,那么在构造体label的内存排布是这样的,首先排l_flags,写入0~3内存空间,其次写入l_perpolicy的第一个元素,从构造体找第一个8字节空间发现写入了l_flags,于是向后找第二个8字节空间,也就是8~15写入数组的第一个元素,其余元素以此类推

April 24, 2022 · 1 min · jiezi

关于c:C语言程序设计谭浩强第五版-第10章-对文件的输入输出-习题答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 题目1:什么是文件型指针?通过文件指针拜访文件有什么益处? 答: 缓冲文件系统中,要害的概念是“文件类型指针”,简称“文件指针”。每个被应用的文件都在内存中开拓一个相应的文件信息区,用来寄存文件的无关信息(如文件的名字、文件状态及文件以后地位等)。这些信息是保留在一个构造体变量中的。该构造体类型是由零碎申明的,取名为FILE。所以,在C语言上,文件型指针就是指FILE类型的指针,它指向一个文件类型的构造,构造里蕴含着该文件的各种属性。 通过文件指针拜访文件的益处是:能够随机拜访文件,无效示意数据结构,动静分配内存,方便使用字符串,无效应用数组。 题目2:对文件的关上与敞开的含意是什么?为什么要关上和敞开文件? 答: 关上文件,是建设文件的各种相干信息,并使文件类型指针指向该文件,以便进行其它操作。而敞开文件操作可强制把缓冲区中的数据写入磁盘文件,保障文件的完整性,同时还将开释文件缓冲区单元和FILE构造,使文件类型指针与具体文件脱钩。 要对一个文件进行操作,必须先将其关上,读写结束后还要将其敞开,以避免不失常的操作。 ”关上“是指为文件建设相应的信息区(用来寄存无关文件的信息)和文件缓冲区(用来临时寄存输入的数据)。 ”敞开“是指撤销文件信息区和文件缓冲区,使文件指针变量不再指向该文件,显然就无奈进行对文件的读写了。 题目3:从键盘输入一个字符串,将其中的小写字母全副转换成大写字母,而后输入到一个磁盘文件 test中保留,输出的字符串以"!"完结。 解: 答案代码: #include <stdio.h>#include <string.h>#include <stdlib.h>int main(){ FILE *fp; char str[100]; int i = 0; if ((fp = fopen("test.txt", "w")) == NULL) { printf("can not open file\n"); exit(0); } printf("input a string:\n"); gets(str); while (str[i] != '!') { if (str[i] >= 'a' && str[i] <= 'z') str[i] = str[i] - 32; fputc(str[i], fp); i++; } fclose(fp); fp = fopen("test.txt", "r"); fgets(str, strlen(str) + 1, fp); printf("%s\n", str); fclose(fp); return 0;}运行后果: ...

April 24, 2022 · 9 min · jiezi

关于c:Linux网络开发必学教程0课程定位目标与安排

课前第一问:为什么要学习网络编程?实际必备技能:学完 C 语言之后想做点我的项目练手,能够吗?职业必备技能:招聘的任职技能时代必备技能 简直所有操作系统都反对网络性能简直所有 app 都须要联网能力工作互联网工夫 → 挪动互联网时代 → 物联网时代人工智能典型落地计划:云边协同推理...课程布局 课程学习路线 课程定位Linux 下的 socket 网络编程 问:只是 Linux 下的网络编程吗?答:也会在 Window 下进行试验把握根本的网络编程模式 问:学习网络编程须要先把握网络原理吗?答:不须要,课程中也不会做特地的解说课程目标以 Linux 零碎为次要平台,从 0 把握 socket 网络编程 把握网协定的实质以及 socket 的实质把握网络编程根底模型,如:C/S把握 TCP 和 UDP 网络编程不同平台网络编程实际...课程安顿socket 接口与 TCP 和 UDP 编程(数据收发)通信协定设计与实现案例开发:基于硬件平台的温湿度检测案例开发:HTTP服务器设计与实现Linux 系列课程初步布局Linux 网络编程(根底 & 进阶)Linux 文件编程(C 接口编程 & 零碎接口编程)Linux 多任务编程 (多过程 & 多线程)Linux 过程间通信...新篇章已开启,筹备好了吗?

April 24, 2022 · 1 min · jiezi

关于c:C语言程序设计谭浩强第五版-第9章-用户自己建立数据类型-习题解析与答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 题目1:定义一个构造体变量(包含年、月、日)。计算该日在本年中是第几天,留神平年问题。 解: 解题思路为:失常年份每个月中的天数是已知的,只有给出日期,算出该日在本年中是第几天是不艰难的。如果是平年且月份在 3 月或 3 月当前时,应再减少 1 天。平年的规定是:年份能被 4 或 400 整除但不能被 100 整除,例如,2000 年是平年,2100 年不是平年。 解法一: #include <stdio.h>struct{ int year; int month; int day;} date; //构造体变量 date中的成员对应于年、月、日int main(){ int days; // days 为天数 printf("input year,month,day:"); scanf("%d,%d,%d", &date.year, &date.month, &date.day); switch (date.month) { case 1: days = date.day; break; case 2: days = date.day + 31; break; case 3: days = date.day + 59; break; case 4: days = date.day + 90; break; case 5: days = date.day + 120; break; case 6: days = date.day + 151; break; case 7: days = date.day + 181; break; case 8: days = date.day + 212; break; case 9: days = date.day + 243; break; case 10: days = date.day + 273; break; case 11: days = date.day + 304; break; case 12: days = date.day + 334; break; } if ((date.year % 4 == 0 && date.year % 100 != 0 || date.year % 400 == 0) && date.month >= 3) days += 1; printf("%d/%d is the%dth day in %d.\n", date.month, date.day, days, date.year); return 0;}运行后果: ...

April 22, 2022 · 16 min · jiezi

关于c:C语言程序设计谭浩强第五版-第8章-善于利用指针-习题解析与答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 本章习题均要求用指针办法解决。 题目1:输出3个整数,按由小到大的程序输入。 解: 答案代码: #include <stdio.h>int main(){ void swap(int *p1, int *p2); int n1, n2, n3; int *p1, *p2, *p3; printf("input three integer n1,n2,n3:"); scanf("%d,%d,%d", &n1, &n2, &n3); p1 = &n1; p2 = &n2; p3 = &n3; if (n1 > n2) swap(p1, p2); if (n1 > n3) swap(p1, p3); if (n2 > n3) swap(p2, p3); printf("Now,the order is:%d,%d,%d\n", n1, n2, n3); return 0;}void swap(int *p1, int *p2){ int p; p = *p1; *p1 = *p2; *p2 = p;}运行后果: ...

April 21, 2022 · 20 min · jiezi

关于c:C语言程序设计谭浩强第五版-第7章-用函数实现模块化程序设计-习题解析与答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 题目1:写两个函数,别离求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数,并输入后果。两个整数由键盘输入。 解:设两个整数为 u 和 v,用辗转相除法求最大公约数的算法如下∶ ifv>u将变量 u与v的值调换 (使大者u为被除数) while(u/v的余数 r≠0){ u=v (使除数v变为被除数 u) v=r (使余数r变为除数 v)}输入最大公约数 r 最小公倍数1= u* v/最大公约数r 能够别离用以下两种办法∶
办法一:用两个函数 hcf 和 lcd 别离求最大公约数和最小公倍数。在主函数中输出两个整数 u 和 v,并传送给函数 hcf,求出的最大公约数返回主函数赋给整型变量 h,而后再把 h 和两个整数 u ,v 一起作为实参传递给函数 lcd,以求出最小公倍数,返回到主函数赋给整型变量 l。输入最大公约数和最小公倍数。
据此写出程序: #include <stdio.h>int main(){ int hef(int, int); //函数申明 int lcd(int, int, int); //函数申明 int u, v, h, l; scanf("%d,%d", &u, &v); h = hef(u, v); printf("H.C.F=%d\n", h); l = lcd(u, v, h); printf("L.C.D=%d\n", l); return 0;}int hef(int u, int v){ int t, r; if (v > u) { t = u; u = v; v = t; } while ((r = u % v) != 0) { u = v; v = r; } return (v);}int lcd(int u, int v, int h){ return (u * v / h);}运行后果: ...

April 20, 2022 · 13 min · jiezi

关于c:C语言程序设计谭浩强第五版-第6章-利用数组处理批量数据-习题解析与答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 题目1:用筛选法求100 之内的素数。 解: 所谓"筛选法"指的是"埃拉托色尼(Eratosthenes)筛法"。埃拉托色尼是古希腊的驰名数学家。他采取的办法是,在一张纸上写上1~1000 的全副整数,而后一一判断它们是否是素数,找出一个非素数,就把它挖掉,最初剩下的就是素数,见图6.1。 具体做法如下∶
(1)先将1挖掉(因为1不是素数)。
(2)用2除它前面的各个数,把能被2整除的数挖掉,即把2的倍数挖掉。 (3)用3除它前面各数,把3 的倍数挖掉。
(4)别离用4,5…各数作为除数除这些数当前的各数。这个过程始终进行到在除数前面的数已全被挖掉为止。例如在图6.1中找1~50 的素数,要始终进行到除数为 47为止。事实上,能够简化,如果须要找1~n 的素数,只须进行到除数为 $ \sqrt{n} $(取其整数)即可,例如对1~50,只须进行到将 $ \sqrt{7} $ 作为除数即可。请读者思考为什么。 下面的算法可示意为∶ (1)挖去1;
(2)用下一个未被挖去的数 p 除 p 前面个数,把 p 的倍数挖掉;
(3)查看p是否小于 $ \sqrt{n} $ 的整数局部(如果 n=1000,则查看 p<31 是否成立),如果是,则返回(2)继续执行,否则就完结; (4)剩下的数就是素数。
用计算机解此题,能够定义一个数组 a。a[1]~a[n] 别离代表1~n这 n 个数。如果查看出数组 a的某一元素的值是非素数,就使它变为 0,最初剩下不为 0 的就是素数。
程序如下: #include <stdio.h>#include <math.h> //程序中用到求平方根函数 sqrtint main(){ int i, j, n, a[101]; //定义a数组蕴含101个元素 for (i = 1; i <= 100; i++) // a[0]不必,只用a[1]~a[100] a[i] = i; //使 a[1]~a[100]的值为1~100 a[1] = 0; //先"挖掉"a[1] for (i = 2; i < sqrt(100); i++) for (j = i + 1; j <= 100; j++) { if (a[i] != 0 && a[j] != 0) if (a[j] % a[i] == 0) a[j] = 0; //把非素数“挖掉" } printf("\n"); for (i = 2, n = 0; i <= 100; i++) { if (a[i] != 0) //选出值不为0的数组元素,即素数 { printf("%5d", a[i]); //输入素数,宽度为5列 n++; //累积本行已输入的数据个数 } if (n == 10) { printf("\n"); n = 0; } } printf("\n"); return 0;}运行后果: ...

April 19, 2022 · 10 min · jiezi

关于c:C语言程序设计谭浩强第五版-第5章-循环结构程序设计-习题解析与答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 题目1:请画出例 5.6 中给出的3个程序段的流程图。 解∶上面别离是教材第5章例5.6给出的程序,据此画出流程图。 (1)程序1: #include <stdio.h>int main(){ int i, j, n = 0; for (i = 1; i <= 4; i++) // n用来累计输入数据的个数 for (j = 1; j <= 5; j++, n++) { if (n % 5 == 0) printf("\n"); //管制在输入5个数据后换行 printf("%d\t", i * j); } printf("\n"); return 0;}运行后果: 其对应的流程图见图5. 1。 (2)程序2: #include <stdio.h>int main(){ int i, j, n = 0; for (i = 1; i <= 4; i++) for (j = 1; j <= 5; j++, n++) { if (n % 5 == 0) printf("\n"); //管制在输入5个数据后换行 if (i == 3 && j == 1) break; //遇到第3行第1列,完结内循环 printf("%d\t", i * j); } printf("\n"); return 0;}运行后果: ...

April 18, 2022 · 11 min · jiezi

关于c:C语言使用指针找出二维数组中最大的值

1、题目现有如下二维数组,请找出其中最大的数。 要求: 1、不在子函数中输入。2、不能批改指定的子函数int GetMax(int* p, int m, int n)示例: 输出:1 2 9           4 9 8输入:max=92、残缺代码2.1 C语言版本#include <stdio.h>#define N 10int GetMax(int* p, int m, int n) { int ret = -0x3f3f3f3f; for (int i = 0; i < m; ++i) for (int j = 0; j < n; ++j) ret = max(ret, (p + i * N)[j]); return ret;}int max(a, b) { if (a >= b) return a; else return b;}int main() { int a[N][N]; for (int i = 0; i < 2; ++i) for (int j = 0; j < 3; ++j) scanf("%d", &a[i][j]); printf("max=%d", GetMax(a[0], 2, 3)); return 0;}2.2 C++版本#include <iostream>#define N 10using namespace std;int GetMax(int *p, int m, int n){ int ret = -0x3f3f3f3f; for(int i = 0; i < m; ++i) for(int j = 0; j < n; ++j) ret = max(ret, (p + i * N)[j]); return ret;}int max(a, b) { if (a >= b) return a; else return b;}int main(){ int a[N][N]; for(int i = 0; i < 2; ++i) for(int j = 0; j < 3; ++j) cin >> a[i][j]; cout << GetMax(a[0], 2, 3) << endl; return 0; }3、截图 ...

April 17, 2022 · 1 min · jiezi

关于c:C语言学习笔记实现简单的猜数字小游戏

C语言实现简略的猜数字小游戏在咱们学习完C语言根本数据类型以及运算、分支构造、循环构造、函数的基础知识当前,能够尝试写一点乏味的小游戏,实现非常简单,大家能够一起入手尝试起来哦~游戏实现C语言实现的猜数字游戏非常简略,次要由以下三个模块组成: 菜单模块游戏模块主函数模块须要援用的头文件本程序调用rand函数,心愿大家看到不要慌乱,应用办法简略,将在主函数模块提及,大家模拟应用即可,除此之外该程序无任何难点,大家肯定要本人尝试写一下哦~ 菜单模块void menu(){ //打印游戏菜单 printf("###################################\n"); printf("###################################\n"); printf("##########输出1:游戏开始##########\n"); printf("##########输出0:游戏完结##########\n"); printf("###################################\n"); printf("###################################\n");}游戏菜单实现非常简单,次要应用输入函数打印一个动态繁难的菜单,置信大家写过第一个C语言程序HelloWorld的话也肯定会写这个。 菜单模块打印一个文本提醒,无返回值,所以函数类型为空类型(void),也不须要任何的函数参数。 游戏模块void game(){ //定义并初始化guess 用来寄存玩家猜想的数字 int guess = 0; //调用rand函数生成随机数,而后管制生成一个1-100之间的随机数m int m = rand()%100+1; //开始猜数字游戏 直到猜对数字完结本轮游戏 while (1) { printf("请输出你猜的数字\n"); //输出玩家猜的数字 scanf("%d", &guess); //玩家所猜数字比随机生成数小 if (guess < m) printf("猜小了\n"); //玩家猜对数字打印猜对并完结本轮游戏 else if (guess == m) { printf("猜对了\n"); break; } ////玩家所猜数字比随机生成数大 else printf("猜大了\n"); }}game函数无返回值,所以函数类型为空。 实现思路:定义guess变量寄存玩家所猜数字,而后调用rand函数生成一个随机数m,应用while循环进行判断guess和m大小,玩家依据游戏提醒一直输出数字,直到猜对数字完结本轮游戏 主函数模块int main(){ int input = 0; //在调用 rand 之前,必须应用 srand 函数为伪随机数生成器进行种子化(语言规定的,这里不了解能够本人去百度深刻理解rand函数) //生成随机数时调用了time函数 依据本地工夫生成一个随机数(精确的说应该是工夫戳,这里不了解能够本人去深刻百度理解time函数) //srand函数的类型是unsign int,而time返回值类型为int,所以要进行强制类型转换 srand((unsigned int)time(NULL)); do { //调用游戏菜单函数 menu(); //用户抉择开始或完结 printf("请输出一个数字抉择是否开始->:\n"); scanf("%d", &input); if (input == 1) //调用游戏函数 game(); else if (input == 0) printf("游戏完结\n"); else printf("非法输出\n"); } while (input); return 0;}主函数模块依据本地工夫生成随机数,应用do-while循环依据用户输出进行相应的操作提醒。须要援用的头文件#include<stdio.h>#include<stdlib.h>#include<time.h>rand函数须要援用第二个头文件,time函数须要援用第三个头文件。

April 15, 2022 · 1 min · jiezi

关于c:跟着Redis学编程之字符串转长整数

前言作为C语言根底,在面试的时候,常常会被要求实现数值到字符串、或者字符串到数值的转换函数。尽管难度不大,然而很容易在一些细节上呈现纰漏。刚好最近在深度剖析Redis7.0源代码。空闲之余,顺带把这部分代码摘录进去,进行剖析、注解。作为一个学习记录的同时也不便后来者疾速理解Redis外部是如何实现的。日后面试兴许能用的上。 Redis实现形式代码片段正文int string2ll(const char *s, size_t slen, long long *value) { const char *p = s; //指向s开始地位 size_t plen = 0; // int negative = 0; //正数 unsigned long long v; /* 如果传递示意字符串长度参数为0,则无需转换,间接返回 0 */ if (plen == slen) return 0; /* 非凡状况, 只有一个字符,并且是0字母 */ if (slen == 1 && p[0] == '0') { if (value != NULL) *value = 0; return 1; } /* 字符串可能是示意带符号的整数,那么须要先解决符号。 */ /* 解决正数:仅仅是设置负号,而后就相似负数的解决形式进行解决 . 结束后转换成正数 */ if (p[0] == '-') { negative = 1; p++; plen++; /* 只有负号,即字符串是这样:"-", 这种字符串间接,异样退出 */ if (plen == slen) return 0; } /* 第一个字符必须是1-9,否则字符串应该是0 */ if (p[0] >= '1' && p[0] <= '9') { v = p[0]-'0';//转成整数 p++; plen++; } else { return 0; } /* 剖析剩下的所有字符,并且每一个步都查看是否溢出。 如果遇到非字符,则循环退出:p[0] <'0' || p[0] > '9' 字符串剖析结束,则循环退出:plen >= slen */ while (plen < slen && p[0] >= '0' && p[0] <= '9') { if (v > (ULLONG_MAX / 10)) /* 先判断溢出,在累加。如果计算后再判断,这时候曾经溢出掉了. */ return 0; v *= 10; if (v > (ULLONG_MAX - (p[0]-'0'))) /* 情理同上,这里咱们能够借鉴:判断溢出的形式. */ return 0; v += p[0]-'0'; p++; plen++; } /* 还有字符没有解决完,到这里其实就是下面的while循环条件, p[0]不是0-9的数字 */ if (plen < slen) return 0; /* 转换为正数,并且要查看溢出 */ /* 整个转换都是应用unsigned long long 作为长期值,最初保留的后果是有符号的,须要转换为 * long long ,这样在赋值和正数转变时候须要做溢出判断。 */ if (negative) { if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* 溢出检查 */ return 0; if (value != NULL) *value = -v; } else { if (v > LLONG_MAX) /* 溢出检查. */ return 0; if (value != NULL) *value = v; } return 1;}代码逻辑剖析小结string2ll整体思路是:解决符号,而后一一字符进行转换,从第一个字符开始转换,每一次转换都判断本次转换后的后果是否溢出,如果溢出就返回转换失败,否则就转换胜利,持续遍历下一个字符。 ...

April 15, 2022 · 2 min · jiezi

关于c:C语言程序设计谭浩强第五版-第4章-选择结构程序设计-习题解析与答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 题目1:什么是算术运算?什么是关系运算?什么是逻辑运算? 算术运算: 算术运算即“四则运算”,是加法、减法、乘法、除法、乘方、开方等几种运算的统称。 其中加减为一级运算,乘除为二级运算,乘方、开方为三级运算。在一道算式中,如果有多级运算存在,则应先进行高级运算,再进行低一级的运算。 C语言中的算熟运算符包含:+、-、*、/、++、--、% 等品种。 如果只存在同级运算;则从左至右的程序进行;如果算式中有括号,则应先算括号里边,再按上述规定进行计算。 示例:$ (1 + 1)^{2} * 4+5 * 3$ 解析: 先进行括号内运算1+1,而后进行乘方运算失去后果4.接下来与4相乘,失去后果16因为乘法优先级大于加法,因而先进行5*3,失去后果15最终相加失去后果31后果:31 关系运算: 关系的根本运算有两类:一类是传统的汇合运算(并、差、交等),另一类是专门的关系运算(抉择、投影、连贯、除法、外连贯等),而在C语言中,关系运算通常被认为是比拟运算,将两个数值进行比拟,判断比拟后果是否合乎给定的条件。 常见的关系运算符包含:<、<=、>、>=、==、!= 等品种。 其中,前4种关系运算符(<、<=、>、>= )的优先级别雷同,后2种(==、!=)也雷同。而前4种高于后2种。 例如, > 优先于 == 。而 > 与 < 优先级雷同。并且,关系运算符的优先级低于算术运算符,关系运算符的优先级高于赋值运算符(=)。 逻辑运算: 在逻辑代数中,有与、或、非三种根本逻辑运算。示意逻辑运算的办法有多种,如语句形容、逻辑代数式、真值表、卡诺图等。而在C语言中,逻辑运算通常用于应用逻辑运算符将关系表达式或其它逻辑量连接起来组成逻辑表达式用来测试虚实值。 常见的逻辑运算符包含:&&、||、! 等品种 &&: 与是双目运算符,要求有两个运算对象,示意两个运算对象都成立,则后果为真,否则后果为假。 例如:(a<b) && (x>y),示意(a<b)和(x>y)同时成立则为真。 ||:是双目运算符,要求有两个运算对象,示意两个运算对象只有任意一个成立,则后果为真,否则后果为假。 例如:(a<b) && (x>y),示意(a<b)和(x>y)两个对象中任意一个成立则后果为真。 !是单目运算符,只要求有一个运算对象,示意取运算对象反义,运算对象为真则后果为假,运算对象后果为假则后果为真。 例如:!(a>b),示意(a>b)成立时后果为假,不成立时后果为真。 若在一个逻辑表达式中蕴含多个逻辑运算符,则优先秩序为: ! > && > ||。当然若一个逻辑表达式中蕴含括号括起来的子逻辑,则优先括号内的子逻辑判断。 示例: (1>2)||(2>3)&&(4>3) 后果为0!(1>2)||(2>3)&&(4>3)后果为1 注:&&优先级大于||,((2>3)&&(4>3))无奈同时成立,则后果为假,而后与(1>2)后果进行逻辑或运算,两者都为假因而第一次后果为假。 而第二次!优先级最高,先对(1>2)的后果取逻辑非,失去后果为真,因而后果为真。 题目2:C语言中如何示意“真”和“假”?零碎如何判断一个量的“真”和“假”? 答案: 对于逻辑表达式,若其值为“真",则以1示意,若其值为“假”,则以0示意。然而在判断一个逻辑量的值时,零碎会以0作为“假”,以非0作为“真”。例如3 && 5的值为“真”,零碎给出3 && 5的值为1。 题目3:写出上面各逻辑表达式的值。设a=3,b=4,c=5。 (1) a+b>c && b==c (2) al|b十c && b-c (3) !(a>b) && !c || 1 (4) !(x=a) && (y=b) && 0 (5) !(a+b)+c-1 && b十c/2 ...

April 15, 2022 · 7 min · jiezi

关于c:C语言指针保存输入的9个数中所有的奇数并输出

1、题目编写一个函数,利用指针实现保留输出的9个数中所有的奇数并输入,若没有奇数则输入NO。 要求: 1、不在子函数中输入。2、不能批改指定的子函数void GetOdd(int a[], int b, int m)示例: 输出:1 4 7 2 5 8 3 6 9输入:1 7 5 3 9 输出:2 2 2 2 2 2 2 2 2输入:NO 2、残缺代码#include<stdio.h>#define N 10int a[N];int res[N];void GetOdd(int a[], int* b, int* m){ *b = 0; for (int i = i = 0; i < 9; ++i) { if (a[i] % 2 == 1) { m[*b] = a[i]; *b = *b + 1; } }}int main(){ int cnt; for (int i = 0; i < 9; ++i) scanf_s("%d", &a[i]); GetOdd(a, &cnt, res); if (cnt == 0) printf("NO"); else for (int i = 0; i < cnt; ++i) printf("%d ", res[i]); return 0;}3、截图 ...

April 14, 2022 · 1 min · jiezi

关于c:C语言生成10个随机种子为824的学生成绩用指针法统计低于均分的情况

1、题目在[0,100]范畴生成10个随机种子为824的学生问题。请你设计子函数实现指针法统计低于均分的状况。 要求: 1、应用子函数:void GetScore(int p, float avg, int* num) //p是指向原问题数组的指针,avg存储均分,num指针存储低于均分人数。2、应用指针法解决数据在子函数中实现统计,不容许在子函数中输入3、主函数中输入,输入分三行: 第一行输入原始问题第二行输入均分及低于均分总个数第三行输入低于均分的问题,保留一位小数示例: 输入:2 78 1 8 43 57 52 54 9 69           avg=37.3 num=4           2 1 8 92、残缺代码#include<stdio.h>#include<stdlib.h>void GetScore(int* b, float* avg, int* num){ int i; *num = 0; *avg = b[0]; for (i = 0; i < 10; i++) { *avg += b[i]; } *avg = *avg / 10; for (i = 0; i < 10; i++) { if (*avg >= b[i]) *num += 1; }}void main(){ int a[10], num; float avg; //种子824 srand(824); for (int i = 0; i < 10; i++) { // 0-100随机数 a[i] = rand() % 101; printf("%d ", a[i]); } GetScore(a, &avg, &num); printf("\navg=%.1f num=%d\n", avg, num); for (int i = 0; i < 10; i++) { if (a[i] < avg) printf("%d ", a[i]); }}3、截图 ...

April 14, 2022 · 1 min · jiezi

关于c:C语言学习笔记分支结构程序之if语句

分支构造程序之if语句家喻户晓,C语言是一种结构化程序设计语言。程序并不会总是执行同样的解决,例如程序会通过条件判断的后果选择性执行某种解决。接下来咱们一起学习依据条件扭转程序运行流程。if 语句1#include<stdio.h>int main(){ int n; //输入一个整数 scanf("%d",&n); //条件判断 0为假 非0为真 if(n%5) printf("输出的数字不能被5整除\n"); return 0;}if(表达式)语句会判断表达式的值,如果表达式的值非0,则会执行相应的语句;()中的表达式称为管制表达式,满足此表达式,后续语句则会则行,否则不执行。if 语句2#include<stdio.h>int main(){ int n; //输出一个整数 scanf("%d",&n); //判断奇偶 if(n%2==0) printf("这个数是偶数\n"); else printf("这个数是奇数\n"); return 0;}if(表达式) 语句1,else(表达式)语句2 else是否则的意思,当表达式1的值不为0的时候执行语句1,否则执行语句2; '==' 为相等运算符,属于双目运算符,对左右两侧的操作数进行比拟;与之对应的运算符是不等运算符 ‘!=’ if 语句3#include<stdio.h>int main(){ int m,n; //输出两个整数 scanf("%d %d",&m,&n); //判断大小 if(a>b) printf("a>b\n"); else if(a<b) printf("a<b\n"); else printf("a=b\n"); return 0;}if(表达式1)语句1,else if(表达式2)语句2,else(表达式3) 语句3; 表达式1的值不为0时,执行语句1,否则判断表达式2的值,若不为0则执行语句2,若为0则执行语句3; ‘>、<’ 为关系运算符,为双目运算符,对两侧操作数进行比拟。其余的关系运算符还有 ‘<=、>=’ 条件运算符语句#include<stdio.h>int main(){ int m,n,max; //输出两个整数 scanf("%d %d",&m,&n); //判断大小 max = m>n?m:n; printf("%d",max); return 0;}条件运算符属于三目运算符,须要三个操作数;a?b:c 若表达式a的值不为0,则后果为b,否则后果为c复合语句#include<stdio.h>int main(){ int m,n,max,min; printf("%d %d",m,n); if(m>n) { max = m; min = n; } else { max = n; min = m; } printf("最大值是%d,最小值是%d",max,min); return 0;}下面程序中的if语句在大括号内的语句称为复合语句或程序块;用{}括起来的复合语句也会被看做繁多的语句。逻辑运算符语句#include<stdio.h>int main(){ int month; scanf("%d",&month); if(month >= 3 && month <= 5) printf("%d是秋季\n"); else if(month >= 6 && month <= 8) printf("%d是冬季\n"); else if(month >= 9 && month <= 11) printf("%d是秋季\n"); else if(month == 1 || month == 2 || month ==12) printf("%d是夏季\n"); else printf("%d月不存在\n"); return 0;}上述语句应用的“&&”和“||”称为逻辑运算符; ...

April 14, 2022 · 1 min · jiezi

关于c:C语言程序设计谭浩强第五版-第3章-最简单的的C程序设计顺序程序设计-习题解析与答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 题目1:如果我国国民生产总值的年增长率为7%,计算10年后我国国民生产总值与当初相比增长多少百分比。计算公式为: $$p=(1+r)^n$$ r 为年增长率,n 为年数,p为与当初相比的倍数。 解:从主教材附录D(库函数)能够查到:能够用pow函数求$y^x$的值,调用pow函数的具体模式是pow(x,y)。在应用pow函数时须要在程序的结尾用# include指令将<math.h>头文件蕴含到本程序模块中。能够用上面的程序求出10年后国民生产总值是当初的多少倍。 答案代码: #include <stdio.h>#include <math.h>int main(){ float p, r, n; r = 0.07; n = 10; p = pow(1 + r, n); printf("p= %f\n", p); return 0;}运行后果: 即10年后国民生产总值是当初的1.967151倍。 题目2:贷款利息的计算。有1000元,想存5年,可按以下5种方法存: (1) 一次存5年期。 (2) 先存2年期,到期后将本息再存3年期。 (3) 先存3年期,到期后将本息再存2年期。 (4) 存1年期,到期后将本息再存1年期,间断存5次。 (5) 存活期存款。定期利息每-季度结算一次。 2017年的银行存款利息如下: 1年期定期存款利息为1.5%; 2年期定期存款利息为2.1%; 3年期定期存款利息为2.75%; 5年期定期存款利息为3%; 活期存款利息为0.35%(活期存款每一季度结算一次利息)。 如果 r 为年利率,n 为贷款年数,则计算本息和的公式如下: 1年期本息和: $P=1000* (1+r)$ ...

April 14, 2022 · 4 min · jiezi

关于c:C语言学习笔记数据类型与运算

C语言学习笔记_数据类型与运算我认为C语言是所有编程语言的根底,C生万物。我本科是软件工程,大一时早早就接触过C语言,但那时学习不够深刻,学习办法也有很大问题,导致编程根底很差。现如今考研失败,决定开始从新零碎学习编程,从C语言根底开始,笔记也只波及C语言根底局部,不会波及太深,因为我的学习方向是Java,接下来就是我的C语言学习笔记,绝不写半句废话,欢送各位一起学习交换以及批评指正~运算#include<stdio.h>int main(){ int x,y; scanf("%d %d",&x,&y); //加减运算符 printf("%d",x+y); printf("%d",x-y); //乘除运算符 //整数的除法运算只取商的整数局部,主动舍弃小数点局部 printf("%d",x*y); printf("%d",x/y); //取余运算符 //取余运算的操作数只能是整数(负整数取余没有意义) printf("%d",x%y); return 0;}像+、-、*、/、%这样能够进行运算的符号称为运算符,参加运算的变量或常量称为操作数用printf函数输入"%"这个符号的化,格式化字符串中要写%%;因为%有转换阐明的性能,当不须要进行转换阐明,只想输入%的时候,就要写成%%取余运算符的利用:#include<stdio.h>int main(){ //利用取余运算符求整数最初一位 int x; scanf("%d",&x); printf("x最初一位是:%d\n",x%10); return 0;}除法和取余运算的各种后果:除法运算和取余运算的后果都是依赖于编译器的两个操作数都是负数时:任何编译器商和余数都是负数两个操作数至多有一个为正数时:后果取决于编译器运算练习: #include<stdio.h>int main(){ //读取两个整数,输入前者是后者的百分之几 int x,y; scanf("%d %d",&x,&y); //%.0f这种用法前面会讲到 //(double)是类型转换 前面也会讲到 printf("x是y的%.0f%%",((double)x/y)*100); return 0;}单目运算符和三目运算符: 以上介绍的都是双目运算符,须要两个操作数,而单目运算符只须要一个操作数,三目操作数须要三个操作数。 常见的单目运算符有+、-、!、~ 三目运算符会在前面的条件运算中介绍 #include<stdio.h>int main(){ int x = 10; //+运算符其实没有什么理论运算 只是为了对应-运算符而设置的 printf("%d",+x); //对符号进行取反操作 printf("%d",-x); //非运算符 前面会介绍 printf("%d",!x); //位取反运算符 前面会介绍 printf("%d",~x); return 0;}C语言中“=”为赋值运算符,而“==”才为相等运算符程序中的一个语句都能够看做一个表达式,表达式必须要以;结尾,称为表达式语数据类型#include<stdio.h>int main(){ //int为整型变量,将9.99赋给x时,小数局部将会被抛弃,此时x=9 int x = 9.99; //double 为浮点型变量 double y = 9.99; //后果为4 printf("%d\n",x/2); //后果为4.995000 printf("%lf\n",y/2); return 0;}printf函数输入int型值的时候,转换阐明应用%dprintf函数输入double型值的时候,转换阐明应用%lf,%lf默认显示小数点后六位数字int 类型只能用来存储整数,即便把实数赋值给它,也只能保留整数局部double类型能够用来存储蕴含小数的实数数据类型之间的运算:进行整数/整数运算时,商的小数局部被舍弃,浮点数之间的运算则不会舍弃小数局部“int/int”与“double/double”这样两个雷同类型的操作数之间的运算,所得后果数据类型放弃不变“double/int”或“int/double”两个不同类型操作数之间的运算,int类型的操作数会进行隐式类型转换,主动向上转换为double型,运算演变成double类型之间的运算,所得后果也为double类型。这样的规定对于+、*等其余运算也实用强制类型转换:#include<stdio.h>int main(){ int a,b; scanf("%d %d",&a,&b); //强制类型转换,格局为:(类型名)a,把a的值转换为指定数据类型对应的值 printf("%lf",(double)(a+b)/2); return 0;}转换阐明书写格局:#include<stdio.h>int main(){ int a,b; int sum; double ave; scanf("%d %d",&a,&b); sum = a+b; ave = sum/2; printf("他们的总和为%05d\n",sum); printf("他们的平均值为%05.4f\n",ave); return 0;}%05d示意显示至多5位的十进制整数,0标记代表如果数值后面有空位用0补齐,若没有0标记则用空格补齐%05.4f示意显示至多5位的浮点数,然而小数点后只显示4位

April 13, 2022 · 1 min · jiezi

关于c:C语言用指针保存小于或等于lim的所有素数

1、题目编写一个函数,用指针保留小于或等于 lim 的所有素数 要求: 1、不要在子函数中输入2、不要批改子函数。应用子函数void GetPrime(int lim,intnum,intx)示例: 输出:20输入:num=82,3,5,7,11,13,17,192、残缺代码2.1 C语言版本#include <stdio.h>//宏定义布尔类型#define BOOL int#define TRUE 1#define FALSE 0#define N 100010BOOL st[N];void GetPrime(int lim, int* num, int* x){ for (int i = 2; i <= lim; ++i) { if (!st[i]) { x[*num] = i; (*num)++; } for (int j = 0; j < *num && i * x[j] <= lim; ++j) { st[i * x[j]] = TRUE; if (i % x[j] == 0) break; } }}void main(){ int x; int cnt = 0; int result[N]; BOOL flag = FALSE; scanf_s("%d", &x); GetPrime(x, &cnt, result); printf("num=%d\n", cnt); for (int i = 0; i < cnt; ++i) { if (flag) printf(","); else flag = TRUE; printf("%d", result[i]); } return 0;}2.2 C++版本#include <iostream>using namespace std;const int N = 1e5 + 10;bool st[N];void GetPrime(int lim, int *num, int *x){ for(int i = 2; i <= lim; ++i) { if(!st[i]) { x[*num] = i; (*num) ++; } for(int j = 0; j < *num && i * x[j] <= lim; ++j) { st[i * x[j]] = true; if(i % x[j] == 0) break; } }}int main(){ int x; int cnt = 0; int result[N]; bool flag = false; cin >> x; GetPrime(x, &cnt, result); printf("num=%d\n", cnt); for(int i = 0; i < cnt; ++i) { if(flag) printf(","); else flag = true; printf("%d", result[i]); } return 0;}3、截图 ...

April 13, 2022 · 2 min · jiezi

关于c:C语言程序设计谭浩强第五版-第2章-算法程序的灵魂-习题解析与答案

你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。 题目1:什么是算法?试从日常生活中找3个例子,形容它们的算法。 答: 算法:算法是计算机解决信息的实质,因为计算机程序实质上是一个算法来通知计算机确切的步骤来执行一个指定的工作。个别地,当算法在解决信息时,会从输出设施或数据的存储地址读取数据,把后果写入输出设备或某个存储地址供当前再调用。 算法是独立存在的一种解决问题的办法和思维。 对于算法而言,实现的语言并不重要,重要的是思维。 例如: 1、自驾去新疆游览 筹备好车,而后筹备游览路线等,开车登程,一路游山玩水。 2、网上买一部手机 首先选好网购平台(某宝,某东,某猫等),而后抉择想要的品牌和型号,下单,期待到货。 3、相亲 首先有七大姑八大姨等(如果没有能够抉择一些交友网站或其余媒婆),而后获取对方的联系方式和根本信息,登程达到目的地,相见,称心或不称心,决定了是否能够再约。 4、把大象放进冰箱 先关上冰箱门,而后将大象放进冰箱,关冰箱。 题目2:什么叫结构化的算法?为什么要提倡结构化的算法? 答: 结构化算法:由一些程序、抉择、循环等根本构造依照程序组成,流程的转移只存在于一个根本的范畴之内。 结构化算法便于编写,可读性高,批改和保护起来简略,能够缩小程序出错的机会,进步了程序的可靠性,保障了程序的品质,因而提倡结构化的算法。 题目3:试述3种根本构造的特点,请另外设计两种根本构造(要合乎根本构造的特点)。 解: 结构化程序设计办法次要由以下三种根本构造组成: 程序构造:程序构造是一种线性、有序的构造,它顺次执行各语句模块抉择构造:抉择构造是依据条件成立与否抉择程序执行的通路。循环构造:循环构造是反复执行一个或几个模块,直到满足某一条件地位 从新设计根本构造要满足以下几点: 只有一个入口只有一个进口构造内的每一部分都有机会执行到构造内不存在死循环 见图2.1和图2.2。 题目4:用传统流程图示意求解以下问题的算法。 (1)有两个瓶子A 和 B,别离盛放醋和酱油,要求将它们调换(即 A 瓶原来盛醋,现改盛酱油,B 瓶则相同)。 解:显然,如果只有两个瓶子,必定不能实现此工作,必须有一个空瓶C作为过渡,其步骤见图 2.3。 (2)顺次将10个数输人,要求输入其中最大的数。 解:流程图见图 2.4。 (3)有3个数a,b,c,要求按大小程序把它们输入。 解:流程图见图2.5。 (4)求1+2+3+……+ 100。 解:流程图见图 2.6。 (5)判断一个数n是否同时被3和5整除。 解:流程图见图 2.7(a)或图 2.7(b)。 (6)将100~200之间的素数输入。 解:流程图见图 2.8。 (7)求两个数m和n的最大公约数。 解:流程图见图 2.9。 (8)求方程式ax2+ bx+c=0的根。别离思考: ①有两个不等的实根; ②有两个相等的实根。 ...

April 13, 2022 · 2 min · jiezi

关于c:自学51单片机-矩阵按键实验

1、开发板原理图 2、程序2.1 行列式扫描法/**************************************************************************************试验名称:矩阵按键试验接线阐明: 试验景象:下载程序后,按下“矩阵按键”模块中S1-S16键,对应数码管最右边显示0-F注意事项: ***************************************************************************************/#include "reg52.h"typedef unsigned int u16; //对系统默认数据类型进行重定义typedef unsigned char u8;#define KEY_MATRIX_PORT P1 //应用宏定义矩阵按键管制口 #define SMG_A_DP_PORT P0 //应用宏定义数码管段码口u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //共阴极数码管显示0~F的段码数据/******************************************************************************** 函 数 名 : delay_10us* 函数性能 : 延时函数,ten_us=1时,大概延时10us* 输 入 : ten_us* 输 出 : 无*******************************************************************************/void delay_10us(u16 ten_us){ while(ten_us--); }/******************************************************************************** 函 数 名 : key_matrix_ranks_scan* 函数性能 : 应用行列式扫描办法,检测矩阵按键是否按下,按下则返回对应键值* 输 入 : 无* 输 出 : key_value:1-16,对应S1-S16键, 0:按键未按下*******************************************************************************/u8 key_matrix_ranks_scan(void){ u8 key_value=0; KEY_MATRIX_PORT=0xf7;//给第一列赋值0,其余全为1 if(KEY_MATRIX_PORT!=0xf7)//判断第一列按键是否按下 { delay_10us(1000);//消抖 switch(KEY_MATRIX_PORT)//保留第一列按键按下后的键值 { case 0x77: key_value=1;break; case 0xb7: key_value=5;break; case 0xd7: key_value=9;break; case 0xe7: key_value=13;break; } } while(KEY_MATRIX_PORT!=0xf7);//期待按键松开 KEY_MATRIX_PORT=0xfb;//给第二列赋值0,其余全为1 if(KEY_MATRIX_PORT!=0xfb)//判断第二列按键是否按下 { delay_10us(1000);//消抖 switch(KEY_MATRIX_PORT)//保留第二列按键按下后的键值 { case 0x7b: key_value=2;break; case 0xbb: key_value=6;break; case 0xdb: key_value=10;break; case 0xeb: key_value=14;break; } } while(KEY_MATRIX_PORT!=0xfb);//期待按键松开 KEY_MATRIX_PORT=0xfd;//给第三列赋值0,其余全为1 if(KEY_MATRIX_PORT!=0xfd)//判断第三列按键是否按下 { delay_10us(1000);//消抖 switch(KEY_MATRIX_PORT)//保留第三列按键按下后的键值 { case 0x7d: key_value=3;break; case 0xbd: key_value=7;break; case 0xdd: key_value=11;break; case 0xed: key_value=15;break; } } while(KEY_MATRIX_PORT!=0xfd);//期待按键松开 KEY_MATRIX_PORT=0xfe;//给第四列赋值0,其余全为1 if(KEY_MATRIX_PORT!=0xfe)//判断第四列按键是否按下 { delay_10us(1000);//消抖 switch(KEY_MATRIX_PORT)//保留第四列按键按下后的键值 { case 0x7e: key_value=4;break; case 0xbe: key_value=8;break; case 0xde: key_value=12;break; case 0xee: key_value=16;break; } } while(KEY_MATRIX_PORT!=0xfe);//期待按键松开 return key_value; }/******************************************************************************** 函 数 名 : main* 函数性能 : 主函数* 输 入 : 无* 输 出 : 无*******************************************************************************/void main(){ u8 key=0; while(1) { key=key_matrix_ranks_scan(); if(key!=0) SMG_A_DP_PORT=gsmg_code[key-1];//失去的按键值减1换算成数组下标对应0-F段码 } }2.2 线翻转扫描法/**************************************************************************************试验名称:矩阵按键试验接线阐明: 试验景象:下载程序后,按下“矩阵按键”模块中S1-S16键,对应数码管最右边显示0-F注意事项: ***************************************************************************************/#include "reg52.h"typedef unsigned int u16; //对系统默认数据类型进行重定义typedef unsigned char u8;#define KEY_MATRIX_PORT P1 //应用宏定义矩阵按键管制口 #define SMG_A_DP_PORT P0 //应用宏定义数码管段码口u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //共阴极数码管显示0~F的段码数据/******************************************************************************** 函 数 名 : delay_10us* 函数性能 : 延时函数,ten_us=1时,大概延时10us* 输 入 : ten_us* 输 出 : 无*******************************************************************************/void delay_10us(u16 ten_us){ while(ten_us--); }/******************************************************************************** 函 数 名 : key_matrix_flip_scan* 函数性能 : 应用线翻转扫描办法,检测矩阵按键是否按下,按下则返回对应键值* 输 入 : 无* 输 出 : key_value:1-16,对应S1-S16键, 0:按键未按下*******************************************************************************/u8 key_matrix_flip_scan(void){ static u8 key_value=0; KEY_MATRIX_PORT=0x0f;//给所有行赋值0,列全为1 if(KEY_MATRIX_PORT!=0x0f)//判断按键是否按下 { delay_10us(1000);//消抖 if(KEY_MATRIX_PORT!=0x0f) { //测试列 KEY_MATRIX_PORT=0x0f; switch(KEY_MATRIX_PORT)//保留行为0,按键按下后的列值 { case 0x07: key_value=1;break; case 0x0b: key_value=2;break; case 0x0d: key_value=3;break; case 0x0e: key_value=4;break; } //测试行 KEY_MATRIX_PORT=0xf0; switch(KEY_MATRIX_PORT)//保留列为0,按键按下后的键值 { case 0x70: key_value=key_value;break; case 0xb0: key_value=key_value+4;break; case 0xd0: key_value=key_value+8;break; case 0xe0: key_value=key_value+12;break; } while(KEY_MATRIX_PORT!=0xf0);//期待按键松开 } } else key_value=0; return key_value; }/******************************************************************************** 函 数 名 : main* 函数性能 : 主函数* 输 入 : 无* 输 出 : 无*******************************************************************************/void main(){ u8 key=0; while(1) { key=key_matrix_flip_scan(); if(key!=0) SMG_A_DP_PORT=gsmg_code[key-1];//失去的按键值减1换算成数组下标对应0-F段码 } }3、后果 ...

April 11, 2022 · 2 min · jiezi

关于c:自学51单片机-独立按键实验

1、程序// 试验景象:下载程序后,按下“独立按键”模块中K1键,管制D1指示灯亮灭 // ,按下“独立按键”模块中K2键,管制D2指示灯亮灭// ,按下“独立按键”模块中K3键,管制D3指示灯亮灭 // ![请增加图片形容](https://img-blog.csdnimg.cn/1b8c0ea933df48e8b275340aaa7e8804.png),按下“独立按键”模块中K4键,管制D4指示灯亮灭 #include "reg52.h"typedef unsigned int uint16; //对系统默认数据类型进行重定义typedef unsigned char uint8;//定义独立按键管制脚sbit KEY1=P3^1; // K1sbit KEY2=P3^0; // K2sbit KEY3=P3^2; // K3sbit KEY4=P3^3; // K4//定义LED管制脚sbit LED1=P2^0; // D1sbit LED2=P2^1; // D2sbit LED3=P2^2; // D3sbit LED4=P2^3; // D4//应用宏定义独立按键按下的键值#define KEY1_PRESS 1#define KEY2_PRESS 2#define KEY3_PRESS 3#define KEY4_PRESS 4#define KEY_UNPRESS 0 /******************************************************************************** 函 数 名 : delay_10us* 函数性能 : 延时函数,ten_us=1时,大概延时10us* 输 入 : ten_us* 输 出 : 无*******************************************************************************/void delay_10us(uint16 ten_us) //消抖{ while(ten_us--); }/******************************************************************************** 函 数 名 : key_scan* 函数性能 : 检测独立按键是否按下,按下则返回对应键值* 输 入 : mode=0:单次扫描按键 mode=1:间断扫描按键* 输 出 : KEY1_PRESS:K1按下 KEY2_PRESS:K2按下 KEY3_PRESS:K3按下 KEY4_PRESS:K4按下 KEY_UNPRESS:未有按键按下*******************************************************************************/uint8 key_scan(uint8 mode){ static uint8 key=1; if(mode)key=1;//间断扫描按键 if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))//任意按键按下 { delay_10us(1000);//消抖10ms key=0; if(KEY1==0) return KEY1_PRESS; else if(KEY2==0) return KEY2_PRESS; else if(KEY3==0) return KEY3_PRESS; else if(KEY4==0) return KEY4_PRESS; } else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1) //无按键按下 { key=1; } return KEY_UNPRESS; }/******************************************************************************** 函 数 名 : main* 函数性能 : 主函数* 输 入 : 无* 输 出 : 无*******************************************************************************/void main(){ uint8 key=0; while(1) { key=key_scan(0); if(key==KEY1_PRESS)//检测按键K1是否按下 LED1=!LED1;//LED1状态翻转 else if(key==KEY2_PRESS)//检测按键K2是否按下 LED2=!LED2;//LED1状态翻转 else if(key==KEY3_PRESS)//检测按键K3是否按下 LED3=!LED3;//LED1状态翻转 else if(key==KEY4_PRESS)//检测按键K4是否按下 LED4=!LED4;//LED1状态翻转 } }2、后果 ...

April 9, 2022 · 1 min · jiezi

关于c:我的编程之路

我的编程之路_第一天我认为C语言是所有编程语言的根底,C生万物。我本科是软件工程,大一时早早就接触过C语言,但那时学习不够深刻,学习办法也有很大问题,导致编程根底很差。现如今考研失败,决定开始从新零碎学习编程,从C语言根底开始,笔记也只波及C语言根底局部,不会波及太深,因为我的学习方向是Java,接下来就是我的C语言学习笔记,绝不写半句废话,欢送各位一起学习交换以及批评指正~ 笔记目录: [✔] 初识C语言[ ] 数据类型与运算[ ] 分支构造程序[ ] 循环控制程序[ ] 数组[ ] 函数[ ] 根本数据类型[ ] 程序编写[ ] 字符串[ ] 指针[ ] 字符串和指针[ ] 构造体[ ] 文件解决[ ] 结束语初识C语言什么是C语言?C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计指标是提供一种能以繁难的形式编译、解决低级存储器、产生大量的机器码以及不须要任何运行环境反对便能运行的编程语言。只管C语言提供了许多低级解决的攻能,但依然放弃着良好跨平台的个性,以一个规范规格写出的C语言程序可在许多电脑平台上进行编译,甚至蕴含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台。具备国际标准语法(初始语法ANSI C),C语言是一门面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同。第一个C语言程序//我的第一个C语言程序//头文件 其中stdio是standard I/O (规范输入输出)的缩写#include<stdio.h>//一个工程中有且仅有一个main函数,是程序运行的入口int main(){ //输入函数,调用输入函数,通过括号中的实参来传递想要的内容,printf函数的第一个实参%d(十进制)指定输入格局,第二个实参显示10的值 //函数调用是申请进行解决的申请,而调用函数的一些辅助批示则通过实参收回 printf("%d",10); return 0;}//前面的内容为正文内容,编译器不会进行辨认,对程序的运行并没有任何影响。编程者用简洁的的语言标注在程序旁,进步程序可读性。 原则上语句必须以分号结尾,{ }中的语句会被程序执行。 如以上代码所示,通过字符序列创立的程序称为源程序,用来保留源程序的文件为源文件,字符序列创立的程序须要转换为计算机可能了解的位序列,也就是0和1序列,一个源程序的执行要通过编辑、编译、链接、运行。 #include<stdio.h>int main(){ printf("1+1等于%d\n",1+1); return 0;}printf 函数中逗号之前局部称为格式化字符串,也是该函数的第一个参数 格式化字符串中的%d指定实参要以十进制数的模式显示,这就是转换阐明,若没有转换阐明则原样输入 \n 代表换行的符号,输入时看不到\和n,而是输入一个看不到的换行符 变量和申明 如果应用变量,必须通过申明明确其类型和名称 #include<stdio.h>int main(){ //申明一个整形变量x,并进行初始化 //变量在生成的时候会被放入不确定的值,因而在申明变量最好进行初始化 //int是变量的类型 x是变量名 int x = 10 ; printf("x的值为:%d",x); return 0;}初始化和赋值其实有一点点不同,初始化时在生成变量的时候放入数值,而赋值则是在已生成的变量中放入数值输出和显示 #include<stdio.h>int main(){ int x; //格式化输出函数scanf,从键盘读取输出信息 //与printf函数不同,应用scanf函数变量名必须加& scanf("%d",&x); printf("%d",x); return 0;}输入函数puts ...

April 9, 2022 · 1 min · jiezi

关于c:COMP2401-simulator

COMP2401 - Assignment #5(Due: Wednesday, March 31st, 2021 @ 6pm)In this assignment, you will make a simulator for a singe 4-way traffic-monitor at an intersection thatuses multiple threads and allows multiple vehicles to connect to it … with each vehicle and traffic lightrunning as its own process.To begin this assignment, you should download ALL of the following files:• makefile – use this to compile everything.• simulator.c – this is the simulator program• simulator.h – contains definitions and structs that will be used throughout your code• trafficServer.c – this is the code to run the traffic server that communicates with the vehicles• movementTimer.c – this code updates the positions of the vehicles• trafficLight.c – this code simulates a traffic light• trafficLight.h – contains definitions for the code pertaining to traffic lights• vehicle.c – this is the code that runs a single vehicle• vehicle.h – contains definitions for the vehicle-related information• display.c – contains the window/drawing code that you will use to display everything• generator.c – this is the code that repeatedly generates vehicles• stop.c – this is the code that stops the server cleanly.There are 4 programs that you will be running:• simulator – runs the server that vehicles communicate with• stop – stops the server when run• vehicle – simulates a single vehicle• generator – generates a bunch of vehicles repeatedlyFollow the steps below (in order) to complete the assignment:(1) Use the makefile to compile everything. Run the simulator program. You should see theintersection showing with 4 red lights and nothing moving. A getchar() has been placed at thebottom of the main() in simulator.c so that you can stop the program either by pressingENTER in the terminal window or pressing the X on the simulator window.(2) Four traffic lights have been created in the main() function of simulator.c. Do not alter thiscode. However, you must add code to the main() function so that it creates 4 threads … onefor each traffic light. The thread should start by calling the runTrafficLight() function in thetrafficLight.c file. You will want to pass in a traffic light to that function. The code currentlyruns in an infinite loop doing nothing but pausing for half a second. The TrafficLight structhas been defined in trafficLight.h. Do not alter it. Add code to the function so that it makesthe traffic lights work properly by setting the currentState and countDownTimer values. Ifyou look at the trafficLight.h header, it also defines the following constants: ...

March 31, 2022 · 17 min · jiezi