c之数组

来源:互联网 发布:淘宝客工具箱 编辑:程序博客网 时间:2024/05/14 10:42

数组作为函数的参数:

我们都知道数组名其实就是指向数组第一个元素的指针(即&array[0]), 将数组名传递给函数的是该指针的一份拷贝。 如果在函数中执行了下标引用, 实际就是对这个指针进行了间接访问操作, 通过这种操作可以访问和修改调用程序的数组元素。

如何理解数组名的传入方式呢?(传值 or 传址)

Q:什么是传址调用?

A:传址调用:通过传递一个指向所需元素的指针, 然后在函数中对该指针执行间接访问操作实现对数据的访问。

其实对于所有的传递给函数的参数都是通过传值方式进行的, 但数组名参数的行为却仿佛是通过传址方式调用的。

Q:那么数组的传值调用表现在什么地方呢?

A:传递给函数参数的是指向数组起始位置的指针的一份拷贝, 所以函数可以自由操作它的指针形参, 而不必担心会修改对应的作为实参的值。 但是若是执行了间接访问操作, 那么函数就可以修改那个变量。 但是无论函数对参数(指针)如何进行修改, 都不会修改调用程序的指针实参本身(但可能改变它所指的内容)

# include <stdio.h>void demo(int *c){    int d[5]=  {45, 56};    c = d;}int main(void){    int a[10] = {1,2 ,4, 5, 6};    int * b;    int i;    b = a;    demo(b);    for (i = 0; i < 10; i++)    {        printf ("%d", b[i]);    }    return 0;}



对一个不打算改变形参的函数, 将形参声明为const, 有三个好处:

第一:这是一个良好的文档习惯

第二:编译器可以捕捉到任何试图修改数据的意外error

第三:这类声明允许向函数传递const参数


初始化

存储于静态内存的数组只初始化一次。 在程序开始之前。 这个初始化是由链接器完成的, 如果数组没有初始化, 则自动设置为零。

存储于动态内存的数组, 因为自动变量位于运行时堆栈中, 执行流每次进入他们所在的代码块时, 这类变量每次所处的内存位置可能并不相同。 在程序开始之前, 编译器没办法对这些位置进行初始化。 所以缺省情况下是未初始化的。 如果自动变量的声明中给出了初始化, 每次当执行自动变量声明所在的作用域时, 变量就被一条隐式的赋值语句初始化。 这条赋值语句和普通的赋值语句一样需要时间和空间来执行。



弄清楚下面三个的区别:

char string[6]=’h’,’e’,’l’,’l’,’o’,’\0’;

char string[] = “hello”

char *string = “hello”

其中第一个与第二个是等价的, 第三个表示string指向字符串常量”hello”的第一个字符。 注意第二个中的”hello”并不是一个字符串常量, 但是除了这种情况之外的其余情况, “hello”都表示字符串常量。


指向数组的指针

int vector[10], * p1 = vector;      // yesint mat[3][10], * p2 = mat;     // error

Vector 是一个指向数组的第一个元素的指针;p1指向的也是一个元素, 所以成立

mat是一个指向数组的指针;p2指向的是一个元素, 所以不成立。 正确的声明应该为
int (*p)[10]
下标的优先级高于间接访问操作符, 凡是括号的存在, p 是一个指针。 p 指向的是某种类型的数组。 该数组元素都为整数。 p 是一个指向拥有10个元素的数组的指针。

# include <stdio.h>int main(void){    int mat[3][10] = {{1, 2, 3, 4, 5}, {11, 22, 33, 44, 55}, {111, 222, 333, 444, 555}};    int (*p)[10] = mat;    int i;    for (i = 0; i < 3; i++)    {        printf ("%d", *p[i]);    }    return 0;}/*在code::blocks中输出结果是:1 11 111*/

函数接收二维数组。 就是指向数组的指针。

 int fun2(int (*P)[10]);    // 这两个是一个意思, 接收一个二维数组, 指向数组的指针。 int fun2(int p[][10]);

指针数组

int *pi[10];定义一个指针数组类似这样。 由于下标的引用高于间接访问, 所以在这个表达式中, 首先执行下标。 所以pi是一个元素为 10 的数组。 下标引用执行完之后,执行间接访问操作, 其结果必然为一个整数(对一个一维数组使用间接访问操作符结果必然为一个确定的值)。

指针数组说白了就是数组中每一个元素都是一个指针

一个指针数组的例子:

char const *keyword[] = {    "do",    "for",    "if",    "register",    "return",     "switch",    "while",    NULL};
# include <stdio.h>int main(void){    char const *keyword[] = {        "do",        "for",        "if",        "register",        "return",        "switch",        "while",        NULL    };    printf ("%s", keyword[1]);    return 0;}/*在code::blocks中输出结果是:for*/

数组总结

数组名在绝大多数时候表示的是指向数组第一个元素的指针, 有两个例外:sizeof返回的是整个数组所占的字节数, &返回一个指向数组的指针, 而不是指向数组第一个元素的指针的指针。

下标表达式与间接访问表达式是一致的。 指针表达式的效率可能比下标表达式高, 但是下标表达式的效率不可能比指针表达式的效率高。

数组和指针并不相等, 当我们定一个数组时, 它分配了一些内存空间, 用于容纳数组元素。 但是定义一个指针时, 只分配了用于容纳指针本身的空间。

当数组名作为函数参数传递时, 实际传递给函数的是一个指向数组第一个元素的指针。 函数接收的只是元参数的一份拷贝, 所以函数可以对其进行操作而不影响实际参数。 但是如果进行间接访问操作就会影响到原来的数组。

多维数组是一维数组的一种特型, 就是它的每个元素是个数组。 多维数组根据行主序存储, 也就是最右边的下标最先变化, 多维数组名是一个指向它第一个元素的指针, 也就是一个指向数组的指针。 使用多维数组作为函数参数时, 除了第一维可以省略, 其余都不能省略。

指针数组:数组的每一个元素都是指针的数组。 字符串的列表可以以矩阵的形式存储, 也可以以指向字符串常量的形式进行存储。 如果是矩阵存储, 那么每行必须与最长的一行相同。

原创粉丝点击