分页: 29 / 31

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2017-12-17 21:38
243750496
sudo sh -c 'echo "deb https://atlassian.artifactoryonline.com ... apt-client $(lsb_release -c -s) main" > /etc/apt/sources.list.d/atlassian-hipchat4.list'

wget -O - https://atlassian.artifactoryonline.com ... key/public | sudo apt-key add -

sudo apt-get update

sudo apt-get install hipchat4

推荐个软件:
gravity designer(Illustrator的替代品,Linux+Mac+Windows+Web)
改头像:community->点击头像->齿轮图标(Preference)->Account->Profile Picture

推荐VPN:
Nord VPN(Purevpn不行了):99美元/3年

photoshop延时显示的bug在configure wine中设置为xp系统即可解决


illustrator中dash line的使用方法:
stroke_5382_3467.jpg
stroke_5382_3467.jpg (46.65 KiB) 查看 17583 次
06tyi91_3840.gif
06tyi91_3840.gif (4.34 KiB) 查看 17583 次

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2017-12-29 20:25
243750496
现代编程语言是用什么语言写成

对于脚本型语言通常是c写的,包括解析器(编译器和执行器)和大部分基础的标准库(比较高阶的库才会用本语言写)。从这个意义上来说,脚本语言只是c的wrapper,正因为如此,所以才会有人喊python的sort居然比go快之类的说法,其实就算是python的sort快,那也只证明了c比go快。但也有一些语言的解析器用c++写(比如V8)。
对于编译型语言,通常编译器也是c写的(但编译器对性能要求不高,理论上可以用任何语言完成)。执行器则分为两种情况:一种编译为机器码的,执行器自然是cpu(比如c++、go这类)。另一种编译为bytecode的,这种执行器一般用c写,但是由于性能方面的考虑,通常会执行器(也就是vm)会把bytecode变成机器码让cpu直接执行。至于标准库,编译型语言通常倾向于用本语言完全重写,而不是去依赖c库。
Go语言是编译型语言里面比较奇葩的。由于Go语言的目标是成为下一个C语言,所以整个Go语言的实现过程中,尽量减少了对c语言的依赖,大部分的工具链都是用Go语言自身来完成。其基本思路是:用gcc或其他标准c的编译器,编译出一个Go特有的c编译器,然后用这个特有的c编译器,来编译Go语言工具链中那些不得不用c写的部分,包括go的编译器。
有人问c是用什么写的。实际上现在多数c编译器都是c写的,大家去看看gcc的代码就知道了。其实,现在汇编编译器一般也是c写的。
从鸡生蛋的角度,编译器的进化史应该是这样的:先用机器码直接写第一个汇编编译器,然后汇编编译器编出第一个c编译器。有c编译器后可以反过来用c重写汇编编译器和c编译器,做更多的功能增强。这个过程理论上每出现一种新cpu指令集、新操作系统就需要重新来一遍。但是人是聪明的。所以交叉编译这样的东西产生了,这就避免需要把整个编译器进化史重新演绎一遍。



什么是交叉编译????????

举个例子来解答。
我们的电脑PC的CPU是intel或者AMD的,这种CPU全部是x86架构的,内在指令是一样的。
而嵌入式linux的CPU一般是ARM的,这种CPU的指令架构和x86完全不同。
如果,你在电脑上写了个C语言程序,然后编译运行,但是这种程序只能在PC上,也就是intel或AMD的CPU上运行。你下载到ARM的机器上是不能运行的。
如果想要运行,就要在PC上根据ARM的指令架构来编译程序。
这种在这种架构的CPU机子上编译另外一种架构CPU的软件,就叫做“交叉”编译。交叉CROSS就是这个意思。


怎么用C++写图形界面程序?
我说的不是控制台,就是有边界有框,正常一点的界面


看的人比较多,所以我觉得还是完善一下回答比较好!//2017年10月17日0点28分

这个问题问得非常好,虽然问题中的描述不准确,但我们都知道他想问的问题是什么意思:就是怎样用C++写一个有窗体界面的程序(很有可能是指在Windows下)。先回答一下这个问题,答案在这儿:从WinMain开始

回想当年,我初学C语言的时候,也有这样的困惑:为啥我写的程序背景是黑不溜秋的,文字也是一行一行显示的,而别人写的程序都带着界面和按钮?

这得从何说起呢?

由于我们最常接触的就是Windows系统中各种带有窗体的程序,使得很多人误以为,这就是程序原本的样子……其实程序原本是没有界面的,就一堆代码在CPU里跑,之所以有界面,是因为人类自身的需要。人类发明了一些硬件设备,来展示程序的过程和结果,最常见的就是普通的电脑显示器。最早我们用一行行的文字来显示界面,俗称CLI(就是控制台,终端,命令行这类界面),随着科技的进步,后来我们发展出了更加人性化的图形界面,俗称GUI。但CLI并没有消失,甚至在某些应用场合,它比GUI方便得多。

其实代码的本质就是控制硬件,比如在显示器上显示一个点,其实是程序对某个硬件进行赋值操作(不同的硬件设备在程序里有着不同的地址,这就是总线结构),所以你要在屏幕上画个点,本质上就是往某个地址上写个值,简单来说就是这样。这个东西也叫作驱动程序。

通过控制屏幕显示各种各样不同的点,我们就可以弄出各种图案,比如窗口啊,按钮啊,文字啊,图片啊,2D或者3D动画啊,这个东西就叫作计算机图形学。

然而我们在Windows这种操作系统下开发程序,并不用关心怎么样去绘制一个窗口或文字,因为已经有人把这部分工作给我们做好了,并且封装成了一个个的函数或类,俗称API(应用程序接口),我们只要调用那个函数,告诉操作系统,给我画个窗口吧,它就屁颠屁颠的去帮你干活了,就是这么简单。

把一堆API打包装在一起,就变成了库。

在命令行上面显示“hello world”和在窗口上显示“hello world”的区别,只是使用了不同库中的不同API而已。对于程序员来说,并没有本质上的区别,仅仅只是调用的函数不一样。

所以,我们实际开发时,需要学习这些API怎么用,有哪些特点,这就属于应用开发的内容了,比如“Windows编程”,“wxWidget应用开发”等等等等……手机软件开发,也是一样的原理。所以,学完C++只是第一步,接下来,如何在相应的操作系统环境下开发软件,还需要学习相应的API。

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2018-03-05 19:27
243750496
固态硬盘的TRIM功能可以避免SSD在GC时将无用数据进行错误搬运,浪费读取时间,从而起到对固态硬盘寿命的延长作用的。但是,如果操作环境是在机械硬盘中,已删除文件系统会进行逻辑位置的标记,使得以后存储数据时能够直接在这些无用数据的逻辑位置上覆盖。但固态硬盘因为是闪存的原因所以没有这种机制,主控并不知道这些数据已经无用,直到有新的数据要求写入该块。这将导致无用数据在垃圾回收(GC)过程中被当作有用数据对待,这无疑会大大降低硬盘效率和使用寿命。因此TRIM的出现就能够弥补该问题的缺陷。


方法/步骤



1


首先检查自身电脑是否已经开启TRIM

只须一个命令就可查看,步骤如下:

在搜索栏中找到“命令提示符”并以管理员身份运行



win10中TRIM如何开启.

2


然后执行如下命令:

fsutil behavior query disabledeletenotify


如果返回值为“0”证明TRIM已经开启;如果返回值是“1”,则说明当前电脑的SSD尚未开启TRIM



win10中TRIM如何开启.

3


这个时候你就需要重新手动开启,请重新打开命令:

同样以管理员的身份运行“命令提示符”然后手动输入

fsutil behavior set disabledeletenotify 0

Win10下依然可用的软件
CleanMyPC
DataRescue
Picture Rescue
BatchPhoto
wiznote
ITunes
NordVPN
Adobe 系列
Alcohol (需要先付费然后在账户里下载可注册版本,否则有捆绑软件报毒,且无法注册只能试用)
DataColor系列(红蜘蛛、打印蜘蛛、48色卡)
dia(流程图,跨平台,免费,因此方便在任何地方安装和交流使用)
3D Coat
FastRawViewer(查看Raw图片+exif信息的好工具)
RawDigger(一个曝光是否准确的极为严谨的的检测软件)
PCMover(迁移旧PC到新PC的好工具)
Modo(商业3d软件)
steam上的Substance B2M+Designer+Painter(替代Mari,因为Mari现在只允许按月订阅1个软件,否则只能按年)
Autodesk Eagle(电路绘制软件)
BricsCAD
Bitwig Studio(音乐制作软件)
Discord(游戏语音工具)
Dacuda PocketScan(口袋扫描仪应用)
Cura Mostfun专版(Sail专用):机型->机型设置->端口Com3,波特率115200,文件->偏好配置->打印窗口类型:Pronterface UI,View Mode:Layers(如果这里显示不出来就说明是模型的问题而不是软件错误)
QQ
百度输入法(搜狗广告太多)
注:Alt+Shift为切换输入法快捷键
Wacom数位板驱动
罗技C930e驱动
微信
Kindle For PC
SketchBook
Guitar Pro 7
迅雷U享版(迅雷9广告太多了)
工商银行
ArtPose Pro(Steam上参考肌肉的好软件,30RMB)
Snipaste 类似Setuna的截屏参考软件(未来会推出linux版)
openCanvas7(windows下类似Sai画原画的好软件)steam上有 Preference->Documents->Touch Operation->Enable Touch Operation 取消勾选,就不会绘制时平移了
解剖参考(查看肌肉、骨骼的软件)visiblebody出品
Muscle Premium for Windows Desktop
Muscle Premium for Windows Desktop
Anatomy & Physiology for Windows Desktop
Open 3D Model Viewer(免费的查看3d模型的软件)
游戏:
Farm Together(农场)
Tale of Toast(网游)
打印机色彩管理设置(打印蜘蛛在执行打印前对打印机的设置):设置高光纸+选择高质量照片模式+去掉照片增强+去掉高速打印选项+使用ICM无色彩管理选项
主窗口.PNG
高级.PNG
L800 HYMN Diamond.icm->C:\Windows\System32\spool\drivers\color

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2018-03-22 12:31
243750496
关掉这些,让WIN10快成一道“闪电”

1、替换自带的杀毒软件Windows Defender

这款软件杀毒方面并不是很棒,而且我们使用也不习惯,建议选择第三方杀毒软件。安装后,系统自动关闭自带杀毒软件Windows Defender。因为它开启会消耗CPU资源!


2、关闭IPV6

这个除了大型网络能使用上,家庭或者在日常工作中很少几乎不使用,不光占用系统资源,同时也是很多问题的元凶。

操作:右键单击【此电脑】——【管理】——【计算机管理】,左侧菜单点【服务】,右侧窗口找到【IPHelper】,右击并选择【属性】,将【启动类型】修改为【禁用】,保存即可


3、关闭家庭组

这个给家庭内部电脑共享文件用的,我们多数人家中一到两台电脑,也几乎用不到文件共享,故此功能也可关闭,开着也是占用CPU、导致卡顿的元凶之一。

操作:右键桌面【此电脑】——【管理】——【计算机管理】,在左侧菜单中点击【服务】,右侧窗格找到【HomeGroup Listener】和【HomeGroup Provider】两者都选择属性并禁用,保存!

4、关闭Windows Search

win10会自动在后台建立索引记录Windows Search。像个搜索引擎,搜索本机的所有文件,现在电脑大多数配备了固态盘(SSD)响应很快,Windows Search实际意义不大。

操作跟上方步骤前面相同,在【服务】右侧窗格找到【Windows Search】,右击属性并选择禁用。



5、设置自动登录

使用密码登录Windows的是一个内部安全机制,在家使用或者不担心重要资料外泄,建议关闭设置自动登录,也可加快Win 10运转

操作:点击任务栏左侧Cortana搜索框,输入【netplwiz】回车,选中当前账号,取消”要使用本计算机,用户必须输入用户名和密码“前面的复选框。点击确定后需要再次输入密码。以后就可直接登录电脑了,直接进入桌面!

6、自动优化驱动器

硬盘分为传统盘(HDD)和固态硬盘(SSD)两种。他们都需要定期的维护操作。简单说,HHD用磁盘碎片整理,SSD用则是TRIM。我设置为自动运行后,WIN10会自动根据磁盘类别进行适合的磁盘优化方式,这样大幅度降低系统日常运行时所产生的卡顿情况。

操作:打开【此电脑】,右击某一个硬盘驱动选择【属性】,点击【工具】——【优化】——【已计划的优化】——【更改设置】。保持【按计划运行】复选框勾选。



7、修改默认电源计划

win10自带三组电源模式,分别是”平衡“、”高性能“、”节能“。不同模式的功效不同。我们选这”高性能“发挥全部电脑性能

操作:右击开始按钮,点击【电源选项】——【其他电源选项】,将首选计划改为”高性能“,然后点击”高性能“右侧的【更改计划设置】——【更改高级电源设置】。将【无线适配器设置】修改为【最高性能】、【PCI Express】修改为【关闭】、【处理器电源管理】——【处理器最大频率】修改为【当前电脑CPU最高功率】。

8、开启快速启动

WIN 10具有“快速启动”功能,这项功能简化开机前的一系列检查步骤来提高Win 10的开机用时。

还有,开启“快速启动”后,Win 10还能在每次关机时,自动将一部分内存数据存储到硬盘上,下次开机可直接调用。从而进一步提升Win 10的开机速度。



操作:点击【开始】菜单——【设置】——【系统(显示、通知、电源)】——【电源和睡眠】——【其他电源设置】,在弹出的面板中点击【选择电源按钮的功能】——【更改当前不可用的设置】勾选【启动快速启动】。

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2018-03-27 22:54
243750496
windows10下编译gimp 2.10源码
下载MSYS2 64bit
运行:pacman -Syu如果按照gimp上说的pacman -Sy pacman则会出现无反馈的情况
然后提示关闭
然后再运行一遍
pacman -Syu
正式进入依赖安装(有的依赖不安会导致其他依赖无法安装从而导致安装失败,所以如果有哪个依赖安装失败就重新执行此命令1遍)
pacman -S mingw-w64-x86_64-atk mingw-w64-x86_64-babl mingw-w64-x86_64-cairo mingw-w64-x86_64-fontconfig mingw-w64-x86_64-freetype mingw-w64-x86_64-gdk-pixbuf2 mingw-w64-x86_64-gegl mingw-w64-x86_64-glib-networking mingw-w64-x86_64-gtk3 mingw-w64-x86_64-harfbuzz mingw-w64-x86_64-libjpeg-turbo mingw-w64-x86_64-libmypaint mingw-w64-x86_64-libpng mingw-w64-x86_64-poppler mingw-w64-x86_64-librsvg mingw-w64-x86_64-libtiff mingw-w64-x86_64-lcms2 mingw-w64-x86_64-libmypaint mingw-w64-x86_64-poppler-data mingw-w64-x86_64-jasper mingw-w64-x86_64-libmng mingw-w64-x86_64-libwebp mingw-w64-x86_64-libwmf mingw-w64-x86_64-icoutils mingw-w64-x86_64-tkimg mingw-w64-x86_64-openexr mingw-w64-x86_64-python2 mingw-w64-x86_64-webkitgtk3 libtool mingw-w64-x86_64-gtk-doc automake1.15 intltool autoconf gtk-doc glib2-devel mingw-w64-x86_64-gtk-engines mingw-w64-x86_64-python3-gobject mingw-w64-x86_64-gtk3 mingw-w64-x86_64-glade mingw-w64-x86_64-devhelp mingw-w64-x86_64-python3-gobject mingw-w64-x86_64-python2-gobject mingw-w64-x86_64-toolchain base-devel

cd 'C:\msys64\home\Anti Chen\'
vim .bash_profile
Next, edit your .bash_profile, and add these lines:
export PREFIX=`realpath ~/prefix`
export PATH="$PREFIX/bin:$PATH"
export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$PREFIX/lib:$LD_LIBRARY_PATH"
然后保存并输入下面命令:
. .bash_profile
然后
cd 'C:\Users\Anti Chen\Downloads'
cd gimp-GIMP_2_10_0_RC1
./autogen.sh
make
make install
但是出了以下错误
AM_PATH_GTK_2_0 not found in library
所以还是等exe正式版放出来吧,在此只做个记录方便需要的人,不费劲捣鼓了

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2018-03-30 16:24
243750496
notepad++安装plugin manager(默认不带)
下载:https://github.com/bruderstein/nppPlugi ... r/releases
拷贝:
PluginManager.dll到plugins下
gpup到updater下
重启notepad++然后就可以安装NppExec了

注:如果用notepad++转换为ANSI编码编译后运行仍然无法去除乱码,那么你肯定忘保存了

Clangbuilder
下载以下安装包(所有和C++有关的安装包都安上)
1.png
2.png
3.png
Automated tools help developers on Windows platforms building LLVM and clang.

Installation

PowerShell Policy

Often you need to change the Power Shell execution policy

Get-ExecutionPolicy

Output:


Restricted

Please run PowerShell with administrator rights, and Enter:

Set-ExecutionPolicy RemoteSigned

General Setup

Clone clangbuilder on Github

git clone https://github.com/fstudio/clangbuilder.git clangbuilder

Click the script/InitializeEnv.bat

The installation script will compile ClangbuilderUI and create a shortcut, download required packages.
然后在clangbuilder-master根目录下双击ClangbuilderUI 运行就OK了
注意编译时不要干别的否则会在Win10下黑屏
If your need install VisualCppTools.Community.Daily ,click script/VisualCppToolsFetch.bat

Paste this code into the notepad++ run section
cmd /k cd $(CURRENT_DIRECTORY) && clang $(FILE_NAME) -o $(NAME_PART).exe && $(NAME_PART).exe && pause -std=c99




GLEW的安装
为了能够使用openGL的扩展库,我们可以安装glew来实现,介于本人痛苦的安装经历,我打算将我的成功安装心得告诉大家,希望大家能够免受软件的安装痛苦,更多的享受openGL的编程乐趣!!!

我的编译环境为VS2005,系统为win764位。首先我们可以到http://glew.sourceforge.net/下载最新的glew文件,将文件解压后将看到多个文件,将bin\release\Win32\glew32.dll放到C:\Windows\SysWOW64中,再将lib\release\x64里的文件复制到C:\\Program Flies(X86)\Visual Studio8\VC\Platform SDK\Lib中,再将include\GL\glew.h复制到C:\\Program Flies(X86)\Visual Studio8\VC\Platform SDK\Include\gl中。到这里我们还差一步。

在我们的工程文件里#include <gl/glew.h>
#include <GL/glut.h>
#include <stdlib.h>
#pragma comment(lib,"glew32.lib")

注意两点,一、glew.h要放在glut.h前

二、必须加上 #pragma comment(lib,"glew32.lib")

希望对大家能有所帮助!
GLEW是一个跨平台的C++扩展库,基于OpenGL图形接口。使用OpenGL的朋友都知道,window目前只支持OpenGL1.1的涵数,但 OpenGL现在都发展到2.0以上了,要使用这些OpenGL的高级特性,就必须下载最新的扩展,另外,不同的显卡公司,也会发布一些只有自家显卡才支 持的扩展函数,你要想用这数涵数,不得不去寻找最新的glext.h,有了GLEW扩展库,你就再也不用为找不到函数的接口而烦恼,因为GLEW能自动识 别你的平台所支持的全部OpenGL高级扩展涵数。也就是说,只要包含一个glew.h头文件,你就能使用gl,glu,glext,wgl,glx的全 部函数。GLEW支持目前流行的各种操作系统(including Windows, Linux, Mac OS X, FreeBSD, Irix, and Solaris)。

glu是实用库,包含有43个函数,函数名的前缀为glu。Glu 为了减轻繁重的编程工作,封装了OpenGL函数,Glu函数通过调用核心库的函数,为开发者提供相对简单的用法,实现一些较为复杂的操作。
glaux是OpenGL辅助库,包含有31个函数,函数名前缀为aux。这部分函数提供窗口管理、输入输出处理以及绘制一些简单三维物体。
glut是实用工具库,基本上是用于做窗口界面的,并且是跨平台(所以有时你喜欢做简单的demo的话,可以光用glut就ok了)


GLX:OpenGL extension for X.

对于X窗口系统,它所使用的的OpenGL扩展(GLX)是作为OpenGL的一个附件提供的,所有的GLX函数都使用前缀glX。


VS2017中nuget获取的glew安装包是需要新建一个Project并且保存ctrl+Shift+S才能下载的,因此推断并不会在编译clang时候作为一个功能来添加上,因此只能采用拷贝相应文件的方法进行安装

bin/glew32.dll to C:/windows/system32
lib/glew32.lib to D:/Programs/LLVM/lib/clang/4.0.0/lib/windows
include/GL/glew.h to D:/Programs/LLVM/lib/clang/4.0.0/include/GL
include/GL/wglew.h to D:/Programs/LLVM/lib/clang/4.0.0/include/GL

测试程序:
#include <windows.h>
#include <GL/glew.h>
// Add a main function
int main() {}


C语言究竟可不可以使用OpenGL编程?网上多的是VC++的,delphi的等等
可我就是不想学VC++,用C语言又不知道怎么初始化设置,好痛苦的。
比方说VC++中,是这样设置的:
1.将glut.dll和glut32.dll拷贝到windows/system32目录下。
2.将glut.h拷贝到集成环境安装目录的include/gl子目录下(如果不存在gl子目录,则创建它)。
3.将glut32.lib拷贝到集成环境安装目录的lib子目录下.
请进门的指点指点啊......
问题补充:

fengjian 兄台:
你推荐的《OpenGL 超级宝典》我下次就到图书馆去借
下面的话我不理解:
“最后在工程编译时,在工程中加入需要的库,有关命令行加入,glu32 opengl32 glut32库就可以编译了。 ”
我用C语言的时候,就是直接点run,一个简单的hello.c,怎么有工程的概念?上面的3个库glu32 opengl32 glut32加入到哪里,能不能说详细一点,拜托了



最佳答案
OpenGL就是基于C语言的,当然可以使用C语言。关于C语言的一本很好书籍为:《OpenGL 超级宝典》现在有第三版中译本,建议使用第二版。我就是靠它入门的。
你上面所说的步骤是正确的,最后在工程编译时,在工程中加入需要的库,有关命令行加入,glu32 opengl32 glut32库就可以编译了。
注意glut.h文件中已经包含gl.h,glu.h在实际编译中可以只加入头文件glut.h,很多相关的例子都是这样的,但是我在mingwstudio上编译发现,在glut.h前还是需要加入glu.h, gl.h.如:
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
才能成功编译


The OpenGL Extension Wrangler Library (GLEW) is a cross-platform open-source C/C++ extension loading library. GLEW provides efficient run-time mechanisms for determining which OpenGL extensions are supported on the target platform. OpenGL core and extension functionality is exposed in a single header file. GLEW has been tested on a variety of operating systems, including Windows, Linux, Mac OS X, FreeBSD, Irix, and Solaris.


GLX是OpenGL Extension to the X Window System的缩写。它作为x的扩展,是x协议和X server的一部分,已经包含在X server的代码中了。GLX提供了x window system使用的OpenGL接口,允许通过x调用OpenGL库。OpenGL 在使用时,需要与一个实际的窗口系统关联起来。在不同平台上有不同的机制以关联窗口系统,在Windows上是WGL,在Linux上是GLX,在Apple OS上是AGL等。
如果是闭源就不能使用glew了而是使用如下配置文件(放置于/Programs/LLVM/lib/clang/4.0.0/include/GL目录下
<GL/glext.h> - OpenGL 1.2 and above compatibility profile and extension interfaces.
• <GL/glcorearb.h> - OpenGL core profile and ARB extension interfaces, as described in appendix G.2 of the OpenGL 4.3 Specification. Does not include interfaces found only in the compatibility profile.
另外windows自带了gl.h和glu.h(在C盘搜索就行,不然就安装VS2017 Community版再搜索就有了)

常见的OpenGL头文件如下:(Windows系统中可以忽略大小写的区别,我自己也没太注意大小写。同时,文件的路径可能变化,例如不是<GL/gl.h>而是"gl.h",具体情况要看你到底把头文件放到哪了)

<GL/gl.h>:OpenGL所使用的函数和常量声明。

<GL/glu.h>:GLU(OpenGL实用库)所使用的函数和常量声明。GLU库属于OpenGL标准的一部分。(以下各种库则不属于

glu: This is OpenGL utilities library, which has been not updated for long time. Don't need to use this header file.
<GL/glaux.h>:GLAUX(OpenGL辅助库)所使用的函数和常量声明。这个库提供了创建窗口,处理键盘和鼠标事件,设置调色板等OpenGL本身不提供,但在编写OpenGL程序时又经常用到的功能。目前这个库已经过时,只有比较少的编译环境中有提供,例如VC系列。在VC系列编译器中,使用这个头文件之前必须使用#include <windows.h>或者具有类似功能的头文件。

<GL/glut.h>:GLUT(OpenGL实用工具包)所使用的函数和常量声明。这个库的功能大致与GLAUX类似,目前许多OpenGL教程使用这个库来编写演示程序。一些编译系统可能不直接提供这个库(例如VC系列),需要单独下载安装。这个头文件自动包含了<GL/gl.h>和<GL/glu.h>,编程时不必再次包含它们,非开源,GLUT is not open source. Mark Kilgard maintains the copyright

<GL/glext.h>:扩展头文件。因为微软公司对OpenGL的支持不太积极,VC系列编译器虽然有<GL/gl.h>这个头文件,但是里面只有OpenGL 1.1版本中所规定的内容,而没有OpenGL 1.2及其以后版本。对当前的计算机配置而言,几乎都支持OpenGL 1.4版本,更高的则到1.5, 2.0, 2.1,而VC无法直接使用这些功能。为了解决这一问题,就有了<GL/glext.h>头文件。这个头文件提供了高版本OpenGL所需要的各种常数声明以及函数指针声明。

<GL/wglext.h>:扩展头文件。与<GL/glext.h>类似,但这个头文件中只提供适用于Windows系统的各种OpenGL扩展所使用的函数和常量,不适用于其它操作系统。

"glee.h":GLEE开源库的头文件。它的出现是因为<GL/glext.h>虽然可以使用高版本的OpenGL函数,但是使用的形式不太方便。GLEE库则让高版本的OpenGL函数与其它OpenGL函数在使用上同样方便。需要注意的是,这个头文件与<GL/gl.h>是冲突的,在包含"glee.h"之前,不应该包含<GL/gl.h>。
#include <GL/glut.h>
#include "glee.h" // 错误,因为glut.h中含有gl.h,它与glee.h冲突
// 但是如果把两个include顺序交换,则正确
"glos.h":虽然这个也时常见到,但我也不知道它到底是什么,可能是与系统相关的各种功能,也可能只是自己编写的一个文件。我曾经看到一个glos.h头文件中只有一句#include <GL/glut.h>。


glut : 提供对窗口的封装,这是跨平台窗口的,我们就不必自己去编写烦琐的窗口代码。

glee : 方便用来判断当前系统是不是支持某项OpenGL特性,我们就不用自己去写烦琐的先取函数地址然后再判断的代码了。

glew : 因为windows默认只支持OpenGL 1.1,你要想用更高版本的OpenGL,你就需要安装它,它能自动识别你的平台所支持的全部OpenGL高级扩展函数。

OpenGL函数采用了以下格式:
<库前缀><根命令><可选的参数个数><可选的参数类型>
库前缀有gl、glu、aux、glut、wgl、glx、agl等等,分别表示该函数属于OpenGL那个开发库,从函数名后面中还可以看出需要多少个参数以及参数的类型。I代表int型,f代表float型,d代表double型,u代表无符号整型。例如glVertex3fv()表示了该函数属于gl库,参数是三个float型参数指针。我们用glVertex*() 来表示这一类函数。
OpenGL函数库相关的API有核心库(gl)、实用库(glu)、辅助库(aux)、实用工具库(glut)、窗口库(glx、agl、wgl)和扩展函数库等。从图可以看出,gl是核心,glu是对gl的部分封装。glx、agl、wgl 是针对不同窗口系统的函数。glut是为跨平台的OpenGL程序的工具包,比aux功能强大。扩展函数库是硬件厂商为实现硬件更新利用OpenGL的扩展机制开发的函数。

查看opengl版本的工具:opengl extension viewer
http://realtech-vr.com/admin/glview



头文件相当于你告诉别人,我这有个功能你可以按照这个格式调用,具体怎么实现的你不用关心,你用我做好的库就行了。
自己写代码的时候也是这么用。比如,你有一个规模很大的程序,包含了比如统计,日历,文本处理很多不同种类的功能。如果你把所有的函数都写在一个巨大的c文件里也行,但是读起来特别累,也不好调试,这时我们就可以考虑把不同种类的功能放在不同的c文件里,分门别类。那放在不同的文件里的函数如何调用对方呢?这时候我们用头文件做声明,告诉a文件如果包含了b文件的头文件,那么a就能调用b的功能。


#ifndef <标识>#define <标识>
............
#endif

<标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般(如果需要:大小写都可以,习惯大写,约定俗成用大写,以此与小写的普通变量区分开来.当然如果你故意小写,也是合法的.不过如果你想让你写的程序具有高可读性,那最好遵守此约定是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:delay.h
#ifndef _DELAY_H_#define _DELAY_H_
......
#endif
这一个在一般的小型程序中经常用到,在做单片机的的程序时,经常把一些可以独立的模块写成头文件,方便程序的阅读和移植。

我看了老长时间的书,终于明白
为什么是:#ifndef _DELAY_H_#define _DELAY_H_
而不是: #ifndef DELAY.H #define DELAY.H
//////////////////////////
因为,后者,定义一个名称,是用于一个程序中或者头文件中的,名称定义
前者,是关于头文件包含的,不是名称定义的。用下划线代替“.”,是没有办法的办法,只有这样才能防止混乱。
前者的意思是,如果没有包含了这个头文件,就包含它。
后者的意思是,如果没有定义这个名称,就定义它。

其实就是换一种写法 以区分两种意思。
两者是不一样的意思。

#error命令是C/C++语言的预处理命令之一,当预处理器预处理到#error命令时将停止编译并输出用户自定义的错误消息。
#if vs. if(#if用于预处理命令常与#define,#else等连用,而if用于逻辑判断,如if(x>1){};
条件编译是C语言中预处理部分的内容,它是编译器编译代码时最先处理的部分,
条件编译里面有判断语句,比如 #if 、#else 、#elif 及 #endif
它的意思是如果宏条件符合,编译器就编译这段代码,否则,编译器就忽略这段代码而不编译,如
#define A 0 //把A定义为0

#if (A > 1)

printf("A > 1"); //编译器没有编译该语句,该语句不生成汇编代码

#elif (A == 1)

printf("A == 1"); //编译器没有编译该语句,该语句不生成汇编代码

#else

printf("A < 1"); //编译器编译了这段代码,且生成了汇编代码,执行该语句

#endif

而 if 语句则不然,if 是 C 语言中的关键字,它根据表达式的计算结果来觉定执行那个语句,它里面的每个分支都编译了的, 如
#define A 0

if (A > 1)

printf("A > 1"); //编译器编译该语句,但因为A == 0 未执行

else if(A == 1)

printf("A == 1"); //编译器编译该语句,但因为A == 0 未执行

else

printf("A < 1"); //编译器编译该语句,因为A == 0 故执行

作为一个编译“开关”,比如:
#if(条件满足)
执行代码1
#else
执行代码2
#endif
假如编译时,确实满足条件,则生成的程序文件(.exe文件)中不会有执行代码2的。如果用普通if语句,生成的程序文件就会有执行代码2,这个区别看看生成文件大小就可以知道。如果你的条件在程序编译前就已经确定了,那就用#if;如果条件需要在程序运行过程中才能判断,则用if。
所以 简单地讲,条件编译是根据 宏条件 选择性地编译语句,它是编译器在编译代码时完成的;
条件语句是根据条件表达式选择性地执行语句,它是在程序运行时进行的。
#if的使用说明
#if的后面接的是表达式
#if (MAX==10)||(MAX==20)
code...
#endif
它的作用是:如果(MAX==10)||(MAX==20)成立,那么编译器就会把其中的#if 与 #endif之间的代码编译进去(注意:是编译进去,不是执行!!)
#if defined的使用
#if后面接的是一个宏。
#if defined (x)
...code...
#endif

这个#if defined它不管里面的“x”的逻辑是“真”还是“假”它只管这个程序的前面的宏定义里面有没有定义“x”这个宏,如果定义了x这个宏,那么,编译器会编译中间的…code…否则不直接忽视中间的…code…代码。
另外 #if defined(x)也可以取反,也就用 #if !defined(x)
#ifdef的使用
#ifdef的使用和#if defined()的用法一致
#ifndef又和#if !defined()的用法一致。
最后强调两点:
第一:这几个宏定义只是决定代码块是否被编译!
第二:别忘了#endif


#ifdef MY_PRINTF_STANDARD=#if defined(MY_PRINTF_STANDARD)


#else指令用于某个#if指令之后,当前面的#if指令的条件不为真时,就编译#else后面的代码。#endif指令将终止上面的条件块。#elif预处理指令综合了#else和#if指令的作用。

中文名
#elif
使用
用于某个#if指令之后
#elif
使您得以创建复合条件指令
预处理指令
综合了#else和#if指令的作用。
#elif 使您得以创建复合条件指令。如果前面的 #if 和前面的任何 #elif(可选)指令表达式的计算结果都不是 true,则将计算 #elif 表达式。如果 #elif 表达式计算为 true,编译器将计算位于 #elif 和下一个条件指令之间的所有代码。例如:

#defineVC7//...
#ifdebug
Console.Writeline("Debugbuild");
#elifVC7
Console.Writeline("VisualStudio7");
#endif

可以使用运算符 ==(相等)、!=(不相等)、&&(与)及 ||(或)来计算多个符号。还可以用括号将符号和运算符分组
#elif 等效于使用:
#else
#if
使用 #elif 更简单,因为每个 #if 都需要一个 #endif,而 #elif 即使在没有匹配的 #endif 时也可以使用。
有关如何使用 #elif 的示例,请参见 #if。

Microsoft Windows要求在gl.h或glu.h之前包含windows.h头文件,因为MicrosoftWindows版本的gl.h和glu.h文件内部使用的一些宏是在windows.h中定义的。


简单办法,先写完整程序,再把一部分抽出去,抽出去的存到 自己的头文件里,在抽出的地方写 #include ...

例如,完整程序(计算平均值):
#include<stdio.h>

double mean(double *y, int N){
int i;
double s=0.0;
for (i=0;i<N;i++) s=s+y;
s = s / (double) N;
return s;
}
void main()
{
double x[10]={1,2,3,4,5,6,7,8,9,10};
printf("mean = %lf\n", mean(x,10));
}
----------------------------------------------
抽出部分 存入 a_x.h :
double mean(double *y, int N){
int i;
double s=0.0;
for (i=0;i<N;i++) s=s+y;
s = s / (double) N;
return s;
}
--------------------------------
程序变:
#include<stdio.h>
#include "a_x.h"
void main()
{
double x[10]={1,2,3,4,5,6,7,8,9,10};
printf("mean = %lf\n", mean(x,10));
}
=============================================
你要是愿意随便抽一块也可以,例如抽出(也叫 a_x.h):
double mean(double *y, int N){
int i;
double s=0.0;
for (i=0;i<N;i++) s=s+y;
s = s / (double) N;
return s;
}
void main()
{
------------------------
程序变:
#include<stdio.h>
#include "a_x.h"
double x[10]={1,2,3,4,5,6,7,8,9,10};
printf("mean = %lf\n", mean(x,10));
}
==============================
语法上,功能上,两种抽法都可以。但第一种方法较好--程序可读性好,不易出错。

一般情况下,头文件里放 函数原型,全局量声明 和 函数定义。



一般用于将C++代码以标准C形式输出(即以C的形式被调用),这是因为C++虽然常被认为是C的超集,但是C++的编译器还是与C的编译器不同的。C中调用C++中的代码这样定义会是安全的。
一般的考虑跨平台使用方法如下:
#ifdefined(__cplusplus)||defined(c_plusplus) //跨平台定义方法
extern "C"{
#endif
//... 正常的声明段
#ifdefined(__cplusplus)||defined(c_plusplus)
}
#endif

简单的用在windows下可以如下定义:
#ifdef __cplusplus
extern "C"{
//... 正常的声明段
}
#endif


a>b ? printf("a比b大!\n") : printf("b比a大!\n");
相当于:

[plain] view plaincopy
if(a>b)
{
printf("a比b大!\n");
}
else
{
printf("a不比b大!\n");
}


C语言有一种数据类型叫结构体,其定义格式为:

struct 结构体名 {
结构体成员变量定义;
};


有几种访问结构体的方法:
访问结构成员的运算符有两种,一种是结构成员运算符“·”,也称为“圆点运算符”,另一种是结构指针运算符“->”,也称“箭头运算符”。
结构成员运算符通过结构变量名访问结构体的成员。例如:
printf("%s",student.name);
结构指针运算符由减号“-”和“>”组成(中间没有空格),它通过指向结构的指针访问结构的成员。假定声明了指向struct student的指针sPtr,并且把结构student1的地址赋给了sPtr,如下列语句通过指针sPtr打印了结构student1的成员name:
printf("%s",sPtr->name);
不要在结构指针运算符的-和>之间插入空格。
在用指针(->)和结构成员运算符(.)引用结构成员时一定要用圆括号(*sPtr).name,因为结构成员运算符“.”比指针复引用运算符“*”的优先级高,所以圆括号是必须的。
下面的程序演示了结构成员和结构指针运算符的用法:
#include<stdio.h>
struct student
{char *name;
char *sex;
int age;
};
main()
{
char i;
struct student student1;
struct student *sPtr;
student1.name="Tom";
student1.sex="male";
student1.age=18;
sPtr=&student1;
printf("%s%s%s\n%s%s%s\n%s%s%s\n",
student1.name,"'s sex is",student1.sex,
sPtr->name,"'s sex is",sPtr->sex,
(*sPtr).name,"'s sex is",(*sPtr).sex);

i = student1.age;
printf("\n\n\ni=%d||student1.age=%d||(*sPtr).age=%d",i,student1.age,(*sPtr).age);


return 0;
}

1、%lf 双精度浮点型,也就是double型的格式,默认保留6位小数。
如:double a = 1.2; printf("%lf",a); //1.200000。
2、%.2lf 同上,不过限制了,值保留2位小数。
如:double a = 1.2345; printf("%.2lf",a); //1.23。
3、%.2f 表示单精度浮点型,也就是float型的格式。
如:float a = 1.2731; printf("%.2f",a); //1.27。


下面的例子:
int main() {
func();
}
void func() {...}
会报错
,如果把func放在main()函数前,在main()调用它之前先定义,那么就ok,why? 因为编译器发现一个不认识的函数调用,不知道该函数的返回类型,就假设为int类型,等后面编译的时候编译器看到实际的函数,它认为有两个同名的函数,一个是文件中的函数,一个是编译器假设返回int的那个
如何去避免呢:有没有办法让编译器一开始就知道函数的返回值类型呢?为了防止编译器假设函数的返回类型,你可以显式地告诉它。告诉编译器函数会返回什么类型的语句就叫函数声明。

1.声明与定义分离

float func(int age);


函数声明包括:函数名,返回值类型,形参类型,以;结束,没有函数体.
一旦声明了函数,编译器就不需要假设,完全可以先调用函数,再定义函数。
对于上面的问题,可以这样写:
int main(int argc, char *argv[]) {
void func(); //声明
func();
return 0;
}

void func(){
printf("come on baby!");
}
如果有多个这样的玩意,我们就需要在main函数中一次次的声明,比较好的方式是可以放在头文件

2.头文件
创建头文件,func.h, 将函数声明写在此:
#ifndef intoC_func_h
#define intoC_func_h

void func();

#endif
然后上面程序就可以在main函数中不用再函数声明(不是定义!!!,只是不用声明了但是仍需定义!了.


Create C Program with Dynamic Link Library (DLL) using Visual Studio 2012 (Implicit Link)

The following procedure is to create a C program with a dynamic link library using Microsoft Visual Studio Express 2012.

Brief Introduction to Dynamic Link Library (DLL)
The important difference between DLL and static library is that the code of external function is stored in the DLL file, whereas when linking with static library, the code of the external functions is copied to the execution file of the application program. With static library, you just need an execution file whereas with DLL you need both the execution file and the DLL file for the program to work.

Implicit or Explicit Link
When creating DLL, we have the choice of implicit linking or explicit linking. Since implicit linking is easier and common, this article will focus on implicit linking. For additional information please refer to the following:

Linking Implicitly
Linking Explicitly
Determining Which Linking Method to Use

Examples:
The following example is a normal C program with functions without using any custom static library.

#include <stdio.h>
#define PI 3.1415

double PowerOf2 (double UserNumber);
double PowerOf3 (double UserNumber);
double CircleArea (double UserRadius);
double CircleCircum (double UserRadius);

int main ( )
{

double p2 = 10.0;
double p3 = 5.0;
double radius = 4.0;

printf ("The number %.2f to the power of 2 is %.2f. \n", p2, PowerOf2(p2));

printf ("The number %.2f to the power of 3 is %.2f. \n", p3, PowerOf3(p3));

printf ("A circle with a radius of %.2f, the area is %.2f. \n", radius, CircleArea(radius));

printf ("A circle with a radius of %.2f, the circumference is %.2f. \n", radius, CircleCircum(radius));

return 0;

}

double PowerOf2 (double UserNumber)
{
return UserNumber * UserNumber;
}


double PowerOf3 (double UserNumber)
{
return UserNumber * UserNumber * UserNumber;
}

double CircleArea (double UserRadius)
{
return UserRadius * UserRadius * PI;
}

double CircleCircum (double UserRadius)
{
return 2 * UserRadius * PI;
}

We will use the above example to create a dynamic link library and an application program that use this library. We will place the DLL in a shared public folder and place the application in the personal document folder.

To create a dynamic link library, it consist of 2 files MyMathDll.h and MyMathDll.c

To create Dynamic Link Library
Step 1: Create a new project as dynamic link library
Create a new project using MyMathDll as project name

dll (1).png


Click "OK". Then click "Next". On following screen you need to specify that you are creating a DLL and make sure you check Empty project.
dll (2).png


Step 2: Create the headers file
Under Solution Explorer, right click Headers Files >> Add >> New Item as shown below.

dll (3).png

Select header file as file type and rename the header file to MyMathDll.h
dll (4).png


Click "Add".

Add the following to the headers:

#ifdef MYMATHDLL_EXPORTS
#define MYMATHDLL_API __declspec(dllexport)
#else
#define MYMATHDLL_API __declspec(dllimport)
#endif

#define PI 3.1415

MYMATHDLL_API double PowerOf2 (double UserNumber);
MYMATHDLL_API double PowerOf3 (double UserNumber);
MYMATHDLL_API double CircleArea (double UserRadius);
MYMATHDLL_API double CircleCircum (double UserRadius);

The dllexport and dllimport attributes are extensions to the C and C++. You can use them to export and import functions to or from a DLL. When the MYMATHDLL_EXPORTS symbol is defined, the MYMATHDLL_API symbol will set the __declspec(dllexport) modifier in the member function declarations. This enables the function to be exported by the DLL so that it can be used by other applications. When MYMATHDLL_EXPORTS is undefined, MYMATHDLL_API defines the __declspec(dllimport) modifier in the member function declarations. This enables the compiler to optimize the importing of the function from the DLL for use in other applications. By default, MYMATHDLL_EXPORTS is defined when the MyMathDll project is built.

You can also define the header file this way.

#define PI 3.1415

__declspec(dllexport) double PowerOf2 (double UserNumber);
__declspec(dllexport) PowerOf3 (double UserNumber);
__declspec(dllexport) CircleArea (double UserRadius);
__declspec(dllexport) double CircleCircum (double UserRadius);

For further information on dllexport and dllimport please refer to this article.

Step 3: Create the Implementation Program
Under Solution Explorer, right click Source Files >> Add >> New Item. Rename the program to MyMathDll.c.

dll (5).png


Enter the source code as follows

#include "MyMathDll.h"

double PowerOf2 (double UserNumber)
{
return UserNumber * UserNumber;
}

double PowerOf3 (double UserNumber)
{
return UserNumber * UserNumber * UserNumber;
}

double CircleArea (double UserRadius)
{
return UserRadius * UserRadius * PI;
}

double CircleCircum (double UserRadius)
{
return 2 * UserRadius * PI;
}

Step 4: Build solutions
Build solutions. You should have result as follows:
dll (6).png

Once the compilation is complete, close the project.


Create a C Application Program Using DLL
Step 1: Create a new project
Create a new project using the name MyApp3 with Console Application as options. Remember to clear all headers and checked Empty Project.

Step 2: Establish Link with the Static Library
Under Solution Explorer, right click and select Add >> Existing Projects
dll (7).png

Navigate to the project folders of MyMathDll and select the project file MyMathDll.vcxproj and click Open.

Your solution explorer should show two projects like below:
dll (8).png
dll (8).png (10.59 KiB) 查看 16451 次

Select MyApp3, right click and select properties. Under Common Properties, select Framework and References. Click "Add New Reference"
dll (9).png

You should see the following screen, there should be a project named "MyMathDll". Check the project as shown below and click "OK".
dll (10).png

On the properties page, under Configuration Properties >> C/C++ expand the list in C/C++ and select "General" as shown below.
dll (11).png

For first line "Additional Include Directories", click the arrow and select edit. The following dialog box shows:

dll (12).png
Click the "New Line" icon and click on the button "...". Now you need to navigate to the DLL folder. Do not select the folder "MyMathDll" under Projects, drill one level down and select the folder "MyMathDll". The purpose is to the select the folder that contain the header file. Highlight the folder and click Select Folder.
dll (13).png

Click OK. Then click Apply. You can close the property dialog box.

Step 3: Create the application program
Under Solution Explorer, right click Source Files >> Add >> New Item. Rename the program to MyApp3.c.

Enter the following program:

#include <stdio.h>
#include "MyMathDll.h"

int main ( )
{

double p2 = 10.0;
double p3 = 5.0;
double radius = 4.0;

printf ("The number %.2f to the power of 2 is %.2f. \n", p2, PowerOf2(p2));

printf ("The number %.2f to the power of 3 is %.2f. \n", p3, PowerOf3(p3));

printf ("A circle with a radius of %.2f, the area is %.2f. \n", radius, CircleArea(radius));

printf ("A circle with a radius of %.2f, the circumference is %.2f. \n", radius, CircleCircum(radius));

return 0;

}

Step 4: Build the solution.
After you have built the solutions, you should received a message similar to the one below. Please note that two projects are being built.

dll (14).png
Step 5: Run the program
You can test the project from the command prompt as shown below:

dll (15).png

Additional Note:
Please note that for the successful execution of the program. MyApp3.exe and MyMathDll.dll should be in the same folder. Alternatively, the MyMathDll.dll should be located where the Windows system could find. The search path the DLL files for Windows are as follows:

The directory where the exe file is located.
The Windows system directory.
The Windows directory.
The directories listed in the PATH environment variable.


This completes the procedure for creating a DLL in C using Visual Studio Express 2012. Please note that the procedure for creating similar DLL using command line is different from using the IDE.



#pragma once是一个比较常用的C/C++杂注,只要在头文件的最开始加入这条杂注,就能够保证头文件只被编译一次。
如果编译失败那么把所有cpp文件改成c后缀的文件
changto c.png

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2018-04-08 0:09
243750496
Code Block OpenGL开发设置(Glew Glfw)
I was having similar problems earlier with importing GLFW into codeblocks, and I recently found something that works for me.
I can see that you have already done the header installation correctly, but I will include that in this response so that you can double-check that everything is in tip-top condition.
I also recommend that you use the sample code within the 'Documentation' tab of glfw.org. It works really well for me, so I think it might for you as well.
Since you are using GLFW, I will assume that you want to use OpenGL in your application, so I will include the installation of OpenGL in the tutorial

A. Creating relevant folders
The first thing you will need to do is set up a location for library files and header files on your system. You can either creates these folders within a specified location on your drive, or you can create these folders within your code::blocks project.
In my case, I created a 'lib' and 'head' folder in my code::blocks project folder.

B. Downloading & Installing necessary media
GLFW:
Head over to GLFW.org, and hit 'Downloads'.
Click '32-bit Windows binaries', and open the 'glfw-version.bin.WIN32' within zip file that was downloaded.
Open the 'include' folder and copy the enclosed GLFW folder to the 'head' folder you created in part A.
Open up 'glfw-version.bin.WIN32' again, and pick the 'lib' folder that corresponds to your compiler. Because I am using the MinGW GCC compiler, I picked 'lib-mingw'. To find your compiler, go to code::blocks, click settings, and then click 'compiler...'. Your compiler is found in the 'selected compiler' section of the window that appears.
Once you've found the 'lib' folder that you will use, open it, and copy all of the files within into the 'lib' folder that you created during part A.
GLEW (OpenGL):
Go to this link
Open the folder that is within the downloaded zip.
Go to 'lib', then release, then Win32, and copy all of the files located there into the 'lib' folder you created in step A.
Go back to the folder within the downloaded zip.
Enter the 'include' directory, and copy the 'GL' folder into the 'head' folder created in part a.
At this point, your 'head' folder should contain 'GLFW' and 'GL' folders, and your 'lib' folder should contain 'glew32', 'glew32s', and all of the library files from GLFW for your compiler.

C. Configuring your code::blocks project
Once you've opened your project, right click on the name of your project in your workspace, and hit 'build options...
On the left of the window that has appeared, make sure 'Debug' is selected.
Next click the 'linker settings' tab, and add the following libraries: 'glfw.3', 'gdi32', and 'opengl32'.
Next, in the 'Search Directories' tab, select the 'Compiler' tab.
Add the path to your 'head' folder. If the head folder was created within your project folder, you can just type 'head'
Also in the 'Search Directories' tab, select the 'Linker' tab.
Add the path to your 'lib' folder. Again, if the lib folder was created withing your project folder, you can just type 'lib'.
Hit 'OK' at the bottom of the window.

D. Build and Run your code :)! Hope this helps!

注意以下几点:
1、Build Options在Project下
2、GUN GCC在Settings->Compiler->Cygwin GCC的滚动条上方
3、先改为GUN GCC然后再改Toolchain executables->Compiler's installation directory为C:\Program Files (x86)\CodeBlocks\MinGW\bin
4、使用GUN GCC编译,如果使用LLVM Clang则会爆出LINK : fatal error LNK1181: cannot open input file 'glfw3.lib'(解决办法见cmake)

报错解决办法:
main.o: file not recognized: File format not recognized codeblocks
删除obj->DEBUG目录下的main.o文件

winapifamily.h : No such file or directory
build options -> search directories -> compiler添加如下路径:
C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\shared

glfw官方测试代码:
#include <GLFW/glfw3.h>

int main(void)
{
GLFWwindow* window;

/* Initialize the library */
if (!glfwInit())
return -1;

/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}

/* Make the window's context current */
glfwMakeContextCurrent(window);

/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);

/* Swap front and back buffers */
glfwSwapBuffers(window);

/* Poll for and process events */
glfwPollEvents();
}

glfwTerminate();
return 0;
}

如果用CodeBlocks创建DLL的话前面Visual Stuido一样然后再参考配置dll和lib(把这两个文件用VS编译后拷贝并配置好)
最后也就是最重要的一步就是Build Options->Linker Settings->添加MyMathDll(没有lib后缀)然后就可以了


cmake是一个构建C++代码的跨平台工具,他能够干什么呢?他能够搜索你的平台环境,然后生成平台上用于Build的文件。在Windows上安装了Visual Studio, 他能够帮你生成.sln然后在VS中Build Project), .vcxproj文件。如果在Linux上,能够帮你生成makefile。在MAC OS上,帮你生成xcode的项目文件。利用这些文件你就可以在本地编译,链接文件。生成这些项目,solution文件的输入信息,就是一套自己编写的和平台无关的配置文件。一般使用CMakeLists.txt文件。


使用GUN GCC编译,如果使用LLVM Clang则会爆出LINK : fatal error LNK1181: cannot open input file 'glfw3.lib'
解决办法:下载Cmake然后使用cmake-gui生成VS 工程文件并在VS中编译

如果不小心设置为X86编译器则需删除掉原glfw文件夹然后重新解压载入就行了
记得勾选上BUIDL_SHARED_LIBS(否则clang将无法使用)
Build_Shared_Libs.png
然后把生成的libs和dll文件拷贝载入并链接上(注意是glfw3dll,不是glfw3!)

