您的位置:首页 > 编程语言 > C语言/C++

C语言指针详解

2010-12-02 09:18 288 查看
/**

* 指针简介

* 可以有效地表示复杂的数据结构

* 能动态分配内存

* 方便地使用字符串

* 有效而方便地使用数组

* 在调用函数时能获得一个以上的结果

* 能直接处理内存单元地址

*/

//地址与指针的概念?

/**

为了说清楚什么是指针,必须弄清楚数据在内存中是如何存储的,又是如何读取的。

声明一个变量,在编译时,系统会给变量分配内存单元(内存空间),内存区的每一个字节有一个编号,这就是"地址",

地址所标志的内存单元中存放数据。

变量的存储与读取流程

定义整型变量i,编译时系统分配2000、2001两个字节给变量i。

在程序中一般是通过变量名来对内存单元进行存取操作的。

程序经过编译后已经将变量名转化成变量的地址,对变量值的存取都是通过地址进行的。

printf("%d", i)

根据变量名与地址的对应关系,找到变量i的地址2000,然后从2000开始的两个字节中取出数据,把它输出。

scanf("%d", &i)

把从键盘输入的值送到地址为2000开始的整型存储单元中。

这种通过变量地址直接存取变量的方式称为"直接访问"方式。

另外一种方式是间接访问,即将变量i的地址存放在另一个变量中,这种变量称为指向变量的指针变量。

int * i_pointer; //i_pointer是指向int型变量的指针变量

i_pointer = &i; //将i的地址2000存放到i_pointer中。

一个变量的地址称为该变量的指针,例如地址2000是变量i的指针。

存放变量地址的变量为指针变量,i_pointer为指针变量。

*指针运算符(或称"间接访问运算符"),取其指向的内容。

i_pointer为指针变量,* i_pointer为i_pointer指向的内容。

i = 3; 等价于 * i_pointer = 3

*/

/**

1. & * i_pointer的含义?

& * i_pointer 相当于 &i

2. * &i的含义?

* &i 相当于 i

3. (* i_pointer)++ 相当于 a++

*/

#include <stdio.h>

void pointer_int();
void pointer_compare();
void pointer_swap();
void index_method();
void pointer_method();
void array_reverse();
void multi_arr();
void str_poiner();

void main()
{
pointer_int();
pointer_compare();
pointer_swap();
index_method();
pointer_method();
array_reverse();
multi_arr();
str_poiner();
}

//通过指针变量访问整型变量
void pointer_int()
{
int a=100, b=10;
int * pointer1, * pointer2;
pointer1 = &a;
pointer2 = &b;
printf("%d, %d/n", a, b);
printf("%d, %d/n", * pointer1, * pointer2);
}

//输入a,b两个整数,按先大后小的顺序输出a和b
void pointer_compare()
{
int *p, *p1, *p2, a, b;
scanf("%d, %d", &a, &b);
p1 = &a;
p2 = &b;
if (a < b)
{
p = p1;
p1 = p2;
p2 = p;
}
printf("a=%d, b=%d/n", a, b);
printf("max=%d, min=%d/n", *p1, *p2);
}

//指针变量作为函数参数
/**
函数的参数不仅可以是整型,浮点型,字符型等数据,还可以是指针类型。
它的作用是将一个变量的地址传送到令一个函数中。
*/
void pointer_swap()
{
void swap(int *p1, int *p2);
int a, b;
int *pointer_1, *pointer_2;
scanf("%d, %d", &a, &b);
pointer_1 = &a;
pointer_2 = &b;
if (a < b)
{
swap(pointer_1, pointer_2);
}
printf("a=%d, b=%d/n", a, b);
}

//如果a<b, 则a与b的值就改变了
void swap(int *p1, int *p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
}

/**
* 数组与指针
*
* 指针变量既可以指向变量,也可以指向数组元素(把某一元素的地址放到一个指针变量中)。
* 所谓数组元素的指针就是数组元素的地址
*
* int a[10]; 定义a为包含10个整型元素
* int *p;    定义p为指向整型变量的指针变量
* p = &a[0]; p = a; 把数组的第一个元素的地址赋给p
*
* int *p; p=&a[0]; 等价于 int *p = &a[0]; 把&a[0]赋给了p而不是*p
*/
/**
* 按C语言规定,如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素。
* 指向数组的指针变量也可以带下标,如p[i]与*(p+i)等价。
* 引用数组元素的方法:
* 1.下标法,如a[i]形式
* 2.指针法,如*(p+i)
*/
//假设有一个a数组,整型,有10个元素,输出各元素的值。
void index_method()
{
//下标法
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int i;
for(i=0; i<10; i++)
{
printf("%d", a[i]);
}
printf("/n");
}

