1. 指针与地址
1.1 指针变量也是变量
指针变量也是变量,int **p : p 是个指针变量,p 中保存的是一个 int * 类型变量的地址,指向只指针的指针。
1.2 指针变量占用的空间
64位操作系统中,指针变量占 8 个字节;32位操作系统中,指针变量占 4 个字节。
1.3 指针代码演示
#include <stdio.h>
int main() {
int num = 0x616263;
printf("%s\n", (char *)(&num));
return 0;
}
num 并不会因为数据表现形式的不同而改变,num 是一个整型变量,占 4 个字节,也可以看做是长度为 4 的字符数组。 每个十六进制数值需要 4 个二进制位表示,所以十六进制中两个数(占8位)为一个字节,因此是每两个数放在一个字节中。
为什么输出结果为cba? 十六进制的63,62,61对应的十进制值是99,98,97,ASCII码中对应于字符c,b,a,而0对应的就是字符\0 ,所以打印的时候遇到 \0 就结束了,因此结果为 cba 。
1.4 栈区地址的增长
#include <stdio.h>
int main() {
int num1 = 0x616263;
int num2 = 0x61626364;
printf("%s\n", (char *)(&num1));
printf("%s\n", (char *)(&num2));
printf("%s\n", (char *)(&num2 + 1));
return 0;
}
为什么 num2 的输出结果为 dcbacba ? 首先,内存占用图如下: 局部变量保存在栈区,num1 和 num2 都要入栈,而栈区的增长是从高地址到低地址,也就呈现了上图中的内存占用分布。 输出 num2 的时候,从 num2 的首地址开始,一直到 \0 结束,所以就输出了 dcbacba 。
在阿里云上执行如下程序:
#include <stdio.h>
int main() {
int num1 = 0x616263;
int num2 = 0x61626364;
printf("num1 = %s\n", (char *)(&num1));
printf("num2 = %s\n", (char *)(&num2));
}
先输出num1 ,结果为 cba ;再输出num2 ,结果为 dcba 。而如果没有第 6 行,num2 的输出结果为 dcbacba ,出现这个结果的原因是阿里云使用的是 瓦片式存储,因为cba 是一样的,于是就叠加,即存储在一个位置。该存储方式的有点是提高内存空间利用率。
2. 函数指针与main函数
int (*add)(int, int);
typedef int (*add)(int, int);
2.1 typedef 的用法
typedef long long lint;
typedef char *pchar;
typedef struct __node {
int x, y;
} Node, *PNode
typedef int (*func)(int);
2.1.1 #define 和 typedef
#include <stdio.h>
#define ppchar char *
typedef char * pchar;
int main() {
pchar p1, p2;
ppchar p3, p4;
printf("p1 = %lu, p2 = %lu\n", sizeof(p1), sizeof(p2));
printf("p3 = %lu, p4 = %lu\n", sizeof(p3), sizeof(p4));
return 0;
}
sizeof(p4) 的值之所以为 1,是因为宏替换出现了问题。使用 g++ -E 查看宏替换后的代码:
typedef char * pchar;
int main() {
pchar p1, p2;
char * p3, p4;
printf("p1 = %lu, p2 = %lu\n", sizeof(p1), sizeof(p2));
printf("p3 = %lu, p4 = %lu\n", sizeof(p3), sizeof(p4));
return 0;
}
宏只是进行了简单的替换,容易出错。
2.2 函数指针
- 函数指针变量:
int (*add)(int, int); - 函数指针类型:
typedef int (*add)(int, int);
2.3 main函数参数
int main();
int main(int argc, char *argv[]);
int main(int argc, char *argv[], char **env);
操作系统调用 main 函数,返回值给操作系统。
2.3.1 main函数带2个参数
#include <stdio.h>
void output(int argc, char *argv[]) {
printf("argc = %d\n", argc);
for (int i = 0; i < argc; i++) {
printf("%s\n", argv[i]);
}
return ;
}
int main(int argc, char *argv[]) {
output(argc, argv);
return 0;
}
运行结果:
./a.out
argc = 1
./a.out
./a.out hello world
argc = 3
./a.out
hello
world
./a.out "hello world"
argc = 2
./a.out
hello world
2.3.2 main函数带 3 个参数
#include <stdio.h>
void output(int argc, char *argv[], char **env) {
printf("argc = %d\n", argc);
for (int i = 0; i < argc; i++) {
printf("%s\n", argv[i]);
}
for(int i = 0; env[i]; i++) {
printf("env[%d] = %s\n", i, env[i]);
}
return ;
}
int main(int argc, char *argv[], char **env) {
output(argc, argv, env);
return 0;
}
运行结果:
argc = 1
./a.out
env[0] = TERM_SESSION_ID=w0t0p1:2F0E81F5-BB38-46DB-B596-5AE909019E39
env[1] = SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.u2uRbeIcuB/Listeners
env[2] = LC_TERMINAL_VERSION=3.3.12
env[3] = COLORFGBG=7;0
env[4] = ITERM_PROFILE=Default
env[5] = XPC_FLAGS=0x0
env[6] = LANG=zh_CN.UTF-8
env[7] = PWD=/Users/maureen/workspace/c_project/course
env[8] = SHELL=/bin/zsh
env[9] = TERM_PROGRAM_VERSION=3.3.12
env[10] = TERM_PROGRAM=iTerm.app
env[11] = PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin
env[12] = LC_TERMINAL=iTerm2
env[13] = COLORTERM=truecolor
env[14] = TERM=xterm-256color
env[15] = HOME=/Users/maureen
env[16] = TMPDIR=/var/folders/jl/14pjh5x96wd7xwk63xkwxcx80000gn/T/
env[17] = USER=maureen
env[18] = XPC_SERVICE_NAME=0
env[19] = LOGNAME=maureen
env[20] = ITERM_SESSION_ID=w0t0p1:2F0E81F5-BB38-46DB-B596-5AE909019E39
env[21] = __CF_USER_TEXT_ENCODING=0x0:25:52
env[22] = SHLVL=1
env[23] = OLDPWD=/Users/maureen/workspace/c_project
env[24] = ZSH=/Users/maureen/.oh-my-zsh
env[25] = PAGER=less
env[26] = LESS=-R
env[27] = LSCOLORS=Gxfxcxdxbxegedabagacad
env[28] = _=/Users/maureen/workspace/c_project/course/./a.out
可以使用 env[17] 即系统变量 USER 设置密码锁。
2.3.3 使用USER环境变量设置密码锁
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void output(int argc, char *argv[], char **env) {
printf("argc = %d\n", argc);
for (int i = 0; i < argc; i++) {
printf("%s\n", argv[i]);
}
for(int i = 0; env[i]; i++) {
if (!strncmp(env[i], "USER=", 5)) {
if (!strcmp(env[i] + 5, "maureen")) {
printf("welcome Maureen\n");
} else {
printf("You are not the user! Please gun!\n");
exit(0);
}
}
}
return ;
}
int main(int argc, char *argv[], char **env) {
output(argc, argv, env);
return 0;
}
|