如果使用CodeBlocks生成lib文件只需要在Project->Properties->Build Targets中去掉勾选:Auto-generate filename prefix 和 Auto-generate filename extension
lib extension.png

#include <iostream>

// GLEW
#define GLEW_STATIC
#include <GL/glew.h>

// GLFW
#include <GLFW/glfw3.h>


// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;

// The MAIN function, from here we start the application and run the game loop
int main()
{
std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl;
// Init GLFW
glfwInit();
// Set all the required options for GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

// Create a GLFWwindow object that we can use for GLFW's functions
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
if (window == nullptr)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
glewExperimental = GL_TRUE;
// Initialize GLEW to setup the OpenGL Function pointers
if (glewInit() != GLEW_OK)
{
std::cout << "Failed to initialize GLEW" << std::endl;
return -1;
}

// Define the viewport dimensions
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);

// Game loop
while (!glfwWindowShouldClose(window))
{
// Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
glfwPollEvents();
// Swap the screen buffers
glfwSwapBuffers(window);
}

// Terminate GLFW, clearing any resources allocated by GLFW.
glfwTerminate();
return 0;
}
再次提醒使用glfw3dll.lib库做链接的的时候输入的是glfw3dll,不是glfw3!)

只用到glew和glfw库的opengl测试源代码:
#include <GL/glew.h>
#include <GLFW/glfw3.h>

int main(int argc, char *argv[])
{
glfwInit();
GLFWwindow* window = glfwCreateWindow(640, 480, "Sample code does not display two triangles", NULL, NULL);
glfwMakeContextCurrent(window);

glewInit();

GLfloat vertices[] =
{
+0.0f, +0.0f, //0
+1.0f, +1.0f, //1
-1.0f, +1.0f, //2
-1.0f, -1.0f, //3
+1.0f, -1.0f, //4
};

GLuint vertexBufferID;
glGenBuffers(1, &vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 2, GL_FLOAT, 0, 0 );

GLuint indexBufferID;
GLushort indices[] = { 0,1,2, 0,3,4 };
glGenBuffers(1, &indexBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

while (!glfwWindowShouldClose(window))
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}

glfwTerminate();
return 0;
}

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2018-04-10 22:08
243750496
config.h

/*
Copyright 2012 Jun Wako <wakojun@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>;.
*/
#ifndef CONFIG_H
#define CONFIG_H

/* USB Device descriptor parameter */
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0x1111
#define DEVICE_VER 0x0001
#define MANUFACTURER CC
#define PRODUCT Onekey
#define DESCRIPTION CC keyboard firmware for GH60-CC
/* key matrix size */
#define MATRIX_ROWS 5
#define MATRIX_COLS 14
/* define if matrix has ghost */
//#define MATRIX_HAS_GHOST
/* Set 0 if debouncing isn't needed */
#define DEBOUNCE 5
/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
#define LOCKING_SUPPORT_ENABLE
/* Locking resynchronize hack */
#define LOCKING_RESYNC_ENABLE
/* key combination for command */
#define IS_COMMAND() ( \
keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
)

/*
* Feature disable options
* These options are also useful to firmware size reduction.
*/
/* disable debug print */
//#define NO_DEBUG
/* disable print */
//#define NO_PRINT
/* disable action features */
//#define NO_ACTION_LAYER
//#define NO_ACTION_TAPPING
//#define NO_ACTION_ONESHOT
//#define NO_ACTION_MACRO
//#define NO_ACTION_FUNCTION

/* PS/2 mouse */
#ifdef PS2_USE_BUSYWAIT
# define PS2_CLOCK_PORT PORTD
# define PS2_CLOCK_PIN PIND
# define PS2_CLOCK_DDR DDRD
# define PS2_CLOCK_BIT 1
# define PS2_DATA_PORT PORTD
# define PS2_DATA_PIN PIND
# define PS2_DATA_DDR DDRD
# define PS2_DATA_BIT 2
#endif

/* PS/2 mouse interrupt version */
#ifdef PS2_USE_INT
/* uses INT1 for clock line(ATMega32U4) */
#define PS2_CLOCK_PORT PORTD
#define PS2_CLOCK_PIN PIND
#define PS2_CLOCK_DDR DDRD
#define PS2_CLOCK_BIT 1
#define PS2_DATA_PORT PORTD
#define PS2_DATA_PIN PIND
#define PS2_DATA_DDR DDRD
#define PS2_DATA_BIT 2
#define PS2_INT_INIT() do { \
EICRA |= ((1<<ISC11) | \
(0<<ISC10)); \
} while (0)
#define PS2_INT_ON() do { \
EIMSK |= (1<<INT1); \
} while (0)
#define PS2_INT_OFF() do { \
EIMSK &= ~(1<<INT1); \
} while (0)
#define PS2_INT_VECT INT1_vect
#endif

/* PS/2 mouse USART version */
#ifdef PS2_USE_USART
#if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)
/* XCK for clock line and RXD for data line */
#define PS2_CLOCK_PORT PORTD
#define PS2_CLOCK_PIN PIND
#define PS2_CLOCK_DDR DDRD
#define PS2_CLOCK_BIT 5
#define PS2_DATA_PORT PORTD
#define PS2_DATA_PIN PIND
#define PS2_DATA_DDR DDRD
#define PS2_DATA_BIT 2
/* synchronous, odd parity, 1-bit stop, 8-bit data, sample at falling edge */
/* set DDR of CLOCK as input to be slave */
#define PS2_USART_INIT() do { \
PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT); \
PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT); \
UCSR1C = ((1 << UMSEL10) | \
(3 << UPM10) | \
(0 << USBS1) | \
(3 << UCSZ10) | \
(0 << UCPOL1)); \
UCSR1A = 0; \
UBRR1H = 0; \
UBRR1L = 0; \
} while (0)
#define PS2_USART_RX_INT_ON() do { \
UCSR1B = ((1 << RXCIE1) | \
(1 << RXEN1)); \
} while (0)
#define PS2_USART_RX_POLL_ON() do { \
UCSR1B = (1 << RXEN1); \
} while (0)
#define PS2_USART_OFF() do { \
UCSR1C = 0; \
UCSR1B &= ~((1 << RXEN1) | \
(1 << TXEN1)); \
} while (0)
#define PS2_USART_RX_READY (UCSR1A & (1<<RXC1))
#define PS2_USART_RX_DATA UDR1
#define PS2_USART_ERROR (UCSR1A & ((1<<FE1) | (1<<DOR1) | (1<<UPE1)))
#define PS2_USART_RX_VECT USART1_RX_vect
#endif
#endif
#endif




keymap_common_gh60_cc.h

#ifndef KEYMAP_COMMON_GH60_CC_H
#define KEYMAP_COMMON_GH60_CC_H

#include <stdint.h>
#include <stdbool.h>
#include "keycode.h"
#include "action.h"
#include "action_macro.h"
#include "report.h"
#include "host.h"
#include "print.h"
#include "debug.h"
#include "keymap.h"
#define KEYMAP( \
K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, \
K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \
K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2D, \
K30, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, K3D, \
K40, K41, K42, K45, K4A, K4B, K4C, K4D \
) { \
{ KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07, KC_##K08, KC_##K09, KC_##K0A, KC_##K0B, KC_##K0C, KC_##K0D }, \
{ KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17, KC_##K18, KC_##K19, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D }, \
{ KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27, KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_NO, KC_##K2D }, \
{ KC_##K30, KC_NO, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37, KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D }, \
{ KC_##K40, KC_##K41, KC_##K42, KC_NO, KC_NO, KC_##K45, KC_NO, KC_NO, KC_NO, KC_NO, KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D } \
}
#endif


keymap_gh60_cc.c
#include "keymap_common_gh60_cc.h"
/*
* CC
*/
const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/* MIT Layout (default)
*
* ,-------------------------------------------------------------------------------------.
* |ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | Backsp |
* |-------------------------------------------------------------------------------------|
* |Tab | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ |
* |-------------------------------------------------------------------------------------|
* |Caps | A | S | D | F | G | H | J | K | L | ; | ' | Enter |
* |-------------------------------------------------------------------------------------|
* |Shift | Z | X | C | V | B | N | M | , | . | / | Shift | Fn |
* |-------------------------------------------------------------------------------------|
* | Ctrl|Super| Alt | Space | Left | Down| Up |Right|
* `-------------------------------------------------------------------------------------'
*/
KEYMAP(
ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, \
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, \
LCTL,A, S, D, F, G, H, J, K, L, SCLN, QUOT, ENT, \
LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, FN0, \
LCTL,LGUI,LALT, SPC, LEFT,DOWN,UP,RGHT),
/* MIT Layout (Fn)
*
* ,-------------------------------------------------------------------------------------.
* | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12| prtscn |
* |-------------------------------------------------------------------------------------|
* |Tab | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ |
* |-------------------------------------------------------------------------------------|
* |Caps | A | S | D | F | G | H | J | K | L | ; | ' | Enter |
* |-------------------------------------------------------------------------------------|
* |Shift | Z | X | C | V | B | N | M | , | . | / | Shift | Fn |
* |-------------------------------------------------------------------------------------|
* | Ctrl| | Alt | | HOME| END |Insrt|Delt|
* `-------------------------------------------------------------------------------------'
*/
KEYMAP(
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR, \
TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, \
TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS, \
TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS, \
TRNS, NO,TRNS, TRNS, HOME, END, INS,DELETE),
};
const action_t PROGMEM fn_actions[] = {
[0] = ACTION_LAYER_MOMENTARY(0),
[1] = ACTION_LAYER_MOMENTARY(1),
};


matrix_gh60_cc.c

/*
Copyright 2017 Jun Wako <wakojun@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <" target="_blank">http://www.gnu.org/licenses/>;.
*/

/*
* scan matrix
*/
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include "debug.h"
#include "timer.h"
#include "matrix.h"


#ifndef DEBOUNCE
# define DEBOUNCE 5
#endif
/* matrix state(1:on, 0:off) */
/*
static matrix_row_t row_debounced = 0;
static matrix_row_t row_debouncing = 0;
static bool debouncing = false;
static uint16_t debouncing_time = 0;
*/
static uint8_t debouncing = DEBOUNCE;

/* matrix state(1:on, 0:off) */
static matrix_row_t matrix[MATRIX_ROWS];
static matrix_row_t matrix_debouncing[MATRIX_ROWS];

static matrix_row_t read_cols(void);
static void init_cols(void);
static void unselect_rows(void);
static void select_row(uint8_t row);

/*
void matrix_init(void)
{
debug_enable = true;
debug_matrix = true;
debug_mouse = true;

// PB0: Input with pull-up(DDR:0, PORT:1)
DDRB &= ~(1<<0);
PORTB |= (1<<0);
}
*/
void matrix_init(void)
{
// initialize row and col
unselect_rows();
init_cols();

// initialize matrix state: all keys off
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
matrix = 0;
matrix_debouncing = 0;
}
}
/*
uint8_t matrix_scan(void)
{
matrix_row_t r = (PINB&(1<<0) ? 0 : 1);
if (row_debouncing != r) {
row_debouncing = r;
debouncing = true;
debouncing_time = timer_read();
}

if (debouncing && timer_elapsed(debouncing_time) > DEBOUNCE) {
row_debounced = row_debouncing;
debouncing = false;
}
return 1;
}
*/

uint8_t matrix_scan(void)
{
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
select_row(i);
_delay_us(30); // without this wait read unstable value.
matrix_row_t cols = read_cols();
if (matrix_debouncing != cols) {
matrix_debouncing = cols;
if (debouncing) {
debug("bounce!: "); debug_hex(debouncing); debug("\n");
}
debouncing = DEBOUNCE;
}
unselect_rows();
}

if (debouncing) {
if (--debouncing) {
_delay_ms(1);
} else {
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
matrix = matrix_debouncing;
}
}
}

return 1;
}

inline
matrix_row_t matrix_get_row(uint8_t row)
{
/*
return row_debounced;
*/
return matrix[row];
}

/*
Col: 1 2 3 4 5 6 7 8 9 10 11 12 13 14
Pin: D0 D1 D2 D3 D4 D5 D6 D7 C0 C1 C2 C3 C4 C5
*/

static void init_cols(void)
{
// Input with pull-up(DDR:0, PORT:1)
DDRD &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<3 | 1<<2 | 1<<1 | 1<<0);
PORTD |= (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<3 | 1<<2 | 1<<1 | 1<<0);
DDRC &= ~(1<<5 | 1<<4 | 1<<3 | 1<<2 | 1<<1 | 1<<0);值为00000000&11000000=00000000
PORTC |= (1<<5 | 1<<4 | 1<<3 | 1<<2 | 1<<1 | 1<<0);值为00000000|00111111=00111111
}

static matrix_row_t read_cols(void)
{
return (PIND&(1<<0) ? 0 : (1<<0)) |
(PIND&(1<<1) ? 0 : (1<<1)) |
(PIND&(1<<2) ? 0 : (1<<2)) |
(PIND&(1<<3) ? 0 : (1<<3)) |
(PIND&(1<<4) ? 0 : (1<<4)) |
(PIND&(1<<5) ? 0 : (1<<5)) |
(PIND&(1<<6) ? 0 : (1<<6)) |
(PIND&(1<<7) ? 0 : (1<<7)) |
(PINC&(1<<0) ? 0 : (1<<8)) |
(PINC&(1<<1) ? 0 : (1<<9)) |
(PINC&(1<<2) ? 0 : (1<<10)) |
(PINC&(1<<3) ? 0 : (1<<11)) |
(PINC&(1<<4) ? 0 : (1<<12)) |
(PINC&(1<<5) ? 0 : (1<<13));
}

/*
Row: 1 2 3 4 5
Pin: C6 C7 A7 A6 A5
*/
static void unselect_rows(void)
{
// Hi-Z(DDR:0, PORT:0) to unselect
DDRC &= ~0b11000000;//初始化后的值(执行过一遍init cols后)等于01000000&00111111=00000000:case0;等于10000000&00111111=00000000:case1,初始值为:00000000&00111111=00000000
PORTC &= ~0b11000000;//初始化后的值(执行过一遍init cols后)等于00111111&00111111=00111111:case0;等于00111111&00111111=00111111:case1,初始值为:00000000&00111111=00000000
DDRA &= ~0b11100000;//初始化后的值(执行过一遍init cols后)等于10000000&00011111=00000000:case2;等于01000000&00011111=00000000:case3;等于00100000&00011111=00000000:case4,初始值为:00000000&00011111=00000000
PORTA &= ~0b11100000;//初始化后的值(执行过一遍init cols后)等于00000000&00011111=00000000:case2;等于00000000&00011111=00000000:case3;等于00000000&00011111=00000000:case4,初始值为:00000000&00011111=00000000
}

static void select_row(uint8_t row)
{
// Output low(DDR:1, PORT:0) to select
switch (row) {
case 0:
DDRC |= (1<<6);//等于00000000|01000000=01000000:case0;
PORTC &= ~(1<<6);//等于00111111&10111111=00111111:case0;
break;
case 1:
DDRC |= (1<<7);//等于00000000|10000000=10000000:case1;
PORTC &= ~(1<<7);//等于00111111&01111111=00111111:case1;
break;
case 2:
DDRA |= (1<<7);//等于00000000|10000000=10000000
PORTA &= ~(1<<7);//等于00000000|01111111=00000000
break;
case 3:
DDRA |= (1<<6);//等于00000000|01000000=01000000
PORTA &= ~(1<<6);//等于00000000|10111111=00000000
break;
case 4:
DDRA |= (1<<5);//等于00000000|00100000=00100000
PORTA &= ~(1<<5);//等于00000000|11011111=00000000
break;
}
}



由于单片机芯片每次只能扫描一种状态(每大端口(C端口或C组端口):比如C,而不是C0~7中的小端口如:C1端口),切换状态需要使用Hiz(又称三态Or高阻态),如果不用高阻态重置状态就会出现处理器无法理解到底是新的(行:row的)高电平还是旧的(列:col的)高电平没变
--------------------------------------------------------------------------------
matrix_gh60_cc.c
/*
Copyright 2017 Jun Wako <wakojun@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <" target="_blank">http://www.gnu.org/licenses/>;.
*/
/*
* scan matrix
*/
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <util/delay.h>
#include "print.h"
#include "debug.h"
#include "util.h"
#include "matrix.h"

