在c语言中,main函数一般为程序运行的入口函数,代码是从main函数开始执行,main函数有两个参数:
int main(int argc,char**argv){
......
}
在Linux下,其中argc 为运行程序时用户所输入的命令行参数个数,如:./hello则命令行参数为1,而./my_ls -l 这种可执行程序命令行参数为2,没有接触linux操作系统的人在理解这个问题上可能不是很容易,其中argv为二维指针,argv[0~(argc-1)]指向每一项命令字符串的首地址,这个在linux 里面学习文件系统编程时,会用到,且比较重要。在其他地方的用途,目前尚未接触。
- 数组指针:顾名思义,即指向数组的指针,相当于一个二级指针常量:
简单示例:
![#include<stdio.h>
int main(){
int b[3][5]={{1,2,3,3,4},{2,4,5,6,7},{6,7,8,8,6}};
int * q;
int (*p)[5];
for(p=b;p<b+3;p++){
for(q=*p;q<*p+5;q++)
printf("%5d",*q);
printf("\n");
}
}
结果如下:
从上面示例我们不难看出,p为指向二维数组第二维的长度为5的数组指针,先将b赋给p,如果看不懂,可以理解,咱们分析一下,这一操作就是类似于:
p[0]=*(b+0);//可以将p也当作二级指针,但每次必须移动5个整型数的长度来遍历数据,
//这一步和循环第一步赋值操作,使二维指针*p先指向了b[0]首地址
第二层循环是让p指向q的地址,要想获得b内元素的值,或者是通过二级解引用q获得,或者是通过一级解引用p,获得b的值。
- 指针数祖
再来一个例子:
int main(){
int nums[3][3]={1,2,3,4,5,6,7,8,9};
printf("%d\n",nums[1][-2]);
printf("%d\n",(-1)[nums][5]);
printf("%d\n",-1[nums][5]);
return 0;
}
想一下这个程序结果会输出什么东西?看下结果:
是不是和你想的一样呢,如果是,那说明c语言基础还不错,分析代码,nums[1][-2]什么意思?我们可以将数组名看成一个一维指针,而括号里的数字我们来解析一下:
nums[1][-2] 我们通常将一维指针如:num[1]可以写成(num+1),可以类比这个nums[1][-2]我们该怎样写呢?(*(nums+1)-2),恩,就是酱紫,和你写的一样吗,理解就是,由于数组是连续性的存储数据,从nums[0][0]开始将nums先移动3个整型长度,对就是3个,里面加1,如果把二维数组比作一个元素为一维数组的一维数组,那么里面加一,就要将指针移动二维数组每个元素规定的长度,这又回到了数组指针那一块,我不多讲了。然后外层加-2,就移动两个整型元素的长度,这样移动下来就会移到所显示相应的值的地址。
- 结构体对齐
程序为了提高读取数据的效率,规定结构体必须对齐,一般程序自动对齐结构体。
struct icd{
int a;
char b;
double c;
}
struct idc{
char a;
double b;
int c;
}
int main(){
printf("%zu %zu\n",sizeof(struct icd),sizeof(struct idc));
return 0;
}
程序结果:
想下会输出什么?根据结构体对齐
int 4 个字节 |
---|
char 1个字节 |
double 8个字节 |
加起来好像icd 总共13个字节,其实根据结构体对齐应该占16个字节
下来看一下结构体对齐规则:
•原则1
数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。
•原则2
结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。)
•原则3
收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。
这样是不是清晰了很多,其实结构体补齐看一下规则就会懂得,所以我也不啰嗦了~~