C的日记-数组和指针

【数组】

C语言中数组名表示该数组的起始地址,即给数组本身对应的值就是一个地址,而数组中的值就是从起始地址开始的不同的地址内的值。
如:char c[9];        //定义时的数组char c[5]中的c和运算时的c是一个含义,都是数组首地址
    scanf("%s",c);
    printf("%d",c); // printf(%s,c)
输入:china 输出:2686675。输出的是字符数组首地址。
若换为后面一个,输出china,输出china。字符数组按照%s格式化输出时会自动输入/输出直到‘/0’,
【数组作为函数参数】
首先我们比较下变量作函数参数和数组作函数参数的区别
    如:

    void main(){
            int a,b;
            sum(a,b);
        }
        sum(int x,int y){
            int sum;
            sum=a+b;
        } 

实参变量类型为int,形参变量类型也为int,实参由自己的地址,形参也有而且和实参不同,实参赋值给形参,形参在函数中进行运算,运算的过程和结果与实参无关,在整个过程中实参和形参是独立开的,执行完函数后形参变了,实参无变化。
    再来看下数组作为变量函数
    如:

    #include <stdio.h>
          void main () {
            void sum(int p[]);
            int a[5]={0,1,2,3,4};
            sum(a);
        }
        void sum(int p[5]){   // (int p[]) // (int *p)
                int i;
            for(i=0;i<5;i++){
                printf("%d,\n",p[i]);
            }
        }   

我们知道数组名代表着数组首地址,所以实参类型为地址,同时我们也知道实参和形参间的沟通是通过赋值进行的,那 什么类型的变量中存放的地址?指针变量,所以形参的类型就是指针变量,实际上C对形参数组的大小是不做检查的,就是说[]之间写什么都行就算是写p[0]、p[1]都可以。另外,在形参数组中,可以用int *p替换int p[],因为数组只是指针变量的一种表示,我们直接写指针变量当然可以~。
 
[数组可以看做是一种特殊的指针变量]
    一般的指针变量中存放的是另一个数据的地址,而数组中存放的是它自己的首地址;
    一般的指针变量有自己的地址,而数组的地址就是它的首地址;
    一般的指针变量中存放别人的地址,而数组的指针变量存放自己的首地址;
    一般的指针变量是可以随着地址变化而变化的,而数组不灭,地址(=首地址)不变。
    指针变量作为数组(函数形参)存在时,看起来是是数组(常用),其实是指针变量(通用);
    指针变量无法转换成数组
    [指针变量和数组的诗]
    指针变量指向别人,数组指向自己
    指针变量有它的载体且不同于它指向的东西,数组变量的载体就是它自己;
    指针变量依靠别人活着,数组依靠自己活着;
    指针变量随着别人变化而变化,数组坚守自己的内心;
    指针变量和数组在一起聊得很好,就像是和数组一类人,但是回到家,指针变量依然是指针变量;
    指针变量很羡慕数组,可它永远成不了数组。
 
[为什么指针变量可以表示数组形参要用数组表示]
    int *p初始时等价于int a[],这是因为a初始时等价于一个不变的指针变量。虽然我们写void sum(int p[]),但它不真正是个数组,它是指针变量!数组地址是不能变的,写成数组是为了好理解,我们也可以理解为这是一个地址可以变化的数组。(奇葩)
[数组和指针变量关系]
    其实已经很清楚了,数组和指针变量都是人,但不是一类人...在数组作形参时,指针变量伪装成数组,本质还是指针变量。
[数组形参可以变么]
    在实参中,数组名是指针常量,不可变;赋值后形参初值还是数组首地址,但是它是可以变化的指针变量!
[最重要的]
    变量作参数和数组作参数:形参变量和实参变量是独立的内存空间,形参数组和实参数组共用一段内存单元。

 【指针和指针变量】