#ifndef DEBOUNCE
# define DEBOUNCE 5
#endif
/* matrix state(1:on, 0:off) */
/*
static matrix_row_t row_debounced = 0;
static matrix_row_t row_debouncing = 0;
static bool debouncing = false;
static uint16_t debouncing_time = 0;
*/
static uint8_t debouncing = DEBOUNCE;
/* matrix state(1:on, 0:off) */
static matrix_row_t matrix[MATRIX_ROWS];
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
static matrix_row_t read_cols(void);
static void init_cols(void);
static void unselect_rows(void);
static void select_row(uint8_t row);
/*
void matrix_init(void)
{
debug_enable = true;
debug_matrix = true;
debug_mouse = true;
// PB0: Input with pull-up(DDR:0, PORT:1)
DDRB &= ~(1<<0);
PORTB |= (1<<0);
}
*/
void matrix_init(void)
{
// initialize row and col
unselect_rows();
init_cols();
// initialize matrix state: all keys off
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
matrix = 0;
matrix_debouncing = 0;
}
}
/*
uint8_t matrix_scan(void)
{
matrix_row_t r = (PINB&(1<<0) ? 0 : 1);
if (row_debouncing != r) {
row_debouncing = r;
debouncing = true;
debouncing_time = timer_read();
}
if (debouncing && timer_elapsed(debouncing_time) > DEBOUNCE) {
row_debounced = row_debouncing;
debouncing = false;
}
return 1;
}
*/
uint8_t matrix_scan(void)
{
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
select_row(i);
_delay_us(30); // without this wait read unstable value.
matrix_row_t cols = read_cols();
if (matrix_debouncing != cols) {
matrix_debouncing = cols;
if (debouncing) {
debug("bounce!: "); debug_hex(debouncing); debug("\n");
}
debouncing = DEBOUNCE;
}
unselect_rows();
}
if (debouncing) {
if (--debouncing) {
_delay_ms(1);
} else {
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
matrix[i] = matrix_debouncing[i];
}
}
}
return 1;
}
inline
matrix_row_t matrix_get_row(uint8_t row)
{
/*
return row_debounced;
*/
return matrix[row];
}
/*
Col: 1 2 3 4 5 6 7 8 9 10 11 12 13 14
Pin: D0 D1 D2 D3 D4 D5 D6 D7 C0 C1 C2 C3 C4 C5
*/
static void init_cols(void)
{
// Input with pull-up(DDR:0, PORT:1)
DDRD &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<3 | 1<<2 | 1<<1 | 1<<0);
PORTD |= (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<3 | 1<<2 | 1<<1 | 1<<0);
DDRC &= ~(1<<5 | 1<<4 | 1<<3 | 1<<2 | 1<<1 | 1<<0);
PORTC |= (1<<5 | 1<<4 | 1<<3 | 1<<2 | 1<<1 | 1<<0);
}
static matrix_row_t read_cols(void)
{
return (PIND&(1<<0) ? 0 : (1<<0)) |
(PIND&(1<<1) ? 0 : (1<<1)) |
(PIND&(1<<2) ? 0 : (1<<2)) |
(PIND&(1<<3) ? 0 : (1<<3)) |
(PIND&(1<<4) ? 0 : (1<<4)) |
(PIND&(1<<5) ? 0 : (1<<5)) |
(PIND&(1<<6) ? 0 : (1<<6)) |
(PIND&(1<<7) ? 0 : (1<<7)) |
(PINC&(1<<0) ? 0 : (1<<8)) |
(PINC&(1<<1) ? 0 : (1<<9)) |
(PINC&(1<<2) ? 0 : (1<<10)) |
(PINC&(1<<3) ? 0 : (1<<11)) |
(PINC&(1<<4) ? 0 : (1<<12)) |
(PINC&(1<<5) ? 0 : (1<<13));
}
/*
Row: 1 2 3 4 5
Pin: C6 C7 A7 A6 A5
*/
static void unselect_rows(void)
{
// Hi-Z(DDR:0, PORT:0) to unselect
DDRC &= ~0b11000000;
PORTC &= ~0b11000000;
DDRA &= ~0b11100000;
PORTA &= ~0b11100000;
}
static void select_row(uint8_t row)
{
// Output low(DDR:1, PORT:0) to select
switch (row) {
case 0:
DDRC |= (1<<6);
PORTC &= ~(1<<6);
break;
case 1:
DDRC |= (1<<7);
PORTC &= ~(1<<7);
break;
case 2:
DDRA |= (1<<7);
PORTA &= ~(1<<7);
break;
case 3:
DDRA |= (1<<6);
PORTA &= ~(1<<6);
break;
case 4:
DDRA |= (1<<5);
PORTA &= ~(1<<5);
break;
}
}


--------------------------------------------------------------------------------
Makefile
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device.
# Please customize your programmer settings(PROGRAM_CMD)
#
# make teensy = Download the hex file to the device, using teensy_loader_cli.
# (must have teensy_loader_cli installed).
#
# make dfu = Download the hex file to the device, using dfu-programmer (must
# have dfu-programmer installed).
#
# make flip = Download the hex file to the device, using Atmel FLIP (must
# have Atmel FLIP installed).
#
# make dfu-ee = Download the eeprom file to the device, using dfu-programmer
# (must have dfu-programmer installed).
#
# make flip-ee = Download the eeprom file to the device, using Atmel FLIP
# (must have Atmel FLIP installed).
#
# make debug = Start either simulavr or avarice as specified for debugging,
# with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
# bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------
# Target file name (without extension).
TARGET = gh60_cc
# Directory common source filess exist
TMK_DIR = ../../tmk_core
# Directory keyboard dependent files exist
TARGET_DIR = .
# project specific files
SRC = keymap_gh60_cc.c \
matrix_gh60_cc.c \
led_gh60_cc.c
CONFIG_H = config.h

# MCU name
#MCU = at90usb1287
#MCU = atmega32u4
MCU = at90usb1286
# Processor frequency.
# This will define a symbol, F_CPU, in all source code files equal to the
# processor frequency in Hz. You can then use this symbol in your source code to
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
# automatically to create a 32-bit value in your source code.
#
# This will be an integer division of F_USB below, as it is sourced by
# F_USB after it has run through any CPU prescalers. Note that this value
# does not *change* the processor frequency - it should merely be updated to
# reflect the processor speed set externally so that the code can use accurate
# software delays.
F_CPU = 16000000

#
# LUFA specific
#
# Target architecture (see library "Board Types" documentation).
ARCH = AVR8
# Input clock frequency.
# This will define a symbol, F_USB, in all source code files equal to the
# input clock frequency (before any prescaling is performed) in Hz. This value may
# differ from F_CPU if prescaling is used on the latter, and is required as the
# raw input clock is fed directly to the PLL sections of the AVR for high speed
# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
# at the end, this will be done automatically to create a 32-bit value in your
# source code.
#
# If no clock division is performed on the input clock inside the AVR (via the
# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
F_USB = $(F_CPU)
# Interrupt driven control endpoint task(+60)
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT

# Boot Section Size in *bytes*
# Teensy halfKay 512
# Teensy++ halfKay 1024
# Atmel DFU loader 4096
# LUFA bootloader 4096
# USBaspLoader 2048
OPT_DEFS += -DBOOTLOADER_SIZE=8192

# Build Options
# comment out to disable the options.
#
#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
#MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
#EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
CONSOLE_ENABLE = yes # Console for debug(+400)
#COMMAND_ENABLE = yes # Commands for debug and configuration
SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend
#NKRO_ENABLE = yes # USB Nkey Rollover
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
#PS2_USE_BUSYWAIT = yes # uses primitive reference code
#PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin
#PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened)

# Search Path
VPATH += $(TARGET_DIR)
VPATH += $(TMK_DIR)
include $(TMK_DIR)/common.mk
include $(TMK_DIR)/protocol.mk
include $(TMK_DIR)/protocol/lufa.mk
include $(TMK_DIR)/rules.mk


led_gh60_cc.c
/*
Copyright 2012 Jun Wako <wakojun@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <" target="_blank">http://www.gnu.org/licenses/>;.
*/
#include <avr/io.h>
#include "stdint.h"
#include "led.h"
/*
LED Col 1:PB0
LED Col 2:PB1
LED Col 3:PB2
LED Col 4:PB3
LED Col 5:PB4
LED Col 6:PB5
LED Col 7:PB6
LED Col 8:PB7
LED Col 9:PF0
LED Col 10:PF1
LED Col 11:PF2
LED Col 12:PF3
LED Col 13:PF4
LED Col 14:PF5
*/
/*
LED Row 1:PA1
LED Row 2:PA2
LED Row 3:PA3
*/
void led_set(uint8_t usb_led)
{
/* if (usb_led & (1<<USB_LED_CAPS_LOCK)) {
// output low
DDRB |= (1<<2);
PORTB &= ~(1<<2);
} else {
// Hi-Z
DDRB &= ~(1<<2);
PORTB &= ~(1<<2);
}
*/
}


