一、指针和二维数组
#include <stdio.h> int main(int argc, const char *argv[]) { int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; //&a:二维数组名取地址表示地址的升级,将行指针变化为指向整个数组的指针 printf("&a = %p\n",&a); printf("&a = %p\n",&a + 1); printf("a = %p\n",a); printf("a = %p\n",a + 1); //*a:二维数组名取*表示地址降级, //将行指针降级为列指针,此时*a的操作空间是4个字节 printf("*a = %p\n",*a); printf("*a = %p\n",*a + 1); printf("**a = %d\n",**a); printf("*(*a+1) = %d\n",*(*a+1)); //a[i][j]------> *(*(a + i) + j) int i,j; for(i = 0 ; i < 3;i++) { for(j = 0 ; j < 4;j++) { //printf("%-5d",a[i][j]); printf("%-5d",*(*(a+i) + j)); } putchar(10); } return 0; }
二、数组指针
#include <stdio.h> int main(int argc, const char *argv[]) { int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; //一级指针p的操作空间只有4个字节,但是二维数组的数组名操作空间是一行数据的大小,也就是16个字节,所以无法 //使用一级指针保存二维数组的首地址 //int *p = a; //错误 //二级指针用于保存一级指针的地址,二维数组名是一个行指针,性质和操作空间不一致 // int **p = a; //错误 // //真正用于保存二维数组的数组名的地址或者说定义一个行指针的方法是定义一个数组指针 //数组指针:本质是一个指针,指针指向一个二维数组,就是定义一个行指针 //格式: 数据类型 (*变量名)[列数] //用途: 数组指针的真正用途试讲一个二维数组通过传参传递给指定函数 int (*p)[4] = a; int i,j; for(i = 0 ; i < 3;i++) { for(j = 0 ; j < 4;j++) { printf("%-5d",p[i][j]); } putchar(10); } return 0; }
三、指针数组
指针数组:本质是一个数组,数组的每一个元素是一个指针
格式: 数据类型 *变量名[数组下标]
例如: int *a[4];
解释:定义一个名为a的指针数组,数组一共有4个元素,每个元素都是int *的指针
#include <stdio.h> int main(int argc, const char *argv[]) { int *a[4]; int num1 = 100; int num2 = 200; int num3 = 300; int num4 = 400; //使用指针数组保存变量的地址 //指针数组的每一个元素都是int *的指针变量 a[0] = &num1; a[1] = &num2; a[2] = &num3; a[3] = &num4; //遍历指针数组 int i; for(i = 0 ; i < 4;i++) { printf("%d ",*a[i]); } putchar(10); char *p[4]; char s1[] = "hello world"; char s2[] = "hello beijing"; char s3[] = "hahahah"; char s4[] = "nihao nanjing"; p[0] = s1; p[1] = s2; p[2] = s3; p[3] = s4; for(i = 0 ; i < 4;i++) { printf("p[%d] =%s\n",i,p[i]); } return 0; }
四、指针和字符串
#include <stdio.h> int main(int argc, const char *argv[]) { char s1[] = "hello world"; char s2[] = "hello world"; printf("s1 = %p\ns2 = %p\n",s1,s2); char *p1 = "hello world"; char *p2 = "hello world"; printf("p1 = %p\np1 = %p\n",p1,p2); //p1[5] = '8'; //printf("p1 = %s\n",p1); p1 = "www.baidu.com"; printf("p1 = %p %s\n",p1,p1); return 0; }
五、多级指针
#include <stdio.h> int main(int argc, const char *argv[]) { int a = 100; //一级指针保存普通变量的地址 int *p = &a; //二级指针保存一级指针的地址 int **q = &p; //三级指针保存二级指针的地址 int ***w = &q; printf("a = %d %d %d %d\n",a,*p,**q,***w); printf("a = %p %p %p %p\n",&a,p,*q,**w); printf("p = %p %p %p\n",&p,q,*w); printf("q = %p %p\n",&q,w); return 0; }
六、const 关键词
6.1 全局变量和局部变量
#include <stdio.h> //我们内存分为很多区域, //定义变量时会根据定义的位置和存储类型放在特定的区域里 //简单的说:全局区,静态区,栈区,堆区,常量区,代码区等 // //在函数外部定义的变量称之为全局变量,保存在内存的全局区 //全局变量可以在当前代码的任意位置(主函数或者子函数)使用 int num = 100; //全局变量如果不初始化,会自动初始化为0 int a; int myval = 999; int main(int argc, const char *argv[]) { printf("num = %d\n",num); num = 888; printf("num = %d\n",num); printf("a = %d\n",a); //在函数内部定义的变量称之为局部变量,如果不使用存储类型修饰,则当前变量存储在栈区 //栈区的空间如果不初始化,里面存放的是随机值 int b; printf("b = %d\n",b); printf("myval = %d\n",myval); int myval = 888; printf("myval = %d\n",myval); return 0; }
6.2 const 修饰全局变量和局部变量
const关键字主要表示只读,但是也要分场合
#include <stdio.h> //const修饰全局变量,只能使用这个变量的值,无论如何也不能改变 const int num = 100; int main(int argc, const char *argv[]) { const int myval = 111; //int *p = # //*p = 111; //printf("*p = %d\n",num); //myval = 222; //printf("myval = %d\n",myval); //const如果修饰的一个局部变量,不能直接通过变量改值,但是可以通过变量保存地址的方法修改值。 int *q = &myval; *q = 222; printf("myval = %d\n",myval); printf("myval = %p q = %p\n",&myval,q); return 0; }
6.3 const 修饰指针变量和修饰指针变量的类型
#include <stdio.h> int main(int argc, const char *argv[]) { int a = 100; //int *p = &a; //const修饰的是指针变量的类型,无法通过指针变量修改指向的地址的内容 //const int *p = &a; //const修饰的是 指针变量p, //无法修改指针的指向 int *const p = &a; //const修饰的是指针变量的类型,无法通过指针变量修改指向的地址的内容 //int const *p = &a; //const既修饰指针变量的类型又修饰指针变量, //则p的指向和p指向的内存的值都无法修改 //const int * const p = &a; //*p = 300; int b = 400; p = &b; return 0; }
七、存储类型
auto
register
static
extern
7.1 auto
默认定义的变量的时候,如果不加存储类型,一般就表示一个局部变量
例如:
auto int num = 100;
int a = 100;
7.2 register
register修饰的变量可能会在寄存器空间开辟区域,这样运行效率会大大提高
寄存器的空间不一定能申请到,申请不到,会自动变成auto修饰
#include <stdio.h> int main(int argc, const char *argv[]) { register int i,j; for(i = 1;i <=10000;i++) { for(j = 1;j <= 10000;j++) { } } return 0; }
7.3 static
#include <stdio.h> int main(int argc, const char *argv[]) { //static修饰的变量保存在静态区 //如果不初始化会自动赋值为0 static int num; printf("num = %d\n",num); return 0; }
7.4 extern
extern外部引用,用extern修饰的变量可以在其它文件中使用,在一个文件中定义的全局变量可以在当前文件中使用extern获取到指定的变量,对应变量的值是可以使用的
八 函数
8.1 函数的相关概念
函数就是将一堆要执行的代码放在一个代码块例,然后给这段代码起个名字,,只要使用名字就相当于执行里面的代码块,所以函数很好的解决了代码的重用性问题。 1.通过函数名找到函数的入口地址(函数名就是地址) 2.给形参分配空间 3.传参,传值(把实参的值传递给形参的值)(值传递,地址传递) 4.执行函数体 5.结果返回到调用的地方 6.释放空间(栈空间)
8.2 定义一个函数以及函数的调用
8.2.1 函数的定义和调用
#include <stdio.h> //一般函数定义在main函数的外部,方便其他程序调用 //myfun:函数名,是一个标识符,满足标识符的命名规则 //void:返回值类型,如果没有返回值,写void //():里面是要传入的参数,如果没有参数,可以不写,但是()必须有 void myfun() { printf("----------------\n"); printf("--helloworld----\n"); printf("-----nihao beijing----\n"); printf("--------nihao nanjing--------\n"); return; } int main(int argc, const char *argv[]) { //调用一个没有参数和返回值的函数 //调用语法:函数名(参数) //注意:调用时一定不能加返回值类型 //如果没有参数可以不传,有参数必须传 //没有参数,函数名()必须要加 myfun(); myfun(); myfun(); myfun(); myfun(); myfun(); myfun(); return 0; }
8.2.2 函数的声明
#include <stdio.h> //函数的声明 void myfun(); int main(int argc, const char *argv[]) { myfun(); myfun(); myfun(); return 0; } void myfun() { printf("----------------\n"); printf("--helloworld----\n"); printf("-----nihao beijing----\n"); printf("--------nihao nanjing--------\n"); return; }
8.2.3 函数立案调用其它函数
#include <stdio.h> //函数的声明 void myfun(); void myfun1(); void myfun2(); void myfun3(); void myfun4(); int main(int argc, const char *argv[]) { myfun4(); return 0; } void myfun() { printf("----------------\n"); printf("--helloworld----\n"); printf("-----nihao beijing----\n"); printf("--------nihao nanjing--------\n"); return; } void myfun1() { printf("11111111\n"); myfun(); return; } void myfun2() { printf("22222222\n"); myfun1(); return; } void myfun3() { printf("3333333333333\n"); myfun2(); return; } void myfun4() { myfun3(); return; }