指针变量=地址变量,里面存储的是指针,所以说指针变量的值是指针(地址);而指针是变量的地址。*加在变量之前代表该变量指向的变量。
如:int *pointer;int i;
定义指针变量在变量名前需加上*,而左端的int是定义指针变量必须指定的“基类型”即此指针变量可以指向的变量的类型。这里基类型为int,就必须使得指针变量中的指针指向的地址的内存空间存放的是int类型的数据。指针变量类型不限。
在上式中,pointer是指针变量,*pointer是整形变量即pointer指针变量中的指针指向的地址的变量类型是整形变量,*pointer的值就是pointer指向变量的值,pointer指针变量的值是指针地址。
指针变量的赋值:<1>指针变量中只能存放地址<2>赋值给指针变量的变量地址只能是和指针变量指向变量类型一致的变量地址。
int *pointer;*pointer=3;
前者是定义整形变量,后者是把3赋值给pointer指向的变量。
 
【指针变量作实参调用函数】
<1>通过调用函数使得实参变量的值发生了直接变化,而在main函数中不通过返回值可以使用这些改变了的值
<2>指针变量做实参执行[调用函数]的过程中,只能通过改变指针变量所指的值的数据,而不能改变指针变量的值(地址),因为实参和形参同时指向某个值,所以它们两个指针变量中的值必然相同,我们想改变必然同时需要改变这两个值,可C中实参形参间的数据传递是单向的即实参中的值是无法改变的,所以我们只能改变实参和形参所指向的地址的值。

【指针和普通数组】

<1>指针与数组
    C语言中,数组名代表着数组的起始地址(而不是整个数组)它是一个指针常量,只能指向起始地址,无法改变。所以
        int a[10];
        <1> int *p;    <2> int *p=a;    <3> int *p =a[0]; //定义时的*p和运算时的p一个含义
        p=&a[0]; / p=a;
    第二行的三种方法等价,第三行两个语句等价,
<2>指针运算
    指针可以执行的运算:+ - += a++ ++a -= a-- --a --
    指针加减的含义
        :如:int a[10]; int *p=a; p=p+1;
        p=p+1的含义是p指向的地址由a[0]转换为a[1],这个过程中p的地址增加了4个字节(VC中的int类型所占空间)
        我们假设i代表着数组a中的第i个元素,此时 a[i]=*(p+i)=*(a+i);
        数组中地址之差/数组类型所占空间(vc-int -4)=两个地址间的元素个数。
    综上我们可以看出,计算机输出a[i]的时候需要先把a[i]转换成*(a+i),活取内部数值,比如我们循环输出一个数组中的数制
        int *p,i,a[10]={0,1,2,3,4,5,6,7,8,9}
        for(i=0;i<10;i++)
        printf("*d",a[i]);
    每一个for循环都会活取当前a的地址,加上当前的i值,根据得到的结果去对应地址中取出数值,但是如果我们这么做
        int *p,i,a[10]={0,1,2,3,4,5,6,7,8,9}
        for(p=a;p<(a+10);p++)
        printf("*d",*p);
    这么做指针变量直接指向数组中数值,除了刚进入for循环地址的赋值,其他情况不需要考虑地址的问题,效率增加。
    同时我们可以想到:a[i]=*(a+i)那么我们也可以写p[i];p[i]的含义是*(p当前地址+i),因为p是变量,所以这个容易出错。

【指针和多维数组】

<1>多维数组元素的地址
在二维数组a[i][j]中,a代表首地址,这个首地址只是[行]首地址,不是[列]首地址,比如:
    x x x x
    x x x x
    x x x x
我们就假设它是3*4的二位,每行代表一维,现在我们把每行看成一个大的元素,那么我们现在得到一个“一维数组”,把这个一维数组横着放,这个数组首地址是a,所以a是列首地址,那么a=a[0],a=a[1],a+2=a[2]就分别代表着第一第二第三个大元素的[行]首地址了。
    注:a和a[0],a+1和a[1]..仅仅是[地址开始的值相同],a,a+1,a+2代表着二位数组,是指向行的,意思就是我加1,行加1,我不加,行为0;而a[0],a[0]+0,a[0]+1,a[1],a[1]+0,a[1]+1这些都是指向列的,就是说我加1,列加1,我不加,列为0;
