第一个C程序
Tips
C/C++的源代码文件是一个普通的文本文件,C语言扩展名必须是.c
。
编写代码
打开IDE或者文本编辑器,编写以下代码
#include <stdio.h>
#include <stdlib.h>
int main(void) {
// 输出 Hello World
printf("Hello World\n");
// system("pause"); // 低版本VS中需要此语句来控制cmd窗口在程序结束后不退出
return 0;
}
代码分析
include头文件包含
#include
的意思是头文件包含,#include <stdio.h>
代表包含stdio.h这个头文件;相应的#include <iostream>
代表包含iostream这个头文件- 使用C语⾔库函数需要提前包含库函数对应的头文件,如这里使用了printf()函数,需要包含stdio.h头文件
- Linux系统可以通过
man 3 printf
查看 printf 函数所需的头文件
stdio.h文件位置
在 Linux 系统中stdio.h在操作系统的系统目录下,可以使用以下命令进行确认
ls -l /usr/include | grep stdio.h
#include< > 与 #include "" 的区别
< >
表⽰系统直接按系统指定的目录检索""
表⽰系统先在""
指定的路径查找头文件(没写路径代表当前路径),如果找不到再按系统指定的目录检索using namespace std;
使用标准命名空间printf
和cout
功能一样,都是向标准输出中输出内容
main函数
一个完整的C语⾔程序,是由一个、且只能有一个 main()
函数(又称主函数,必须有)和若⼲个其他函数结合而成(可选)。main函数是C语⾔程序的⼊口,程序是从main函数开始执行。
- 在C语言的标准规范中,
int main()
表示一个函数可以接受任意数量的参数。这种声明方式不指定函数形参的数量和类型,具体的实现由编译器平台自己决定。 - 在C语言规范标准中,
int main(void)
明确指出函数不接受任何参数。 - 在C++标准中,
int main()
和int main(void)
这两种声明在C++中被视为等价的,都表示主函数不接受任何参数。
综上所述,我们给出以下结论和建议:
- 如果是在C++当中,二者没有区别,是等价的声明方式。
- 如果是在C语言当中,规范的C语言代码中,应该使用
void
填充形参列表,以明确表示某个函数不需要传入任何参数,这是一个规范的做法!
Tips
操作系统在调用main函数时,是可以给main函数传参的,这就是命令行参数。当然若想要在调用main函数时,给main函数传参,main函数的形参就不能再使用void了,需要使用如下形式
int main(int argc, char *argv[]){
return 0;
}
程序体和代码块
- 使用
{}
包裹的内容叫代码块,一个代码块内部可以有一条或者多条语句 - C语⾔每句可执行代码都是
;
分号结尾 - 所有的
#
开头的行,都代表预编译指令,预编译指令行结尾是没有分号的 - 所有的可执行语句必须是在代码块里⾯
注释
注释用于解释代码,使得代码更容易被理解。。C语言有两种类型的注释:
单行注释。使用 开头。从双斜杠开始,直到该行结束的所有内容都会被视为注释。单行注释仅能使某一行成为注释。
cpp// 这个函数用于计算两个整数的和 int add(int a, int b) { return a + b; // 返回两个整数的和 }
多行注释(也叫块注释)。从开始到结束,中间的部分都属于注释。这种注释可以跨越多行。
cpp/* * 这是一个多行注释。 * 这里可以写很多行的解释和描述。 */ int x = 5; /* 这也是一个多行注释,但多行注释尽量不要用于注释单行 */
注释本身是一个简单的语法,也不参与编译不影响程序执行,基本是一个随意使用的语法。下面提一些小的注意事项:
- 单行注释通常用于解释一行代码或代码的一个小段。
- 多行注释通常用于解释一个代码块、一个结构,比如解释一个函数。
- 不要嵌套多行注释。
注意事项
单行注释实际上直到C99才成为C语言的官方标准语法,在较早的C标准中,如C90,单行注释并不是合法的C语言语法。所以如果你希望需要与旧版C标准兼容,最好避免使用单行注释,并使用多行注释来进行注释。(但一般不需要,我们前面提到过常用的C语言版本当中,最旧的就是C99)
- cpp
/* * 有星号 * 有星号 * 有星号 */
多行注释不推荐形式
cpp/* 没有星号 没有星号 没有星号 */
某些公司团队,在写单行注释时会在后面加一个空格再写注释信息。但也可以不加,这是根据个人或团队的编程风格和偏好而定的。
cpp// 这是一个单行注释,后面有空格 int x = 10; //这是一个单行注释,后面没有空格 int y = 20;
printf函数
printf是C语⾔库函数,功能是向标准输出设备输出一个字符串。
printf("Hello World\n");
// 向屏幕输出 Hello World
// \n的意思是回车换行
system函数
函数原型
#include <stdlib.h>
int system(const char* command);
功能:在已经运行的程序中执行另一个外部程序
参数:外部可执行程序名字
返回值:
- 成功:
0
- 失败:任意数字
示例代码
// 使用system函数需要引入头文件#include <stdlib.h>
#include <stdlib.h>
int main(void) {
//windows平台,作用是唤起系统⾃带计算器软件
system("calc");
//Linux平台,作用是列出当前工作目录下的文件
//system("ls");
return 0;
}
运行结果:
return语句
return
代表函数执行完毕,使用return
语句返回代表函数的终⽌如果
main
定义的时候前⾯是int
,那么return
后⾯就需要写一个整数;如果main
定义的时候前⾯是void
,那么return
后⾯什么也不需要写在main函数中
return 0;
代表程序执行成功,return -1;
代表程序执行失败int main()
和void main()
在C语⾔中是一样的,但C++只接受int main()
这种定义⽅式
main函数的参数
main 函数有三个参数,argc、argv 和 envp,它的标准写法如下:
int main(int argc, char *argv[], char *envp[]) {
return 0;
}
- argc 存放了程序参数的个数,包括程序本身。
- argv 字符串的数组,存放了每个参数的值,包括程序本身。
- envp 字符串的数组,存放了环境变量,数组的最后一个元素是空。
在程序中,如果不关心 main()函数的参数,可以省略不写。
输出参数
#include <stdio.h>
int main(int argc, char *argv[])
{
for (int i = 0; i < argc; ++i)
{
printf("%s\n", argv[i]);
}
return 0;
}
运行结果:
$ gcc 01-argv.c
$ ls
01-argv.c a.out
$ ./a.out
./a.out
$ ./a.out aa 123 bb 456 cc
./a.out
aa
123
bb
456
cc
$
输出环境变量
#include <stdio.h>
int main(int argc, char *argv[], char *envp[])
{
for (int i = 0; envp[i] != 0; ++i)
{
printf("%s\n", envp[i]);
}
return 0;
}
运行结果:
$ gcc 02-env.c
$ ./a.out
SHELL=/bin/bash
SESSION_MANAGER=local/ubt:@/tmp/.ICE-unix/1398,unix/ubt:/tmp/.ICE-unix/1398
QT_ACCESSIBILITY=1
COLORTERM=truecolor
XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/etc/xdg
XDG_MENU_PREFIX=gnome-
TERM_PROGRAM_VERSION=1.99.3
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
LANGUAGE=zh_CN:en
LC_ADDRESS=zh_CN.UTF-8
GNOME_SHELL_SESSION_MODE=ubuntu
LC_NAME=zh_CN.UTF-8
SSH_AUTH_SOCK=/run/user/1000/keyring/ssh
MEMORY_PRESSURE_WRITE=c29tZSAyMDAwMDAgMjAwMDAwMAA=
XMODIFIERS=@im=ibus
DESKTOP_SESSION=ubuntu
LC_MONETARY=zh_CN.UTF-8
GTK_MODULES=gail:atk-bridge
PWD=/media/psf/code/c/main
XDG_SESSION_DESKTOP=ubuntu
LOGNAME=syss
XDG_SESSION_TYPE=wayland
SYSTEMD_EXEC_PID=1451
XAUTHORITY=/run/user/1000/.mutter-Xwaylandauth.WWCG52
NODE_HOME=/usr/local/node-v22.14.0-linux-arm64
VSCODE_GIT_ASKPASS_NODE=/usr/share/code/code
IM_CONFIG_CHECK_ENV=1
GJS_DEBUG_TOPICS=JS ERROR;JS LOG
HOME=/home/syss
USERNAME=syss
IM_CONFIG_PHASE=1
LC_PAPER=zh_CN.UTF-8
LANG=zh_CN.UTF-8
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=00:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.avif=01;35:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.webp=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:*~=00;90:*#=00;90:*.bak=00;90:*.crdownload=00;90:*.dpkg-dist=00;90:*.dpkg-new=00;90:*.dpkg-old=00;90:*.dpkg-tmp=00;90:*.old=00;90:*.orig=00;90:*.part=00;90:*.rej=00;90:*.rpmnew=00;90:*.rpmorig=00;90:*.rpmsave=00;90:*.swp=00;90:*.tmp=00;90:*.ucf-dist=00;90:*.ucf-new=00;90:*.ucf-old=00;90:
XDG_CURRENT_DESKTOP=Unity
MEMORY_PRESSURE_WATCH=/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/session.slice/org.gnome.Shell@wayland.service/memory.pressure
WAYLAND_DISPLAY=wayland-0
GIT_ASKPASS=/usr/share/code/resources/app/extensions/git/dist/askpass.sh
INVOCATION_ID=cb53246594c74274b656d7830b7a6c47
MANAGERPID=1181
CHROME_DESKTOP=code.desktop
GJS_DEBUG_OUTPUT=stderr
VSCODE_GIT_ASKPASS_EXTRA_ARGS=
GNOME_SETUP_DISPLAY=:1
LESSCLOSE=/usr/bin/lesspipe %s %s
XDG_SESSION_CLASS=user
TERM=xterm-256color
LC_IDENTIFICATION=zh_CN.UTF-8
LESSOPEN=| /usr/bin/lesspipe %s
USER=syss
VSCODE_GIT_IPC_HANDLE=/run/user/1000/vscode-git-523837d516.sock
CLUTTER_DISABLE_MIPMAPPED_TEXT=1
DISPLAY=:0
SHLVL=1
GSM_SKIP_SSH_AGENT_WORKAROUND=true
LC_TELEPHONE=zh_CN.UTF-8
QT_IM_MODULE=ibus
LC_MEASUREMENT=zh_CN.UTF-8
PAPERSIZE=a4
XDG_RUNTIME_DIR=/run/user/1000
DEBUGINFOD_URLS=https://debuginfod.ubuntu.com
LC_TIME=zh_CN.UTF-8
VSCODE_GIT_ASKPASS_MAIN=/usr/share/code/resources/app/extensions/git/dist/askpass-main.js
JOURNAL_STREAM=9:13909
XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/
GDK_BACKEND=x11
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/node-v22.14.0-linux-arm64/bin:/home/syss/.npm-global/bin:/usr/local/node-v22.14.0-linux-arm64/bin:/home/syss/.npm-global/bin
GDMSESSION=ubuntu
ORIGINAL_XDG_CURRENT_DESKTOP=ubuntu:GNOME
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
GIO_LAUNCHED_DESKTOP_FILE_PID=121605
GIO_LAUNCHED_DESKTOP_FILE=/usr/share/applications/code.desktop
LC_NUMERIC=zh_CN.UTF-8
TERM_PROGRAM=vscode
_=./a.out
OLDPWD=/media/psf/code/c
$
通过运行可以看到环境变量的信息是自动传入的,无需手动传入。并且环境变量是一个字符串数组,每个元素都是一个环境变量的信息,最后一个元素是空。
环境变量
在上面内容中我们提到了环境变量,那么什么是环境变量呢?
环境变量是一个全局变量,它可以在任何地方使用,并且可以被任何程序访问。
我们还可以设置只在本进程中生效的环境变量,这种环境变量叫做局部环境变量。
函数原型
#include <stdlib.h>
int setenv(const char *name, const char *value, int overwrite);
int unsetenv(const char *name);
char *getenv(const char *name);
char *secure_getenv(const char *name);
函数参数
- name 环境变量名。
- value 环境变量的值。
- overwrite
- 0:如果环境不存在,增加新的环境变量,如果环境变量已存在,不替换其值;
- 非0:如果环境不存在,增加新的环境变量,如果环境变量已存在,替换其值。
返回值
- 0:成功;
- -1:失败(失败的情况极少见)。
注意
此函数设置的环境变量只对本进程有效,不会影响 shell 的环境变量。如果在运行程序时执行了 setenv()函数,进程终止后再次运行该程序,上次的设置是无效的。
示例代码
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[], char *envp[])
{
setenv("test-env", "0000", 1);
printf("%s\n", getenv("test-env"));
return 0;
}
运行结果:
$ gcc 03-env.c
$./a.out
0000
$