cygwin -bash:make: 未找到命令:
no make.png
重新点击我们的安装包
在选择保的时候,展开Devel
devel.png
在里面找到make,然后,Bin 和 Src 如果可以勾选都 勾选上,点击下一步就可以安装了
make.png
Using the GNU AVR toolchain on Windows 10(不设置无法编译出键盘.hex文件,编译时会cgwin提示缺少avr-gcc,而这个包是不在包管理器里的
Table of Contents
Introduction
Install Git
Install the Atmel GNU Toolchain
Install GNU Make
Install avrdude
Update your PATH
Install Drivers for your Programmer
Sanity Check
Introduction
This page attempts to describe a procedure for installing a complete GCC-based toolchain on a modern Windows system. I've developed these instructions on my Windows 10 machine, but they should work for versions of Windows as far back as Windows 7. On older versions, you might want to use WinAVR. WinAVR used to be the preferred way to get this toolchain set up on Windows, even to the point of being semi-official, but has not been maintained in years. The installer reportedly wreaks havoc on newer Windows versions, but it likely works great on XP.
Install Git
We're going to use the bash shell installed by Git as our starting point. It's easy to install, and if you're using Git on Windows, you might have it already. Click the Start menu and search for "Git Bash". If it comes up, you have it already. If not, download and install Git for Windows. The defaults for all of the choices in the installer will work for our purposes.
Install the Atmel GNU Toolchain
Download the Atmel AVR Toolchain for Windows from Atmel's site and run the installer. When asked where to extract the files, click the "..." button and navigate to C:\Program Files, then click Extract.
toolchain_install.png
toolchain_install.png (3.99 KiB) 查看 16072 次
Install GNU Make
Download Gnu Make and launch the installer. Accept the default location for the installation. You can choose whether or not you want an icon in your start menu.
make_install.png
Install avrdude
Download avrdude
. Unzip the archive, and copy the archive inside to C:\Program Files.
Update your PATH
Now we need to tell Windows where to locate all of the tools you've just installed when you type their names on the command line. Go to the Start menu and open the Control Panel, then go to System. From the left pane, choose "Advanced System Settings". Under the Advanced tab, click the "Environment Variables" button.
env_vars.png
Under User variables, select "Path" and click the Edit button. If you don't already have a variable called "Path", click the New button to create it, enter "Path" without the name, and fill out the value as described below.
edit_vars.png
The Edit window that pops up is unfortunately different depending on whether you are creating a new variable or only have one item in your path, or if you have multiple items in your path already. In the first two cases, you just get a textbox for a value. In the third case, you get a list of values. Either way, you want to add the following three values. If you get the list, add them as separate items (see screenshot below). If you get the textbox, enter them separated by semicolons. Make sure that they are entered exactly or Windows won't be able to find the programs.
The three values to add are:
C:\Program Files\avr8-gnu-toolchain\bin
C:\Program Files (x86)\GnuWin32\bin
C:\Program Files\avrdude
edit_window.png
Click OK on all of the windows you've opened.
Install Drivers for your Programmer
This tutorial assumes you are going to use a FabISP, FabTinyStarISP, or other USBtiny-based programmer. If you are using one of the official Atmel programmers instead, the easiest way to get the drivers is to install Atmel Studio.
The USBtiny programmers use a generic libusb driver, but Windows 10's driver signing policy makes the installation more complicated. Fortunately, there's a tool that helps with this. Download Zadig and launch it. Plug in your programmer, and select the "USBtinySPI" device in the list. (If it doesn't show up, go to the Options menu and click "List All Devices". The driver you want to install (to the right of the green arrow) is either libusb-win32 or libusb0. Click the "Install Driver" button. You should only have to do this once.

Sanity Check
Everything is now installed. Let's check that it all works.
Go to the start menu and search for "Git Bash" and start it. When you see instructions telling you to open your terminal in other tutorials, this is the terminal window you should use.
Check to make sure that the commands we installed work okay:
make
Type make -v and press enter. You should see:
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
... and so on.
If you get a "command not found" error instead, re-check your installation of make and your path variable setting for typos.
avr-gcc
Type avr-gcc --version and press enter. You should see:
avr-gcc.exe (AVR_8_bit_GNU_Toolchain_3.5.4_1709) 4.9.2
... and so on.
If you get a "command not found" error instead, re-check your installation of the Atmel toolchain and your path variable setting for typos.
avrdude
Connect your programmer to a USB port and type: avrdude -c usbtiny -p t45 and press enter. You should see:
avrdude.exe: initialization failed, rc=-1
...
This means that avrdude successfully found your programmer, but failed to talk to a target board (expected because we don't have anything conencted to the programmer right now.)
If instead you see:
avrdude.exe: Error: Could not find USBtiny device (0x1781/0xc9f)
check your USB driver installation (the Zadig steps).
If you get a "command not found" error, check your installation of avrdude and your path variable.
Yay!
You should be ready to go!
打开cgwin并输入:
cd 'C:\Users\Anti Chen\Documents\tmk_keyboard-master\keyboard\onekey'
make -f Makefile clean
make -f Makefile


Git for windows的安装
下载:访问网站下载最新版的git版本


安装:点击”next“,转到步骤3


安装地址:可以更改也可以直接使用默认的


将Additional icons中的On the Desktop勾上;
将Windows Explorer integration选项中的“Git Bash here”和“Git GUI here”勾上。
Git bash and gui.png
Git notpad plus plus.png
在“Adjusting your PATH environment”选项中,选择默认即可。
Git command prompt.png
在Choosing HTTPS transport backend 中选择默认。
Git openssl.png
在“Configuring the line ending conversions”选项中,第一个选项:如果是跨平台项目,在windows系统安装,选择;第二个选项:如果是跨平台项目,在Unix系统安装,选择;第三个选项:非跨平台项目,选择。
Git check winstl.png
在Configuring the terminal emulator to use with Git Bash中选择默认
Git MinTTY.png
在Configuring extra options中选择默认,
然后点击“Install”开始安装。如果之前安装过旧版本,会先卸载然后再安装新版本。
Git caching and manager.png
安装完成后点击“finish”即可
桌面上或者开始菜单找到Git Bash 双击打开即可开始愉快的Git之旅了

从https://www.pjrc.com/teensy/loader_cli.html下载Windows binary (于C盘根目录解压放置exe)
然后在系统环境变量里加入C盘根目录就行了,就可以
cd 'C:\Users\Anti Chen\Documents\tmk_keyboard-master\keyboard\onekey'
make -f Makefile teensy,然后按reset烧录了

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2018-04-18 13:00
243750496
先熟悉指针函数的声明形式:数据类型 (* 指针变量名) (形参列表);
例如: int (* func)(void);//这是一个变量声明语句(指针函数的声明),声明了一个函数指针变量func,注意区别指针函数和函数指针。 func = &test; //变量赋值(给指针函数赋值);
那么现在来理解typedef int (* func)(void)语句;
1.去掉"typedef"得到一个正常的变量声明语句(指针函数声明): int (*func)(void);这里变量func的类型为一个函数类型,而当加上”typedef"后,就得到一个新的类型, 原来的变量名称func就变成新类型的名称,func不再是变量名称,而是一个新类型名--func,用这个新的类型就可以去定义和原来func变量相同类型的变量,注意看去除和加上"typedef“时func的变化,没有"typedef"时,func为变量名,加上"typedef"时,func为类型名(这个类型等同于原来func变量的类型),因此下面正确:
typedef int (* t_func)(void);//定义了一个新类型 t_func;
int (*func)(void); 变量声明语句(指针函数声明):
//....
t_func func2 = func; //func2和func是相同类型,这就好理解加上"typedef"产生的变化了。
可以这么想,加上"typedef"关键字后,原来语句声明的变量变成类型,以下正确:
1. int id; ==> typedef int ID; //在加上"typedef"后,变量id就变成类型ID(为了清楚,把类型变大写),这个新类型等同于原来变量对应的类型; id <==>ID id ;
2. int a[10]; ==> typedef int A[10];//加上"typedef"后,变量a就成了类型A(为了清楚,把类型变大写),这个新类型等同于原来变量对应的类型; a <=> A a;
因此typedef就好理解。


在c语言中,定义一个结构体要用typedef ,例如下面的示例代码,Stack sq;中的Stack就是struct Stack的别名。
如果没有用到typedef,例如定义
struct test1{
int a;
int b;
int c;

};

test1 t;//声明变量
下面语句就会报错
struct.c:31:1: error: must use 'struct' tag to refer to type 'test1'
test1 t;
^
struct
1 error generated.
声明变量时候就要用struct test1;这样就解决了

如果这样定义的话
typedef struct test3{
int a;
int b;
int c;
}test4;
test3 d;
test4 f;
此时会报错
struct.c:50:1: error: must use 'struct' tag to refer to type 'test3'
test3 d;
^
struct
1 error generated.
所以要struct test3这样来声明变量d;

分析一下:
上面的test3是标识符,test4 是变量类型(相当于(int,char等))。

我们可以用struct test3 d来定义变量d;为什么不能用test3 d来定义是错误的,因为test3相当于标识符,不是一个结构体,struc test3 合在一起才代表是一个结构类型。
所以声明时候要test3时候要用struct test3 d;

typedef其实是为这个结构体起了一个新的名字,test4;
typedef struct test3 test4;
test4 相当于struct test3;
就是这么回事

#include<stdio.h>
#include<stdlib.h>

typedef struct Stack
{
char * elem;
int top;
int size;
}stack;
/*推荐
typedef struct Stack
{
char * elem;
int top;
int size;
}Stack;
*/
struct test1{
int a;
int b;
int c;

};

typedef struct{
int a;
int b;
int c;

}test2;
int main(){

printf("hello,vincent,\n");
//stack sq;等于struct Stack sq;
//Stack sq;(推荐)
struct Stack sq;
//
sq.top = -1;
sq.size=10;
printf("top:%d,size:%d\n",sq.top,sq.size);

// 如果定义中没有typedef,就要用struct test1声明变量,否则报错:
struct test1 t;
t.a=1;
t.b=2;
t.c=3;
printf("a:%d,b:%d,c:%d\n",t.a,t.b,t.c);

test2 e;
e.a=4;
e.b=5;
e.c=6;
printf("a:%d,b:%d,c:%d\n",e.a,e.b,e.c);
return 0;

}

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2018-04-18 15:25
243750496
指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; 能很方便地使用数组和字符串; 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。指针极大地丰富了C语言的功能。 学习指针是学习C语言中最重要的一环, 能否正确理解和使用指针是我们是否掌握C语言的一个标志。同时, 指针也是C语言中最为困难的一部分,在学习中除了要正确理解基本概念,还必须要多编程,上机调试。只要作到这些,指针也是不难掌握的。
  指针的基本概念 在计算机中,所有的数据都是存放在存储器中的。 一般把存储器中的一个字节称为一个内存单元, 不同的数据类型所占用的内存单元数不等,如整型量占2个单元,字符量占1个单元等, 在第二章中已有详细的介绍。为了正确地访问这些内存单元, 必须为每个内存单元编上号。 根据一个内存单元的编号即可准确地找到该内存单元。内存单元的编号也叫做地址。 既然根据内存单元的编号或地址就可以找到所需的内存单元,所以通常也把这个地址称为指针。 内存单元的指针和内存单元的内容是两个不同的概念。 可以用一个通俗的例子来说明它们之间的关系。我们到银行去存取款时, 银行工作人员将根据我们的帐号去找我们的存款单, 找到之后在存单上写入存款、取款的金额。在这里,帐号就是存单的指针, 存款数是存单的内容。对于一个内存单元来说,单元的地址即为指针, 其中存放的数据才是该单元的内容。在C语言中, 允许用一个变量来存放指针,这种变量称为指针变量。因此, 一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。图中,设有字符变量C,其内容为“K”(ASCII码为十进制数 75),C占用了011A号单元(地址用十六进数表示)。设有指针变量P,内容为011A, 这种情况我们称为P指向变量C,或说P是指向变量C的指针。 严格地说,一个指针是一个地址, 是一个常量。而一个指针变量却可以被赋予不同的指针值,是变。 但在常把指针变量简称为指针。为了避免混淆,我们中约定:“指针”是指地址, 是常量,“指针变量”是指取值为地址的变量。 定义指针的目的是为了通过指针去访问内存单元。
 
   既然指针变量的值是一个地址, 那么这个地址不仅可以是变量的地址, 也可以是其它数据结构的地址。在一个指针变量中存放一
个数组或一个函数的首地址有何意义呢? 因为数组或函数都是连续存放的。通过访问指针变量取得了数组或函数的首地址, 也就找到了该数组或函数。这样一来, 凡是出现数组,函数的地方都可以用一个指针变量来表示, 只要该指针变量中赋予数组或函数的首地址即可。这样做, 将会使程序的概念十分清楚,程序本身也精练,高效。在C语言中, 一种数据类型或数据结构往往都占有一组连续的内存单元。 用“地址”这个概念并不能很好地描述一种数据类型或数据结构, 而“指针”虽然实际上也是一个地址,但它却是一个数据结构的首地址, 它是“指向”一个数据结构的,因而概念更为清楚,表示更为明确。 这也是引入“指针”概念的一个重要原因。
指针变量的类型说明
  对指针变量的类型说明包括三个内容:
(1)指针类型说明,即定义变量为一个指针变量;
(2)指针变量名;
(3)变量值(指针)所指向的变量的数据类型。
   其一般形式为: 类型说明符 *变量名;
   其中,*表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。
   例如: int *p1;表示p1是一个指针变量,它的值是某个整型变量的地址。 或者说p1指向一个整型变量。至于p1究竟指向哪一个整型变量, 应由向p1赋予的地址来决定。
   再如:
staic int *p2; /*p2是指向静态整型变量的指针变量*/
float *p3; /*p3是指向浮点变量的指针变量*/
char *p4; /*p4是指向字符变量的指针变量*/ 应该注意的是,一个指针变量只能指向同类型的变量,如P3 只能指向浮点变量,不能时而指向一个浮点变量, 时而又指向一个字符变量。
指针变量的赋值
  指针变量同普通变量一样,使用之前不仅要定义说明, 而且必须赋予具体的值。未经赋值的指针变量不能使用, 否则将造成系统混乱,甚至死机。指针变量的赋值只能赋予地址, 决不能赋予任何其它数据,否则将引起错误。在C语言中, 变量的地址是由编译系统分配的,对用户完全透明,用户不知道变量的具体地址。 C语言中提供了地址运算符&来表示变量的地址。其一般形式为: & 变量名; 如&a变示变量a的地址,&b表示变量b的地址。 变量本身必须预先说明。设有指向整型变量的指针变量p,如要把整型变量a 的地址赋予p可以有以下两种方式:
(1)指针变量初始化的方法 int a;
int *p=&a;
(2)赋值语句的方法 int a;
int *p;
p=&a;
不允许把一个数赋予指针变量,故下面的赋值是错误的: int *p;p=1000; 被赋值的指针变量前不能再加“*”说明符,如写为*p=&a 也是错误的
指针变量的运算
  指针变量可以进行某些运算,但其运算的种类是有限的。 它只能进行赋值运算和部分算术运算及关系运算。
1.指针运算符
(1)取地址运算符&
   取地址运算符&是单目运算符,其结合性为自右至左,其功能是取变量的地址。在scanf函数及前面介绍指针变量赋值中,我们已经了解并使用了&运算符。
(2)取内容运算符*
   取内容运算符*是单目运算符,其结合性为自右至左,用来表示指针变量所指的变量。在*运算符之后跟的变量必须是指针变量。需要注意的是指针运算符*和指针变量说明中的指针说明符* 不是一回事。在指针变量说明中,“*”是类型说明符,表示其后的变量是指针类型。而表达式中出现的“*”则是一个运算符用以表示指针变量所指的变量。
main(){
int a=5,*p=&a;
printf ("%d",*p);
}
......
表示指针变量p取得了整型变量a的地址。本语句表示输出变量a的值。
2.指针变量的运算
(1)赋值运算
指针变量的赋值运算有以下几种形式:
①指针变量初始化赋值,前面已作介绍。
②把一个变量的地址赋予指向相同数据类型的指针变量。例如:
int a,*pa;
pa=&a; /*把整型变量a的地址赋予整型指针变量pa*/
③把一个指针变量的值赋予指向相同类型变量的另一个指针变量。如:
int a,*pa=&a,*pb;
pb=pa; /*把a的地址赋予指针变量pb*/
由于pa,pb均为指向整型变量的指针变量,因此可以相互赋值。 ④把数组的首地址赋予指向数组的指针变量。
例如: int a[5],*pa;
pa=a; (数组名表示数组的首地址,故可赋予指向数组的指针变量pa)
也可写为:
pa=&a[0]; /*数组第一个元素的地址也是整个数组的首地址,
也可赋予pa*/
当然也可采取初始化赋值的方法:
int a[5],*pa=a;
⑤把字符串的首地址赋予指向字符类型的指针变量。例如: char *pc;pc="c language";或用初始化赋值的方法写为: char *pc="C Language"; 这里应说明的是并不是把整个字符串装入指针变量, 而是把存放该字符串的字符数组的首地址装入指针变量。 在后面还将详细介绍。
⑥把函数的入口地址赋予指向函数的指针变量。例如: int (*pf)();pf=f; /*f为函数名*/
(2)加减算术运算
  对于指向数组的指针变量,可以加上或减去一个整数n。设pa是指向数组a的指针变量,则pa+n,pa-n,pa++,++pa,pa--,--pa 运算都是合法的。指针变量加或减一个整数n的意义是把指针指向的当前位置(指向某数组元素)向前或向后移动n个位置。应该注意,数组指针变量向前或向后移动一个位置和地址加1或减1 在概念上是不同的。因为数组可以有不同的类型, 各种类型的数组元素所占的字节长度是不同的。如指针变量加1,即向后移动1 个位置表示指针变量指向下一个数据元素的首地址。而不是在原地址基础上加1。
例如:
int a[5],*pa;
pa=a; /*pa指向数组a,也是指向a[0]*/
pa=pa+2; /*pa指向a[2],即pa的值为&pa[2]*/ 指针变量的加减运算只能对数组指针变量进行, 对指向其它类型变量的指针变量作加减运算是毫无意义的。(3)两个指针变量之间的运算只有指向同一数组的两个指针变量之间才能进行运算, 否则运算毫无意义。
①两指针变量相减
两指针变量相减所得之差是两个指针所指数组元素之间相差的元素个数。实际上是两个指针值(地址) 相减之差再除以该数组元素的长度(字节数)。例如pf1和pf2 是指向同一浮点数组的两个指针变量,设pf1的值为2010H,pf2的值为2000H,而浮点数组每个元素占4个字节,所以pf1-pf2的结果为(2000H-2010H)/4=4,表示pf1和 pf2之间相差4个元素。两个指针变量不能进行加法运算。 例如, pf1+pf2是什么意思呢?毫无实际意义。
②两指针变量进行关系运算
指向同一数组的两指针变量进行关系运算可表示它们所指数组元素之间的关系。例如:
pf1==pf2表示pf1和pf2指向同一数组元素
pf1>pf2表示pf1处于高地址位置
pf1<pf2表示pf2处于低地址位置
main(){
int a=10,b=20,s,t,*pa,*pb;
pa=&a;
pb=&b;
s=*pa+*pb;
t=*pa**pb;
printf("a=%d/nb=%d/na+b=%d/na*b=%d/n",a,b,a+b,a*b);
printf("s=%d/nt=%d/n",s,t);
}
......
说明pa,pb为整型指针变量
给指针变量pa赋值,pa指向变量a。
给指针变量pb赋值,pb指向变量b。
本行的意义是求a+b之和,(*pa就是a,*pb就是b)。
本行是求a*b之积。
输出结果。
输出结果。
......
指针变量还可以与0比较。设p为指针变量,则p==0表明p是空指针,它不指向任何变量;p!=0表示p不是空指针。空指针是由对指针变量赋予0值而得到的。例如: #define NULL 0 int *p=NULL; 对指针变量赋0值和不赋值是不同的。指针变量未赋值时,可以是任意值,是不能使用的。否则将造成意外错误。而指针变量赋0值后,则可以使用,只是它不指向具体的变量而已。
main(){
int a,b,c,*pmax,*pmin;
printf("input three numbers:/n");
scanf("%d%d%d",&a,&b,&c);
if(a>b){
pmax=&a;
pmin=&b;}
else{
pmax=&b;
pmin=&a;}
if(c>*pmax) pmax=&c;
if(c<*pmin) pmin=&c;
printf("max=%d/nmin=%d/n",*pmax,*pmin);
}
......
pmax,pmin为整型指针变量。
输入提示。
输入三个数字。
如果第一个数字大于第二个数字...
指针变量赋值
指针变量赋值
指针变量赋值
指针变量赋值
判断并赋值
判断并赋值
输出结果
......
数组指针变量的说明和使用
  指向数组的指针变量称为数组指针变量。 在讨论数组指针变量的说明和使用之前,我们先明确几个关系。
一个数组是由连续的一块内存单元组成的。 数组名就是这块连续内存单元的首地址。一个数组也是由各个数组元素(下标变量) 组成的。每个数组元素按其类型不同占有几个连续的内存单元。 一个数组元素的首地址也是指它所占有的几个内存单元的首地址。 一个指针变量既可以指向一个数组,也可以指向一个数组元素, 可把数组名或第一个元素的地址赋予它。如要使指针变量指向第i号元素可以把i元素的首地址赋予它或把数组名加i赋予它。
  设有实数组a,指向a的指针变量为pa,从图6.3中我们可以看出有以下关系:
pa,a,&a[0]均指向同一单元,它们是数组a的首地址,也是0 号元素a[0]的首地址。pa+1,a+1,&a[1]均指向1号元素a[1]。类推可知a+i,a+i,&a
指向i号元素a
应该说明的是pa是变量,而a,&a都是常量。在编程时应予以注意。
main(){
int a[5],i;
for(i=0;i<5;i++){
a=i;
printf("a[%d]=%d/n",i,a);
}
printf("/n");
}
主函数
定义一个整型数组和一个整型变量
循环语句
给数组赋值
打印每一个数组的值
......
输出换行
......
数组指针变量说明的一般形式为:
类型说明符 * 指针变量名
   其中类型说明符表示所指数组的类型。 从一般形式可以看出指向数组的指针变量和指向普通变量的指针变量的说明是相同的。
引入指针变量后,就可以用两种方法来访问数组元素了。
   第一种方法为下标法,即用a形式访问数组元素。 在第四章中介绍数组时都是采用这种方法。
   第二种方法为指针法,即采用*(pa+i)形式,用间接访问的方法来访问数组元素。
main(){
int a[5],i,*pa;
pa=a;
for(i=0;i<5;i++){
*pa=i;
pa++;
}
pa=a;
for(i=0;i<5;i++){
printf("a[%d]=%d/n",i,*pa);
pa++;
}
}
主函数
定义整型数组和指针
将指针pa指向数组a
循环
将变量i的值赋给由指针pa指向的a[]的数组单元
将指针pa指向a[]的下一个单元
......
指针pa重新取得数组a的首地址
循环
用数组方式输出数组a中的所有元素
将指针pa指向a[]的下一个单元
......
......
下面,另举一例,该例与上例本意相同,但是实现方式不同。
main(){
int a[5],i,*pa=a;
for(i=0;i<5;){
*pa=i;
printf("a[%d]=%d/n",i++,*pa++);
}
}
主函数
定义整型数组和指针,并使指针指向数组a
循环
将变量i的值赋给由指针pa指向的a[]的数组单元
用指针输出数组a中的所有元素,同时指针pa指向a[]的下一个单元
......
......
数组名和数组指针变量作函数参数
  在第五章中曾经介绍过用数组名作函数的实参和形参的问题。在学习指针变量之后就更容易理解这个问题了。 数组名就是数组的首地址,实参向形参传送数组名实际上就是传送数组的地址, 形参得到该地址后也指向同一数组。 这就好象同一件物品有两个彼此不同的名称一样。同样,指针变量的值也是地址, 数组指针变量的值即为数组的首地址,当然也可作为函数的参数使用。
float aver(float *pa);
main(){
float sco[5],av,*sp;
int i;
sp=sco;
printf("/ninput 5 scores:/n");
for(i=0;i<5;i++) scanf("%f",&sco);
av=aver(sp);
printf("average score is %5.2f",av);
}
float aver(float *pa)
{
int i;
float av,s=0;
for(i=0;i<5;i++) s=s+*pa++;
av=s/5;
return av;
}
指向多维数组的指针变量
本小节以二维数组为例介绍多维数组的指针变量。
一、多维数组地址的表示方法
设有整型二维数组a[3][4]如下:
0 1 2 3
4 5 6 7
8 9 10 11
   设数组a的首地址为1000,各下标变量的首地址及其值如图所示。在第四章中介绍过, C语言允许把一个二维数组分解为多个一维数组来处理。因此数组a可分解为三个一维数组,即a[0],a[1],a[2]。每一个一维数组又含有四个元素。例如a[0]数组,含有a[0][0],a[0][1],a[0][2],a[0][3]四个元素。 数组及数组元素的地址表示如下:a是二维数组名,也是二维数组0行的首地址,等于1000。a[0]是第一个一维数组的数组名和首地址,因此也为1000。*(a+0)或*a是与a[0]等效的, 它表示一维数组a[0]0 号元素的首地址。 也为1000。&a[0][0]是二维数组a的0行0列元素首地址,同样是1000。因此,a,a[0],*(a+0),a[0][0]是相等的。同理,a+1是二维数组1行的首地址,等于1008。a[1]是第二个一维数组的数组名和首地址,因此也为1008。 &a[1][0]是二维数组a的1行0列元素地址,也是1008。因此a+1,a[1],*(a+1),&a[1][0]是等同的。 由此可得出:a+i,a,*(a+i),&a[0]是等同的。 此外,&a和a[i]也是等同的。因为在二维数组中不能把&a[i]理解为元素a[i]的地址,不存在元素a[i]。
  C语言规定,它是一种地址计算方法,表示数组a第i行首地址。由此,我们得出:a[i],&a[i],*(a+i)和a+i也都是等同的。另外,a[0]也
可以看成是a[0]+0是一维数组a[0]的0号元素的首地址, 而a[0]+1则是a[0]的1号元素首地址,由此可得出a[i]+j则是一维数组a[i]的j号元素首地址,它等于&a[i][j]。由a[i]=*(a+i)得a[i]+j=*(a+i)+j,由于*(a+i)+j是二维数组a的i行j列元素的首地址。该元素的值等于*(*(a+i)+j)。

#define PF "%d,%d,%d,%d,%d,/n"
main(){
static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
printf(PF,a,*a,a[0],&a[0],&a[0][0]);
printf(PF,a+1,*(a+1),a[1],&a[1],&a[1][0]);
printf(PF,a+2,*(a+2),a[2],&a[2],&a[2][0]);
printf("%d,%d/n",a[1]+1,*(a+1)+1);
printf("%d,%d/n",*(a[1]+1),*(*(a+1)+1));
}
二、多维数组的指针变量
  把二维数组a 分解为一维数组a[0],a[1],a[2]之后,设p为指向二维数组的指针变量。可定义为: int (*p)[4] 它表示p是一个指针变量,它指向二维数组a 或指向第一个一维数组a[0],其值等于a,a[0],或&a[0][0]等。而p+i则指向一维数组a[i]。从前面的分析可得出*(p+i)+j是二维数组i行j 列的元素的地址,而*(*(p+i)+j)则是i行j列元素的值。
  二维数组指针变量说明的一般形式为: 类型说明符 (*指针变量名)[长度] 其中“类型说明符”为所指数组的数据类型。“*”表示其后的变量是指针类型。 “长度”表示二维数组分解为多个一维数组时, 一维数组的长度,也就是二维数组的列数。应注意“(*指针变量名)”两边的括号不可少,如缺少括号则表示是指针数组(本章后面介绍),意义就完全不同了。
main(){
static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
int(*p)[4];
int i,j;
p=a;
for(i=0;i<3;i++)
for(j=0;j<4;j++) printf("%2d ",*(*(p+i)+j));
}
字符串指针变量的说明和使用字符串指针变量的定义说明与指向字符变量的指针变量说明是相同的。只能按对指针变量的赋值不同来区别。 对指向字符变量的指针变量应赋予该字符变量的地址。如: char c,*p=&c;表示p是一个指向字符变量c的指针变量。而: char *s="C Language";则表示s是一个指向字符串的指针变量。把字符串的首地址赋予s。
请看下面一例。
main(){
char *ps;
ps="C Language";
printf("%s",ps);
}
运行结果为:
C Language
上例中,首先定义ps是一个字符指针变量, 然后把字符串的首地址赋予ps(应写出整个字符串,以便编译系统把该串装入连续的一块内存单元),并把首地址送入ps。程序中的: char *ps;ps="C Language";等效于: char *ps="C Language";输出字符串中n个字符后的所有字符。
main(){
char *ps="this is a book";
int n=10;
ps=ps+n;
printf("%s/n",ps);
}
运行结果为:
book 在程序中对ps初始化时,即把字符串首地址赋予ps,当ps= ps+10之后,ps指向字符“b”,因此输出为"book"。
main(){
char st[20],*ps;
int i;
printf("input a string:/n");
ps=st;
scanf("%s",ps);
for(i=0;ps[i]!='/0';i++)
if(ps[i]=='k'){
printf("there is a 'k' in the string/n");
break;
}
if(ps[i]=='/0') printf("There is no 'k' in the string/n");
}
   本例是在输入的字符串中查找有无‘k’字符。 下面这个例子是将指针变量指向一个格式字符串,用在printf函数中,用于输出二维数组的各种地址表示的值。但在printf语句中用指针变量PF代替了格式串。 这也是程序中常用的方法。
main(){
static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
char *PF;
PF="%d,%d,%d,%d,%d/n";
printf(PF,a,*a,a[0],&a[0],&a[0][0]);
printf(PF,a+1,*(a+1),a[1],&a[1],&a[1][0]);
printf(PF,a+2,*(a+2),a[2],&a[2],&a[2][0]);
printf("%d,%d/n",a[1]+1,*(a+1)+1);
printf("%d,%d/n",*(a[1]+1),*(*(a+1)+1));
}
   在下例是讲解,把字符串指针作为函数参数的使用。要求把一个字符串的内容复制到另一个字符串中,并且不能使用strcpy函数。函数cprstr的形参为两个字符指针变量。pss指向源字符串,pds指向目标字符串。表达式:
(*pds=*pss)!=`/0'
cpystr(char *pss,char *pds){
while((*pds=*pss)!='/0'){
pds++;
pss++; }
}
main(){
char *pa="CHINA",b[10],*pb;
pb=b;
cpystr(pa,pb);
printf("string a=%s/nstring b=%s/n",pa,pb);
}
   在上例中,程序完成了两项工作:一是把pss指向的源字符复制到pds所指向的目标字符中,二是判断所复制的字符是否为`/0',若是则表明源字符串结束,不再循环。否则,pds和pss都加1,指向下一字符。在主函数中,以指针变量pa,pb为实参,分别取得确定值后调用cprstr函数。由于采用的指针变量pa和pss,pb和pds均指向同一字符串,因此在主函数和cprstr函数中均可使用这些字符串。也可以把cprstr函数简化为以下形式:
cprstr(char *pss,char*pds)
{while ((*pds++=*pss++)!=`/0');}
   即把指针的移动和赋值合并在一个语句中。 进一步分析还可发现`/0'的ASCⅡ码为0,对于while语句只看表达式的值为非0就循环,为0则结束循环,因此也可省去“!=`/0'”这一判断部分,而写为以下形式:
cprstr (char *pss,char *pds)
{while (*pdss++=*pss++);}
表达式的意义可解释为,源字符向目标字符赋值, 移动指针,若所赋值为非0则循环,否则结束循环。这样使程序更加简洁。简化后的程序如下所示。
cpystr(char *pss,char *pds){
while(*pds++=*pss++);
}
main(){
char *pa="CHINA",b[10],*pb;
pb=b;
cpystr(pa,pb);
printf("string a=%s/nstring b=%s/n",pa,pb);
}
使用字符串指针变量与字符数组的区别
用字符数组和字符指针变量都可实现字符串的存储和运算。 但是两者是有区别的。在使用时应注意以下几个问题:
1. 字符串指针变量本身是一个变量,用于存放字符串的首地址。而字符串本身是存放在以该首地址为首的一块连续的内存空间中并以‘/0’作为串的结束。字符数组是由于若干个数组元素组成的,它可用来存放整个字符串。
2. 对字符数组作初始化赋值,必须采用外部类型或静态类型,如: static char st[]={“C Language”};而对字符串指针变量则无此限制,如: char *ps="C Language";
3. 对字符串指针方式 char *ps="C Language";可以写为: char *ps; ps="C Language";而对数组方式:
static char st[]={"C Language"};
不能写为:
char st[20];st={"C Language"};
而只能对字符数组的各元素逐个赋值。
  从以上几点可以看出字符串指针变量与字符数组在使用时的区别,同时也可看出使用指针变量更加方便。前面说过,当一个指针变量在未取得确定地址前使用是危险的,容易引起错误。但是对指针变量直接赋值是可以的。因为C系统对指针变量赋值时要给以确定的地址。因此,
char *ps="C Langage";
或者 char *ps;
ps="C Language";都是合法的。
函数指针变量
  在C语言中规定,一个函数总是占用一段连续的内存区, 而函数名就是该函数所占内存区的首地址。 我们可以把函数的这个首地址(或称入口地址)赋予一个指针变量, 使该指针变量指向该函数。然后通过指针变量就可以找到并调用这个函数。 我们把这种指向函数的指针变量称为“函数指针变量”。
函数指针变量定义的一般形式为:
类型说明符 (*指针变量名)();
其中“类型说明符”表示被指函数的返回值的类型。“(* 指针变量名)”表示“*”后面的变量是定义的指针变量。 最后的空括号表示指针变量所指的是一个函数。
例如: int (*pf)();
表示pf是一个指向函数入口的指针变量,该函数的返回值(函数值)是整型。
下面通过例子来说明用指针形式实现对函数调用的方法。
int max(int a,int b){
if(a>b)return a;
else return b;
}
main(){
int max(int a,int b);
int(*pmax)();
int x,y,z;
pmax=max;
printf("input two numbers:/n");
scanf("%d%d",&x,&y);
z=(*pmax)(x,y);
printf("maxmum=%d",z);
}
   从上述程序可以看出用,函数指针变量形式调用函数的步骤如下:1. 先定义函数指针变量,如后一程序中第9行 int (*pmax)();定义pmax为函数指针变量。
2. 把被调函数的入口地址(函数名)赋予该函数指针变量,如程序中第11行 pmax=max;
3. 用函数指针变量形式调用函数,如程序第14行 z=(*pmax)(x,y); 调用函数的一般形式为: (*指针变量名) (实参表)使用函数指针变量还应注意以下两点:
a. 函数指针变量不能进行算术运算,这是与数组指针变量不同的。数组指针变量加减一个整数可使指针移动指向后面或前面的数组元素,而函数指针的移动是毫无意义的。
b. 函数调用中"(*指针变量名)"的两边的括号不可少,其中的*不应该理解为求值运算,在此处它只是一种表示符号。
指针型函数
前面我们介绍过,所谓函数类型是指函数返回值的类型。 在C语言中允许一个函数的返回值是一个指针(即地址), 这种返回指针值的函数称为指针型函数。
定义指针型函数的一般形式为:
类型说明符 *函数名(形参表)
{
…… /*函数体*/
}
其中函数名之前加了“*”号表明这是一个指针型函数,即返回值是一个指针。类型说明符表示了返回的指针值所指向的数据类型。
如:
int *ap(int x,int y)
{
...... /*函数体*/
}
   表示ap是一个返回指针值的指针型函数, 它返回的指针指向一个整型变量。下例中定义了一个指针型函数 day_name,它的返回值指向一个字符串。该函数中定义了一个静态指针数组name。name 数组初始化赋值为八个字符串,分别表示各个星期名及出错提示。形参n表示与星期名所对应的整数。在主函数中, 把输入的整数i作为实参, 在printf语句中调用day_name函数并把i值传送给形参 n。day_name函数中的return语句包含一个条件表达式, n 值若大于7或小于1则把name[0] 指针返回主函数输出出错提示字符串“Illegal day”。否则返回主函数输出对应的星期名。主函数中的第7行是个条件语句,其语义是,如输入为负数(i<0)则中止程序运行退出程序。exit是一个库函数,exit(1)表示发生错误后退出程序, exit(0)表示正常退出。
  应该特别注意的是函数指针变量和指针型函数这两者在写法和意义上的区别。如int(*p)()和int *p()是两个完全不同的量。int(*p)()是一个变量说明,说明p 是一个指向函数入口的指针变量,该函数的返回值是整型量,(*p)的两边的括号不能少。int *p() 则不是变量说明而是函数说明,说明p是一个指针型函数,其返回值是一个指向整型量的指针,*p两边没有括号。作为函数说明, 在括号内最好写入形式参数,这样便于与变量说明区别。 对于指针型函数定义,int *p()只是函数头部分,一般还应该有函数体部分。
main(){
int i;
char *day_name(int n);
printf("input Day No:/n");
scanf("%d",&i);
if(i<0) exit(1);
printf("Day No:%2d-->%s/n",i,day_name(i));
}
char *day_name(int n){
static char *name[]={ "Illegal day",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"};
return((n<1||n>7) ? name[0] : name[n]);
}
   本程序是通过指针函数,输入一个1~7之间的整数, 输出对应的星期名。指针数组的说明与使用一个数组的元素值为指针则是指针数组。 指针数组是一组有序的指针的集合。 指针数组的所有元素都必须是具有相同存储类型和指向相同数据类型的指针变量。
   指针数组说明的一般形式为: 类型说明符*数组名[数组长度]
   其中类型说明符为指针值所指向的变量的类型。例如: int *pa[3] 表示pa是一个指针数组,它有三个数组元素, 每个元素值都是一个指针,指向整型变量。通常可用一个指针数组来指向一个二维数组。 指针数组中的每个元素被赋予二维数组每一行的首地址, 因此也可理解为指向一个一维数组。图6—6表示了这种关系。
int a[3][3]={1,2,3,4,5,6,7,8,9};
int *pa[3]={a[0],a[1],a[2]};
int *p=a[0];
main(){
int i;
for(i=0;i<3;i++)
printf("%d,%d,%d/n",a[i][2-i],*a[i],*(*(a+i)+i));
for(i=0;i<3;i++)
printf("%d,%d,%d/n",*pa[i],p[i],*(p+i));
}
   本例程序中,pa是一个指针数组,三个元素分别指向二维数组a的各行。然后用循环语句输出指定的数组元素。其中*a[i]表示i行0列元素值;*(*(a+i)+i)表示i行i列的元素值;*pa[i]表示i行0列元素值;由于p与a[0]相同,故p[i]表示0行i列的值;*(p+i)表示0行i列的值。读者可仔细领会元素值的各种不同的表示方法。 应该注意指针数组和二维数组指针变量的区别。 这两者虽然都可用来表示二维数组,但是其表示方法和意义是不同的。
  二维数组指针变量是单个的变量,其一般形式中"(*指针变量名)"两边的括号不可少。而指针数组类型表示的是多个指针( 一组有序指针)在一般形式中"*指针数组名"两边不能有括号。例如: int (*p)[3];表示一个指向二维数组的指针变量。该二维数组的列数为3或分解为一维数组的长度为3。 int *p[3] 表示p是一个指针数组,有三个下标变量p[0],p[1],p[2]均为指针变量。
  指针数组也常用来表示一组字符串, 这时指针数组的每个元素被赋予一个字符串的首地址。 指向字符串的指针数组的初始化更为简单。例如在例6.20中即采用指针数组来表示一组字符串。 其初始化赋值为:
char *name[]={"Illagal day",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"};
   完成这个初始化赋值之后,name[0]即指向字符串"Illegal day",name[1]指?quot;Monday"......。
  指针数组也可以用作函数参数。在本例主函数中,定义了一个指针数组name,并对name 作了初始化赋值。其每个元素都指向一个字符串。然后又以name 作为实参调用指针型函数day name,在调用时把数组名 name 赋予形参变量name,输入的整数i作为第二个实参赋予形参n。在day name函数中定义了两个指针变量pp1和pp2,pp1被赋予name[0]的值(即*name),pp2被赋予name[n]的值即*(name+ n)。由条件表达式决定返回pp1或pp2指针给主函数中的指针变量ps。最后输出i和ps的值。
指针数组作指针型函数的参数
main(){
static char *name[]={ "Illegal day",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"};
char *ps;
int i;
char *day name(char *name[],int n);
printf("input Day No:/n");
scanf("%d",&i);
if(i<0) exit(1);
ps=day name(name,i);
printf("Day No:%2d-->%s/n",i,ps);
}
char *day name(char *name[],int n)
{
char *pp1,*pp2;
pp1=*name;
pp2=*(name+n);
return((n<1||n>7)? pp1:pp2);
}
下例要求输入5个国名并按字母顺序排列后输出。在以前的例子中采用了普通的排序方法, 逐个比较之后交换字符串的位置。交换字符串的物理位置是通过字符串复制函数完成的。 反复的交换将使程序执行的速度很慢,同时由于各字符串(国名) 的长度不同,又增加了存储管理的负担。 用指针数组能很好地解决这些问题。把所有的字符串存放在一个数组中, 把这些字符数组的首地址放在一个指针数组中,当需要交换两个字符串时, 只须交换指针数组相应两元素的内容(地址)即可,而不必交换字符串本身。程序中定义了两个函数,一个名为sort完成排序, 其形参为指
针数组name,即为待排序的各字符串数组的指针。形参n为字符串的个数。另一个函数名为print,用于排序后字符串的输出,其形参与sort的形参相同。主函数main中,定义了指针数组name 并作了初始化赋值。然后分别调用sort函数和print函数完成排序和输出。值得说明的是在sort函数中,对两个字符串比较,采用了strcmp 函数,strcmp函数允许参与比较的串以指针方式出现。name[k]和name[ j]均为指针,因此是合法的。字符串比较后需要交换时, 只交换指针数组元素的值,而不交换具体的字符串, 这样将大大减少时间的开销,提高了运行效率。
现编程如下:
#include"string.h"
main(){
void sort(char *name[],int n);
void print(char *name[],int n);
static char *name[]={ "CHINA","AMERICA","AUSTRALIA",
"FRANCE","GERMAN"};
int n=5;
sort(name,n);
print(name,n);
}
void sort(char *name[],int n){
char *pt;
int i,j,k;
for(i=0;i<n-1;i++){
k=i;
for(j=i+1;j<n;j++)
if(strcmp(name[k],name[j])>0) k=j;
if(k!=i){
pt=name[i];
name[i]=name[k];
name[k]=pt;
}
}
}
void print(char *name[],int n){
int i;
for (i=0;i<n;i++) printf("%s/n",name[i]);
}
main函数的参数
  前面介绍的main函数都是不带参数的。因此main 后的括号都是空括号。实际上,main函数可以带参数,这个参数可以认为是 main函数的形式参数。C语言规定main函数的参数只能有两个, 习惯上这两个参数写为argc和argv。因此,main函数的函数头可写为: main (argc,argv)C语言还规定argc(第一个形参)必须是整型变量,argv( 第二个形参)必须是指向字符串的指针数组。加上形参说明后,main函数的函数头应写为:
main (argc,argv)
int argv;
char *argv[];或写成:
main (int argc,char *argv[])
   由于main函数不能被其它函数调用, 因此不可能在程序内部取得实际值。那么,在何处把实参值赋予main函数的形参呢? 实际上,main函数的参数值是从操作系统命令行上获得的。当我们要运行一个可执行文件时,在DOS提示符下键入文件名,再输入实际参数即可把这些实参传送到main的形参中去。
  DOS提示符下命令行的一般形式为: C:/>可执行文件名 参数 参数……; 但是应该特别注意的是,main 的两个形参和命令行中的参数在
位置上不是一一对应的。因为,main的形参只有二个,而命令行中的参数个数原则上未加限制。argc参数表示了命令行中参数的个数(注意:文件名本身也算一个参数),argc的值是在输入命令行时由系统按实际参数的个数自动赋予的。例如有命令行为: C:/>E6 24 BASIC dbase FORTRAN由于文件名E6 24本身也算一个参数,所以共有4个参数,因此argc取得的值为4。argv参数是字符串指针数组,其各元素值为命令行中各字符串(参数均按字符串处理)的首地址。 指针数组的长度即为参数个数。数组元素初值由系统自动赋予。其表示如图6.8所示:
main(int argc,char *argv){
while(argc-->1)
printf("%s/n",*++argv);
}
本例是显示命令行中输入的参数如果上例的可执行文件名为e24.exe,存放在A驱动器的盘内。
因此输入的命令行为: C:/>a:e24 BASIC dBASE FORTRAN
则运行结果为:
BASIC
dBASE
FORTRAN
   该行共有4个参数,执行main时,argc的初值即为4。argv的4个元素分为4个字符串的首地址。执行while语句,每循环一次 argv值减1,当argv等于1时停止循环,共循环三次, 因此共可输出三个参数。在printf函数中,由于打印项*++argv是先加1再打印, 故第一次打印的是argv[1]所指的字符串BASIC。第二、 三次循环分别打印后二个字符串。而参数e24是文件名,不必输出。
  下例的命令行中有两个参数,第二个参数20即为输入的n值。在程序中*++argv的值为字符串“20”,然后用函数"atoi"把它换为整型作为while语句中的循环控制变量,输出20个偶数。
#include"stdlib.h"
main(int argc,char*argv[]){
int a=0,n;
n=atoi(*++argv);
while(n--) printf("%d ",a++*2);
}
   本程序是从0开始输出n个偶数。指向指针的指针变量如果一个指针变量存放的又是另一个指针变量的地址, 则称这个指针变量为指向指针的指针变量。
  在前面已经介绍过,通过指针访问变量称为间接访问, 简称间访。由于指针变量直接指向变量,所以称为单级间访。 而如果通过指向指针的指针变量来访问变量则构成了二级或多级间访。在C语言程序中,对间访的级数并未明确限制, 但是间访级数太多时不容易理解解,也容易出错,因此,一般很少超过二级间访。 指向指针的指针变量说明的一般形式为:
类型说明符** 指针变量名;
例如: int ** pp; 表示pp是一个指针变量,它指向另一个指针变量, 而这个指针变量指向一个整型量。下面举一个例子来说明这种关系。
main(){
int x,*p,**pp;
x=10;
p=&x;
pp=&p;
printf("x=%d/n",**pp);
}
   上例程序中p 是一个指针变量,指向整型量x;pp也是一个指针变量, 它指向指针变量p。通过pp变量访问x的写法是**pp。程序最后输出x的值为10。通过上例,读者可以学习指向指针的指针变量的说明和使用方法。
  下述程序中首先定义说明了指针数组ps并作了初始化赋值。 又说明了pps是一个指向指针的指针变量。在5次循环中, pps 分别取得了ps[0],ps[1],ps[2],ps[3],ps[4]的地址值(如图6.10所示)。再通过这些地址即可找到该字符串。
main(){
static char *ps[]={ "BASIC","DBASE","C","FORTRAN",
"PASCAL"};
char **pps;
int i;
for(i=0;i<5;i++){
pps=ps+i;
printf("%s/n",*pps);
}
}
本程序是用指向指针的指针变量编程,输出多个字符串。
本章小结
1. 指针是C语言中一个重要的组成部分,使用指针编程有以下优点:
(1)提高程序的编译效率和执行速度。
(2)通过指针可使用主调函数和被调函数之间共享变量或数据结构,便于实现双向数据通讯。
(3)可以实现动态的存储分配。
(4)便于表示各种数据结构,编写高质量的程序。
2. 指针的运算
(1)取地址运算符&:求变量的地址
(2)取内容运算符*:表示指针所指的变量
(3)赋值运算
·把变量地址赋予指针变量
·同类型指针变量相互赋值
·把数组,字符串的首地址赋予指针变量
·把函数入口地址赋予指针变量
(4)加减运算
对指向数组,字符串的指针变量可以进行加减运算,如p+n,p-n,p++,p--等。对指向同一数组的两个指针变量可以相减。对指向其它类型的指针变量作加减运算是无意义的。
(5)关系运算
指向同一数组的两个指针变量之间可以进行大于、小于、 等于比较运算。指针可与0比较,p==0表示p为空指针。
3. 与指针有关的各种说明和意义见下表。
int *p;     p为指向整型量的指针变量
int *p[n];   p为指针数组,由n个指向整型量的指针元素组成。
int (*p)[n];  p为指向整型二维数组的指针变量,二维数组的列数为n
int *p()    p为返回指针值的函数,该指针指向整型量
int (*p)()   p为指向函数的指针,该函数返回整型量
int **p     p为一个指向另一指针的指针变量,该指针指向一个整型量。
4. 有关指针的说明很多是由指针,数组,函数说明组合而成的。
但并不是可以任意组合,例如数组不能由函数组成,即数组元素不能是一个函数;函数也不能返回一个数组或返回另一个函数。例如
int a[5]();就是错误的。
5. 关于括号
在解释组合说明符时, 标识符右边的方括号和圆括号优先于标识符左边的“*”号,而方括号和圆括号以相同的优先级从左到右结合。但可以用圆括号改变约定的结合顺序。
6. 阅读组合说明符的规则是“从里向外”。
从标识符开始,先看它右边有无方括号或园括号,如有则先作出解释,再看左边有无*号。 如果在任何时候遇到了闭括号,则在继续之前必须用相同的规则处理括号内的内容。例如:
int*(*(*a)())[10]
↑ ↑↑↑↑↑↑
7 6 4 2 1 3 5
上面给出了由内向外的阅读顺序,下面来解释它:
(1)标识符a被说明为;
(2)一个指针变量,它指向;
(3)一个函数,它返回;
(4)一个指针,该指针指向;
(5)一个有10个元素的数组,其类型为;
(6)指针型,它指向;
(7)int型数据。
因此a是一个函数指针变量,该函数返回的一个指针值又指向一个指针数组,该指针数组的元素指向整型量。



符号位
  C语言规定,把内存的最高位作为符号位,且用0表示正数,用1表示负数。
2 在计算机中,负数以其正值的补码形式表示
2.1 原码
  一个整数,按照绝对值大小转换成的二进制数,称为原码。
如 00000000 00000000 00000000 00000110 是 6 的原码。
1
2.2 反码
  将二进制数按位取反,所得的新二进制数称为原二进制数的反码。
如 00000000 00000000 00000000 00000110 的反码是 11111111 11111111 11111111 11111001
1
2.3 补码
  反码加1称为补码。也就是说,要得到一个数的补码,先得到反码,然后反码加上1,所得数称为补码。
  所以 -6 在计算机器的表示形式为:
# -6 的正值 6 的二进制:
00000000 00000000 00000000 00000110

# 取反得反码:
11111111 11111111 11111111 11111001

# +1 得补码,即 -6 在计算机中的二进制表示:
11111111 11111111 11111111 11111010

模(Modulo)
1.1 什么是模数
In mathematics, modular arithmetic is a system of arithmetic for integers, where numbers “wrap around” upon reaching a certain value—the modulus (plural moduli).
1.1.1 理解
  模是指一个计量系统的计数范围。如时钟等。计算机也是一个计算器,它也是有一个计量范围,即都存在一个“模”。
  如时钟的计量范围是0~11,模 = 12。
  32位计算机的计量范围是2^32,模 = 2^32。
  “模”是计量器产生“溢出”的量,它的值在计量器上表示不出来,计量器上只能表示出模的余数,如12的余数有0,1,2,3,4,5,6,7,8,9,10,11。
1.2 补数
  假设当前时针指向11点,而准确时间是8点,调整时间可有以下两种拨法:
一种是倒拨3小时,即:11-3=8
另一种是顺拨9小时:11+9=12+8=8
  在以模为12的系统中,加9和减3效果是一样的,因此凡是减3运算,都可以用加9来代替。对“模”12而言,9和3互为补数(二者相加等于模)。所以我们可以得出一个结论,即在有模的计量系统中,减一个数等于加上它的补数,从而实现将减法运算转化为加法运算的目的。
1.3 再谈“模”
  从上面的化减法为加法,以及所谓的溢出等等可以看到,“模”可以说就是一个太极,阴阳转化,周而复始,无始无终,循环往复。
2 补码原理
  计算机上的补码就是算术里的补数。
  设我们有一个 4 位的计算机,则其计量范围即模是
2^4 = 16,所以其能够表示的范围是0~15,现在以计算 5 - 3为例,我们知道在计算机中,加法器实现最简单,所以很多运算最终都要转为加法运算,因此5-3就要转化为加法:
# 按以上理论,减一个数等于加上它的补数,所以
5 - 3
# 等价于
5 + (16 - 3) // 算术运算单元将减法转化为加法
# 用二进制表示则为:
0101 + (10000 - 0011)
# 等价于
0101 + ((1 + 1111) - 0011)
# 等价于
0101 + (1 + (1111 - 0011))
# 等价于
0101 + (1 + 1100) // 括号内是3(0011)的反码+1,正是补码的定义
# 等价于
0101 + 1101
# 所以从这里可以得到
-3 = 1101
# 即 `-3` 在计算机中的二进制表示为 `1101`,正是“ -3 的正值 3(`0011`)的补码(`1101`)”。
# 最后一步 0101 + 1101 等于
10010

  因为我们的计算机是 4 位的,第一位“溢出”了,所以我们只保存了 4 位,即 0010,而当计算机去读取时这正是我们所期望的 2!!叹为观止吧,天才般的设计!感恩伏羲、莱布尼兹和冯诺依曼!

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2018-04-19 15:07
243750496
可以使用系统函数system("pause");进行暂停。

1、system函数:
原型:int system(const char * command);
功能:执行 dos(windows系统) 或 shell(Linux/Unix系统) 命令,参数字符串command为命令名;
说明:在windows系统中,system函数直接在控制台调用一个command命令。在Linux/Unix系统中,system函数会调用fork函数产生子进程,由子进程来执行command命令,命令执行完后随即返回原调用的进程;
头文件:stdlib.h;
返回值:命令执行成功返回0,执行失败返回-1。
2、例程:

#include<stdio.h>
#include<stdlib.h>
int main(){
system("pause");//暂停
return 0;
}

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2018-04-20 15:31
243750496
打开http://wiki.codeblocks.org/index.php?title=Syntax_highlighting_custom_colour_themes


保存相关代码为CB_Color_Themes.conf
CB_Color_Themes.conf.txt
(91.56 KiB) 已下载 260 次
②运行安装目录下的cb_share_config.exe
cb_share_configure.jpg
③左边选择你下载的文件,右边选择 default.conf(一般这个文件地址是C:\用户\(你电脑的用户名)\AppData\Roaming\CodeBlocks\default.conf) 左边的全部勾上,然后依次点3个按钮(是否备份无所谓,默认主题会保留下来的)
3 steps.jpg
④重启Codeblocks,Settings→Editor→Syntax highlighting→colour theme就能看到咯


第1步<配置主题>:
主题效果可以点此去官网预览
打开codeblocks,setting(设置)->editor(编辑)->Syntax highlighting(语法高亮), 然后在右边的Colour theme(主题)里选择适合你的主题。<推荐obsidian、sublime>
1.png
注:点击Background->添加自定义颜色->记住上图的六个数据,后面会用到!
第三步<配置字体>:
setting(设置)->editor(编辑)->Font->Choose, 然后选择适合你的字体<推荐Consolas 大小:四号-14>
2.png
第2步<设置光标>:
可能用新的界面风格由于颜色会看不到光标,setting(设置)->editor(编辑)->Margins and caret->caret, 然后选择适合你颜色、大小的光标
3.png
第3步<设置左边行号区域部分>:
设置完以上四部应该会如下图所示,左边很丑。
4.png
接下来我们进行改装:
setting(设置)->Environment->Colurs, 然后就要用到第二步的六个数值!
如下图修改:
5.png

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2018-07-07 8:20
243750496
茶叶种类(淘宝上可买的到的):普洱只分熟茶生茶

黑茶:安化黑茶(带金花的)

黄茶:霍山黄芽、君山银叶

白茶:白牡丹、白毫银针

乌龙茶:铁观音、凤凰水仙、东方美人

红茶:滇红、祁门红茶、霍山红茶、宜兴红茶、安化红茶、川红、英德红茶

绿茶:信阳毛尖、桐城小花、湄潭翠芽、青城雪芽、峨眉毛峰、金坛雀舌、华顶云雾、井冈翠绿、九华佛茶、安庆绿茶、紫阳毛尖、庐山云雾、开化龙顶、太平猴魁、南京雨花茶、安吉白茶、侗乡雀舌、都匀毛尖、恩施玉露、永川秀芽、涌溪火青、蒙顶甘露、信阳毛尖、汉家刘氏绿茶、峨眉竹叶青、云雾绿茶、狗脑茶、六安瓜片、黄山毛峰、汉中仙毫、日照绿茶、碧螺春、兰馨雀舌、峨眉雪芽、西湖龙井

滇红茶(推荐金枝玉叶:中度花香有回甘):一叶金螺苦、一叶金芽药味重、大金芽有花香但微苦、古树滇红药味重淡苦味、黄金螺药味淡没特点、蜜香金芽药味重且酸苦、金丝滇红不苦有花香和回甘但回甘同时伴有药味

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2018-08-15 15:12
243750496
想了解自己的屏幕色域是多少的吗?一个个查规格书?实在是麻烦又费时,现在有
了更便捷的方法,请看:
(1)首先安装一个获取显示器信息的软件Monitor Asset Manager 2.9,地址如下:
https://www.entechtaiwan.com/util/moninfo.shtm
安装过程之类的不必啰嗦,是个人就会。好了,装好之后打开,界面如下:
Monitor Asset Manager.png
左上角红框中带有[Registry-Active]的是你当前使用的显示器的ID,右下角红框处的是屏幕颜色方面的信息,色域方面我们需要的是其中的蓝色框里面的信息。

(2)下载我提供的“色域计算.xls”表格,地址如下:
色域计算.xls
(22.5 KiB) 已下载 244 次
打开表格,在如图所示红色框起来的部分随便选择一行,在对应的位置填入刚才从软件当中获取的Rx、Ry、Gx、Gy、Bx、By信息,则NTSC百分比会自动计算出来,得到的结果就是你当前显示器的色域大小。

Re: Ubuntu&Fedora装机&Mac装机(Mac装机将会持续更新)

发表于 : 2018-11-23 15:13
243750496
Windows软件:

Snipaste,librePCB
Software on Desktop.png
Silo,3DCoat,Affinity Photo+Designer+Publisher,On1 Photo,OpenCanvas7,Xmind 8,Office,Steam,NordVPN,AnyVideoConverter Ultimate,AnyDVDCloner Platinum,Batch Photo,Anatomy and Physiology,PDFElement6 PRO,AutoQ3D CAD,BricsCAD ,天翼云盘,百度网盘,腾讯微云,CleanMyPC,VivaDesigner,Bitwig Studio,Alcohol 120%,Data Rescue,Trello,Modo,iTunes,MacProVideo Player,Simplify3D Software,微信,虾米音乐,AC3D,Bloom,Sketchbook,Laplink PC Mover Professional,ClipGrab,控制面板,PCBDroid,Eagle,PaintStorm Studio,Concepts,Explain Everything,Imazing HEIC Converter,ArtRange,MuseScore,FLStudio
Software on Start up Screen .png
Software on Start up Screen 2 .png
Software on Start up Screen 3 .png
Ipad 软件:

设置,相机,时钟,APP Store,网易蜗牛读书,bilibili,查找,ZAKER HD,Ravenscroft 275 Piano,115网盘,QQ邮箱,Trello,照片,网银云音乐HD,网易邮箱大师,手机淘宝,百度Hi HD,微信,酷狗音乐HD

not oftern use:网易新闻,考拉海购,网易云课堂,forger,scuulptur,qlone,Face Model,manus,singer'sStudio,Tenuto,infinite painter ,Texpad,shapr3d,pixiv,虾米音乐

Working:Facetune 2,Photofox,Videoleap,Affinity Photo+Designer,ColorInspiron,ipalettes,Artstudio Pro,Paintstorm,概念画板,Floorplans,Umake,建筑平面图,AutoQ3D CAD,LumaFusion,Symphony Pro 5,TT语音

Entertainment:Authy,Merriam-Webster Dictionary Pro,牛津高阶,Bravolol,Toolbox PRO,BookScanner,Dice,微信读书,kindle,OplayerHD,HBO Now,Decibel X Pro,Musescore,BeatHawk,Carrot(天气),搜狗输入法

Others:OneDrive,什么垃圾,ItunesU,imovie剪辑,keynote演讲,numbers表格,pages文档,可立拍,库乐队,字幕浏览器PRO,花田,Relax Melodies,Relax Melodies P,ASUS Router,菜鸟裹裹

Buiness:顺丰速运,中国建设银行,Brain Trainer,IPasse,100%-A memory challange,文本音乐(1351),My Wishes,P站助手,信息,坚果云,outlook,WPS,AnyDESK,向日葵,立创商城,codehub

Tools:Word Excel PowerPoint,Xmind,,Copper,cad看图王,PDF Expert,Scanner Pro,Printer Pro,iZip Pro,Neflix,FiLMic专业版 ,USBDisk Pro,测距仪,ArtRage,Guitar PRO,

Life:弹琴吧,iXpand Drive,Filmic Remote,Youtube,My W Goals ,my W Days,Explain Everything,Star walk 2,MedBang Paint,小米有品,百度地图,阿里tv助手,爱城市网,青桔,山东一卡通,猫耳FM

Draft:Procreate,Vectornator,Morpholio Trace,Stave'n'Tabs,Putty3D,StavenTabs,Putty 3D,Real Guitar,PretaTemplate,ArtPoseME,ArtPoseFE,ArtPosePro,FLStudioMobile,ILRemote,bilibili漫画

Utilities1:天翼云盘,sendanywhere,ASUS Lyra,Exif Viewer,计算器air,AR Viewer,PDF Converter,Anatomy and Physiology,AdBlock,LumaFX,Authenticatior,PubReader,Pub Converter,京东,网易严选,apple store

Utilies2:视频(apple),遥控器(apple),联通手机营业厅,电信营业厅,中国移动,央视影音HD,Flock ,米家,文件,邮件(apple),小米运动,备忘录(apple),QQ音乐HD,百度网盘HD,京东读书,QQ空间

文件夹:必胜客,麦当劳Pro,美团外卖,饿了么,英语语法(Grammar图标的),慧语法,肯德基,Gitter,百度帐号管家,QQ安全中心,轻蜂加速器,爱加速,Chrome,QQ,Paypal,Ebay

底栏:Hayday,微店店长版,QQ,ZenBrush2,Sketchbook,Ipalettes,微云,工商银行,工银融e联,支付宝,Safari