c语言学习总结----指针

c语言学习总结—-指针

在c语言的学习中,指针始终是一个非常重要的知识点,同时它也是一个难理解的知识点。相比于其他的语言,比如java(好吧,只学过java) xxx等,指针也是c语言的一个重要特点。通过指针,c语言程序可以直接访问内存地址(或者称为虚拟地址空间更准确,对已实实在在的物理内存,虚拟地址空间是一个比较抽象概念,大概的意思是只要知道虚拟内存地址,通过虚拟内存与物理内存的映射关系,电脑自己会找到对已的物理内存然后把数据存进去,具体可参考操作系统书籍中内存这一部分。一般的32bit电脑的最大寻址空间是 232 2 32 =4G,而64bit的电脑最大寻址空间是 264 2 64 =xxG,好吧,太大了不会算,反正希望能有用到这么大内存的一天。这也是为什么物理内存大于4G的电脑装32bit的系统会无法识别多出的那部分),而很多高级语言如java是没有地址访问这一个说法的(当然java中的引用和c中的指针很类似),这也是为什么很多底层开发有会用到c语言的语言之一吧。在c语言中指针的种类也不少,比如数组指针、指针数组 和 函数指针、指针函数等,乍一听过还感觉差不多,其实是失之毫厘差之千里,千万不要搞混淆了,make a long story short。

1. 概念

指针,就是一个内存地址,在程序进行编译时,系统会给各个变量分配内存单元而该变量的指针就是这个内存单元的地址,其形式为0x00000000共8位16进制数也就是对应32位地址空间。对应int型的指针a,其形式为int * a,表示指针a指向的内存单元中存储的是一个int型的数据。同理,要是一个char型的指针b,其形式为int * b,表示指针b指向的内存单元中存储的是一个char型的数据。除了这些指针外,还有一种void类型的指针,它表示指向一个抽象的类型的数据,使用的时候需要进行强制转换。使用指针可以提高程序的效率以及实现动态存储分配,指针的使用如下:

#include<stdio.h>
void main()
{
int data_a,data_b;
int * point_a, * point_b;
data_a=0;data_b=1;
point_a=&data_a;/*通过符号&来获得变量的地址*/
point_b=&data_b;
printf("通过指针point_a来获得a的值为:%d\n",* point_a);/*通过符号 * 来获得指针的指向对象的内容*/
printf("通过指针point_b来获得b的值为:%d\n",* point_b);
}

执行后的结果为:

通过指针point_a来获得a的值为:0
通过指针point_b来获得b的值为:1

2. 其他指针

除了指向基本数据类型的指针外,还有一些其他类型的指针,比如指向某些结构体类型的指针,不过它和指向基本数据类型的指针大同小异(有点类似于java语言中对象的引用类型)这里就不在复习,接下来看看下面这些类型指针:

2.1数组与指针

数组实际上是同类型元素有序的一个集合,可以通过数组名及对应的下标定位元素,每个数组元素在内存中占用了存储单元,所以都有相对地址。指针表示指向某个数据元素的地址,所以也是可以用指针来指向数组元素的,如把int数组a中第0个元素地址赋值给p:

int * p;
int a[]={23,53,4,64,3,6,2,4};
p=&a[0];

在c语言中规定数组名表示数组中第一个元素的地址,即a可以表示a[0]的地址,所以也可以这样写:

int * p;
int a[]={23,53,4,64,3,6,2,4};
p=a;

除了一维数组外,还有多维数组,多维数组的实质就是数组的数组,而多维数组的指针相对于一维数组指针会复杂点。
如一个二维数组int arr_a[3][4]表示3个int arr_b[4],而一个int arr_b[4]表示有4个int型元素,所以数组arr_a有12个元素。
数组名arr_a表示指向3个int arr_b[4]元素中的第一个元素地址,而该元素则又是一个int数组,所以arr_a也表示指向int数组的第一个元素(虽然说arr_a指向的地址和arr_a[0]指向的地址是一样的,但是个人感觉从某种意义上说它们并不代表同一个概念。arr_a是具有3个int arr_b[4]元素的数组名,表示指向第一个int arr_b[4]元素的地址,而arr_a[0]表示第一个int arr_b[4]元素的数组名,指向4个int型元素的第一个元素)。

#include<stdio.h>
void main()
{
    int arr_a[3][4]={{1,2},{0,5,8,9},{1}};
    printf("%p and %p\n",arr_a,&arr_a);/*   奇怪的发现arr_a和*&arr_a结果发现是一样的       */
        printf("the address of a[0] is %p: %p ,and the value of arr_a[0][0]is :%d\n",arr_a,*arr_a,**arr_a);

    printf("the value of a[1][1] is %d:\n ",arr_a[1][0]);
    printf("the address of a[1][0] is %p:\n ",&arr_a[1][0]);
}

运行结果:

0x7fff4156aef0 and 0x7fff4156aef0
the address of a[0] is 0x7fff4156aef0: 0x7fff4156aef0 ,and the value of arr_a[0][0]is :1
the value of a[1][1] is 0:
the address of a[1][0] is 0x7fff4156af00:

从上面的代码中可以看出很多奇怪的现象,比如arr_a、&arr_a以及arr_a的值都一样,好吧只能说c语言真的博大精深,而这还只是二维数组,想想多维数组,确实够难理解的。所以只好用最笨的方法记住这些。( *1.多维数组即数组的数组 2.数组名表示数组中第一个元素的地址 )

对应字段含义
arr_a二维数组名,指向首行元素地址
**arr_a,arr_a[0][0]表示0行0列元素的值
*arr_a,arr_a[0]表示0行0列地址
*(arr_a+1)+2,arr_r[1]+2都表示第二行第3列元素地址
*(arr_a+1),arr_a[1]都表示第二行0列元素地址
arr_a+1,&arr_a[1]都表示第二行地址

2.2 字符串与指针

在c语言中,有2种方式访问一个字符串:

  • 用一个字符数组存放一个字符串(语言中没有String类型,都是使用char数组来保存字符串),通过操作该数组来访问字符串。
#include<stdio.h>
void main()
{
    char string[]="hello World";
    printf("%s\n",string);
}
输出结果:
hello World
  • 用字符指针来指向一个字符串。
#include<stdio.h>
void main()
{
    char * string ="helloworld!";
    printf("%s\n",string);
}
输出结果:
helloWorld!

字符数组和字符指针变量都可以用来操作字符串,但是2者之间并不相同。

1.字符数组是由多个元素组成,每个元素中存入一个字符,以’\0’为结束。
2.字符数组和字符指针变量赋值方式不一样,字符数组只能通过对各个元素赋值,而字符指针可以通过如下方式赋值:

char *a;
a="helloworld!";

3.定义一个字符数组,在编译时就会为它分配一个固定的地址并确定它的大小,在以后的操作中,该数组大小无法改变。而字符指针表示指向一个字符变量的地址,是可以改变的,如果一个字符指针没有进行赋值,则该指针是随机的指向一个地址(这存在非常大的隐患)。

2.3 函数指针

2.4 指针函数

2.5 数组指针

数组指针,可以简单的把它理解成普通的指针(数组指针不是数组,它是一个指针),而与普通的指针不同之处在于它指向的对象是个数组。
其声明为:

int (*point_arr)[];

即相当于有一个数组对象arr

int arr[]={2,5,8,6,7};

指针point_arr指向数组对象arr的地址,又因为数组名arr可以表示数组的首地址,所以数值上arr==point_arr,但是所表示的意义不一样。point_arr表示指向的是整个数组对象,如果对它取值*point_arr,得到的是数组首地址(point_arr*point_arr值相同,含义是不一样的)。

#include<stdio.h>
int main()
{
    int i;
    int (* point_arr)[];
    int arr[5]={2,5,8,6,7};
    point_arr=arr;
    printf("%p and the value of first element is %d ,the valueof  point is %p\n",point_arr,**point_arr,*(point_arr));
    return 0;
}


0x7fffb1ebc710 and the value of first element is 2 ,the valueof point is 0x7fffb1ebc710

2.6 指针数组

2.7 指针的指针

3 .小结

3.1 各种数据类型的指针

3.2 指针间的运算

指针是可以进行运算的,如将指向int数组a中第一个元素的指针p进行p+1操作,则p+1表示指向数组a中的第二个元素(这里不是说把数组a第一个元素的地址加1)。同理,如果指针p指向一个float数组b,p+1同样表示数组中p指向元素的下一个元素,它代表的地址操作为p指向的地址+1*float的字节数。

#include<stdio.h>
void main()
{
    int a[10];
    int *p ,i;
    for(i=0;i<10;i++)
    {
        a[i]=(i+5)%10;
    }
    printf("\n");
    for(p=a;p<(a+10);p++)
    {
        printf("%d",*p);
    }
    printf("\n");
}
  • 数组名是可以作为函数参数传递的,但是数组名不能当做指针变量进行运算,它是一个指针常量,固定的指向数组中的第一个元素。
#include<stdio.h>
#include<string.h>
#define N 5
#define M 8
void fun(char (* ss)[M])
{
    char *ps[N],*tp;int i,j,k;
    for(i=0;i<N;i++)
    {
        ps[i]=ss[i];
    }
    for(i=0;i<N-1;i++)/*same as select sort*/
    {
        k=i;
        for(j=i+1;j<N;j++)
        {
            if(strlen(ps[k])<strlen(ps[j]))
                k=j;
        }
            tp=ps[i];
            ps[i]=ps[k];
            ps[k]=tp;
    }
        printf("\n The string after sorting by length :\n\n");
        for(i=0;i<N;i++)
        {
            puts(ps[i]);
        }
}
main()
{
    char ch[N][M]={"red","green","bule","yellow","black"};
    int i;
    printf("\nThe original string\n\n");
    for(i=0;i<N;i++)
    {
        puts(ch[i]);
    }
        printf("\n");

        fun(ch);
}

运行结果:

The original string

red
green
bule
yellow
black


 The string after sorting by length :

yellow
green
black
bule
red
  • 9
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值