void pointer_method()
{
//指针法
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int *p;
//&a[0]+10是第十个元素下一个元素的首地址
//(p=&a[0]; p<(&a[0]+10); p++) 也可以写成 (p=a; p<(a+10); p++)
for(p=&a[0]; p<(&a[0]+10); p++)
{
printf("%d", *p);
}
printf("/n");
}

/**
* 用数组名作函数参数
* 用数组名作为函数参数的情况,实参数组名代表该数组首元素的地址,而形参是用来接收从实参传递过来的数组首元素地址的。
* 因此,形参应该是一个指针变量(只有指针变量才能存放地址)。实际上,C编译器都是将形参数组名作为指针变量来处理的。
* f(int arr[], int n) 等价于 f(int *arr, int n)
* 以上这两种写法是等价的。在该函数被调用时,系统会建立一个指针变量arr。
* 用来存放从主调函数传递过来的实参数组首元素的地址。
* 当 arr接收了实参数组的首元素地址后,arr就指向实参数组首元素,也就是指向了array[0],arr+1 指向 array[1]...
*/
//将数组a中n个整数按相反顺序存放
void array_reverse()
{
void inv(int *x, int n);
int i,a[10]={3,7,9,11,0,6,7,5,4,2};
printf("The array:/n");
for(i=0;i<10;i++)
{
printf("%d", a[i]);
}
printf("/n");
inv(a, 10);
printf("The array has been inverted:/n");
for(i=0;i<10;i++)
{
printf("%d", a[i]);
}
printf("/n");
}

void inv(int *x, int n)
{
int *p,temp,*i,*j,m=(n-1)/2;
i=x;
j=x+n-1;
p=x+m;
for(;i<=p;i++,j--)
{
temp=*i;
*i=*j;
*j=temp;
}
}

/**
* 多维数组和指针
* 用指针变量输出二维数组元素的值
*/
void multi_arr()
{
int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}};
int *p;
for(p=a[0];p<a[0]+12;p++)
{
if ((p-a[0])%4 == 0) printf("/n");
printf("%-4d", *p);
}
printf("/n");
}

/**
* 字符串与指针
* 在C中,有两种方法访问一个字符串
* 1.字符数组  char string[] = "Hello Word!";
* 2.字符指针  char *string = "Hello Word!"; 把字符数组第一个元素的的地址赋给string
*/
//用字符指针实现字符串的复制
void str_poiner()
{
void copy_string(char *from, char *to);
char *a = "I am a teacher.";
char *b = "You are a student.";
printf("string a=%s/nstring b=%s/n",a,b);
printf("/ncopy string a to string b:/n");
copy_string(a,b);
printf("/nstring a=%s/nstring b=%s/n",a,b);
}

void copy_string(char *from, char *to)
{
for(;* from!='/0';from++, to++)
{
*to = *from;
}
* to='/0';
}

/**
* 指向函数的指针
* 指针可以指向变量,字符串,数组等,也可以指向一个函数。一个函数在编译时被分配给一个入口地址。
* 这个函数的入口地址就称为函数的指针。
* 指向函数的指针变量的一般定义形式
* 数据类型 (* 指针变量名)(函数参数列表);
*/

void poniter_function()
{
int max(int, int);
int (*p)(int, int);
int a,b,c;
p=max;
scanf("%d,%d",&a,&b);
c=(*p)(a,b);
printf("a=%d,b=%d,max=%d/n",a,b,c);
}

/**
* 返回指针值的函数
* 一个函数可以返回整型值、字符值、实型值,也可以返回指针型的数据,即地址。
* 类型名 * 函数名(参数列表)
*/

/**
* 指针数组和指向指针的指针
* 指针数组
* 一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都相当于一个指针变量。
* 为什么会用到指针数组呢,这是因为它比较适合于用来指向若干个字符串。
* char * str[];
* str[0] -> "Hello"
* str[1] -> "Word"
*
* 指向指针的指针
* 指向指针数据的指针变量,简称为指向指针的指针
* char **p; 指针变量p指向一个字符指针变量。
*/

//使用指向指针的指针
void p_ponier()
{
char * name[] = {"Hello Word", "welcome", "Great Wall"};
char **p;
int i;
for(i=0;i<3;i++)
{
p=name+i;
printf("%s/n", *p);
}
}

/**
* 指针数组作为main函数的参数
* argc和argv都是main函数的形参。main函数是由操作系统调用的。
* 命令行状态下argc为参数个数,argv是指针数组,是向程序传入的参数。
* 命令名   参数1   参数2 ... 参数n
*/
//void main(int argc, char * argv[])
//void main(int argc, char ** argv)
/**
* ** argv为一个指向指针的指针,argv指向的是 * argv[]指针数组中的元素。
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: