二维数组作为实参,调用函数,段错误

  我相信大家在进行C/C++编程时,都遇到过这样的情况,即需要将二维数组作为实参来调用函数。代码如下所示:

#include <stdio.h>
void set_char(char *c[]){
    c[0][0] = 'b';
}
int main(){
    char c[10][10];
    c[0][0] = 'a';
    set_char(c);
    printf("%c\n", c[0][0]);
    return 0;
}

  理所当然,我们可能第一眼认为输出值为 b。

  然而,终端无情的给了你一个Segmentation fault(段错误)。不应该,难道不是输出 b吗???

  到底是为什么呢?从终端给出的段错误提示来看,应该是地址访问非法。出现上述错误主要是我们对指针理解还是不够深。
  首先注意set_char形参c的值等于主函数内数组c(二维数组)的首地址。然而的形参c是一个一维的指针数组,数组的每一个元素是一个指向char的8字节指针(此处以64位系统为例)。

c[0][0] = 'b';

   该行代码先将形参c的首元素(指针)取出,此处取出的指针值等于主函数中数组c前8字节所保存的值。然后,将该指针指向的内存块中的第一个字节赋值为’b’。一般来说,该指针的值仍然属于当前进程的地址空间,但是很可能该地址还未被当前进程分配,故产生段错误。即使该地址已被分配,可能用于保存进程的重要信息,修改该地址指向的内存可能造成未定义的错误。

  按上面的解释,若是我们将主函数内c的前8字节赋值为主函数某个变量的值,那么调用set_char之后,该变量的值应发生相应的变化。测试代码如下:

#include <stdio.h>
#include <stdlib.h>
void set_char(char *c[]){
    printf("%lld\n", *((long long*)c));
    c[0][0] = 'b';
}
int main(){
    char a = 'a';
    unsigned char c[10][10];
    long long addr = &a;
    //以下代码将变量a的地址保存至数组c的前8个字节内。
    c[0][0] = addr & 0x00000000000000ff;
    c[0][1] = (addr & 0x000000000000ff00) >> 8;
    c[0][2] = (addr & 0x0000000000ff0000) >> 16;
    c[0][3] = (addr & 0x00000000ff000000) >> 24;
    c[0][4] = (addr & 0x000000ff00000000) >> 32;
    c[0][5] = (addr & 0x0000ff0000000000) >> 40;
    c[0][6] = (addr & 0x00ff000000000000) >> 48;
    c[0][7] = (addr & 0xff00000000000000) >> 56;

    printf("%lld\n%lld\n%lld\n", &a, addr, *((long long *)c));

    set_char(c);

    printf("%c\n", a); //输出'b'
}

  此处,我们先将主函数内c的前8个字节赋值为变量a的地址,然后调用同样的set_char函数,set_char函数内,通过代码

c[0][0] = 'b';

将主函数内变量a的值赋值为’b’。

  注意,此处采用的机器采用小端存储(低字节存在低地址内)。若是采用大端存储,只需将主函数内对数组c的赋值语句改为如下代码即可:

c[0][7] = addr & 0x00000000000000ff;
c[0][6] = (addr & 0x000000000000ff00) >> 8;
c[0][5] = (addr & 0x0000000000ff0000) >> 16;
c[0][4] = (addr & 0x00000000ff000000) >> 24;
c[0][3] = (addr & 0x000000ff00000000) >> 32;
c[0][2] = (addr & 0x0000ff0000000000) >> 40;
c[0][1] = (addr & 0x00ff000000000000) >> 48;
c[0][0] = (addr & 0xff00000000000000) >> 56;

  说了这么多,那究竟如何才能达到我们的目的呢?
  当然很简单呀,只需要将形参改为对应的二维数组即可,代码如下。

#include <stdio.h>
void set_char(char c[][10]){ //第二维的size必须指定
    c[0][0] = 'b';
}
int main(){
    char c[10][10];
    c[0][0] = 'a';
    set_char(c);
    printf("%c\n", c[0][0]);  //输出'b'
    return 0;
}

猜你喜欢

转载自blog.csdn.net/nice_wen/article/details/80464213
今日推荐