<2>重要语法:
    <21>在指向行的指针前加“*”就转换成指向列的指针,变得具体,如a[i][j]=*(a[i]+j)=*(*(a+i)+j)。
        我们从右往左看,a+i是行指针,*(a+i)是加0的列指针,*(a+i)是加i的列指针,有了行指针和列指针,去除指针指向的内存地址中的数,注意里面的是[行->列]转换指针,外面的是标准的转换成取出指向单元内容符号。
        *(*(a+i)+j)中里面的*(a+i)意义就是取出a+i指针变量所指向的地址中的[范围]具体值,二维-一维.
    <22>在指向列指针前面加“&”就转换成了指向行的指针,变得抽象,比如&(&a[1][2])=&(a[1])=&(*(a+1))=a+1,
        &(&a[1][2])中的外面的一层&是取地址,里面的一层是把当前的[范围]具体值转换成一个抽象值。
 
        注意:[行->列]转换a+0加上*转换成a[0],a[0]加上*转换成a[0][0],这个过程是a变化的过程,a,a[0],a[0][0]三个含义完全不同,首先1/2是行/列指针,它们地址的值相同,但含义一个是第一个行地址,一个是第一个行地址中的第一个列地址;然后和第三个比较,第三个的含义是第一个行地址中的第一个列地址的数值,这个不可知。

 【字符指针变量和字符数组】    

输出字符串的两种方式
<1> char string[]="I love China";
    printf("%s",string);
    注:字符数组按照字符串格式化%s可以完全输入/输出字符串直到‘/0’。
        这种情况下:string中存放的是第一个字符的内存地址,可以对字符串数组重新赋值。
<2> char *string="I love China";
    printf("%s",string);
    注:定义字符指针变量,把多个字符赋值给无名数组,把数组首地址传给字符指针。
        这种情况下:string指针变量作用同上,而指针指向的是字符串常量,不能改变。注意,这个时候字符串是常量不可变,但指针变量可以变化。
字符指针变量和字符数组的区别
<1>字符数组由若干元素构成,而每个元素存放一个字符,字符数组的数组名和字符指针变量作用类似。
<2>赋值方式:
    字符数组只能在定义的时候整体赋值,而在赋值语句中需要对各个元素赋值,
    而字符指针变量可以在任意情况下使用char *a="I love China";直接赋值。
    注:字符指针变量只能赋初值,即只能赋值一次。
<3>能否直接赋值
    如:int str[10];
        scanf("%s",str);
        这样是可以的,因为在编译的时候给数组分配内存单元,这个内存单元是没用过的,而函数名就是这个空白内存单元的首地址,首地址可知,输入数据的时候会以首地址为始写入。
    如:int *str;
        scanf("%s",str);
        这样写勉强可以通过编译,但是有问题,str指针变量虽然分配了内存单元,但是str里面的地址未知,而输入的字符串正是以str里面的地址为首地址的,这种做法容易造成冲突。
    而:int *str="I love china"
        这种情况是先把字符串分配给字符数组,再把字符数组首地址传给指针变量,指针变量有内存单元和指向的地址,比较安全。
<4>指针变量可变,数组名不可变。
<5>对于可变的指针变量,如str+5的值,可以用str[5]进行表示,因为str[5]=*(str+5);
<6>字符数组元素可再赋值,字符指针变量指向字符串不可改变。
 
//今天学习了 数组&指针/普通&多维数组/字符指针&字符数组

时间: 2024-09-27 04:32:49

C的日记-数组和指针的相关文章

数组与指针的区别?

数组要么在静态存储区被创建(如全局数组),要么在栈上被创建.指针可以随时指向任意类型的内存块.    (1)修改内容上的差别 char a[] = "hello";  //它们有各自的内存空间:a[0] = 'X';char *p = "world"; // 注意p 指向常量字符串p[0] = 'X'; // 编译器不能发现该错误,运行时错误 (2) 用运算符sizeof 可以计算出数组的容量(字节数).sizeof(p),p 为指针得到的是一个 指针变量的字节数,

数组与指针

//使用递归来计算阶乘#include<stdio.h>long rfact(int n);int main(){ int num; printf("This program calculate factorials.\n"); printf("Enter a value in the range 0-12(q to quit): \n"); while(scanf("%d",&num)==1) { if(num <0

数组与指针操作

一,数组 1,const int array[5] = {0, 1, 2, 3, 4}; 2,c99新特性,可以对指定的数组的某一个元素初始化.例如:int array[10] = {1, 3, [4] = 2, 6, 7, [1] = 32};如果多次对一个元素进行初始化,取最后一次的值. 3,c不支持把数组作为一个整体来赋值,也不支持用花括号括起来的列表形式进行赋值. 4,sizeof表达式被认为是一个整数常量. 5 * 5 - 1 就是整数常量表达式. 5,变长数组int array[n]

(C/C++)区别:数组与指针,指针与引用

1.数组跟指针的区别 数组要么在静态存储区被创建(如全局数组),要么在栈上被创建.数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变. 指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存.指针远比数组灵活,但也更危险. 数组和指针特点的简单比较: 数组 指针 保存数据 保存地址 直接访问数据 间接访问数据,先取得指针的内容,然后以它为地址取得数据 用于存储数目固定且类型相同的数据 通常用于动态数据结构 编译器自动分配和删除

C语言关于数组与指针内容小结

数组的基本概念 什么是数组:数组就是:数组是相同类型的元素的一个集合       类型说明符 数组名 [常量表达式]: 其中,类型说明符是任一种基本数据类型或构造数据类型.数组名是用户定义的数组标识符.方括号中的常量表达式表示数据元素的个数,也称为数组的长度.例如: int a[10]; /* 说明整型数组a,有10个元素 */ float b[10], c[20]; /* 说明实型数组b,有10个元素,实型数组c,有20个元素 */ char ch[20]; /* 说明字符数组ch,有20个元

编程练习之数组与指针

数组与指针 阅读如下代码,为何出错. 1 int main() { 2 char a[] = { "I am a bad boy" }; 3 char * pA = new char[ sizeof( a ) ]; 4 pA = a; 5 6 for ( size_t i = 0; i < sizeof( a ); ++i ) { 7 std::cout << *pA << std::endl; 8 ++pA; 9 } 10 delete [] pA; 1

数组与指针的本质

指针是C/C++语言的特色,而数组名与指针有太多的相似,甚至很多时候,数组名可以作为指针使用.于是乎,很多程序设计者就被搞糊涂了.而许多的大学老师,他们在C语言的教学过程中也错误得给学生讲解:"数组名就是指针".很幸运,我的大学老师就是其中之一.时至今日,我日复一日地进行着C/C++项目的开发,而身边还一直充满这样的程序员,他们保留着"数组名就是指针"的误解. 想必这种误解的根源在于国内某著名的C程序设计教程.如果这篇文章能够纠正许多中国程序员对数组名和指针的误解,

【好程序员笔记分享】——数组与指针

ios培训 ------我的c语言笔记,期待与您交流! 前面我们介绍了关于C语言的内存分配问题,下面我们就开始介绍关于C语言的两个非常重要的知识点:数组与指针 数组与指针其实不仅仅是再C语言中,再OC中(当然OC是内部已经帮我们处理好了,但是还有存在大量的指针),C#中,C++中等待一些开发中都是非常常见的,所以作为一个程序员是必须掌握的. 一.数组:相同类型的集合 1:一维数组 平时我们都是申明一个变量,那么如果变量很多我们要怎么做呢,这个时候我们就能用到数组,那么什么是数组呢? 首先来看一个

深入理解 [指针函数] 、[函数指针]、[指针的指针]、[指向指针数组的指针]

指针函数 1.指针函数是指带指针的函数,即本质是一个函数.当一个函数声明其返回值为一个指针时,实际上就是返回一个地址给调用函数,以用于需要指针或地址的表达式中. 函数返回类型是某一类型的指针: 格式: 类型标识符  *函数名(参数表) int *match(void *key_x,void *key_y); 解析:首先来说它是一个函数,只不过这个函数的返回值是一个地址值.函数返回值必须用同类型的指针变量来接受,也就是说,指针函数一定有函数返回值,而且,在主调函数中,函数返回值必须赋给同类型的指针