(汇编分析)字符指针数组与二维字符数组

cc str str1 的数组赋值及其汇编代码如下

    int cc[2][2] = {{1,2},{3,4}};
00D63598  mov         dword ptr [ebp-18h],1 
00D6359F  mov         dword ptr [ebp-14h],2 
00D635A6  mov         dword ptr [ebp-10h],3 
00D635AD  mov         dword ptr [ebp-0Ch],4 
    char *str[] = {"abg","cd"};
00D635B4  mov         dword ptr [ebp-28h],offset string "abg" (0D65808h) 
00D635BB  mov         dword ptr [ebp-24h],offset string "cd" (0D657ACh) 
    char str1[2][10] = {"abg","cd"};
00D635C2  mov         eax,dword ptr [string "abg" (0D65808h)] 
00D635C7  mov         dword ptr [ebp-44h],eax 
00D635CA  xor         eax,eax 
00D635CC  mov         dword ptr [ebp-40h],eax 
00D635CF  mov         word ptr [ebp-3Ch],ax 
00D635D3  mov         ax,word ptr [string "cd" (0D657ACh)] 
00D635D9  mov         word ptr [ebp-3Ah],ax 
00D635DD  mov         cl,byte ptr ds:[0D657AEh] 
00D635E3  mov         byte ptr [ebp-38h],cl 
00D635E6  xor         eax,eax 
00D635E8  mov         dword ptr [ebp-37h],eax 
00D635EB  mov         word ptr [ebp-33h],ax 
00D635EF  mov         byte ptr [ebp-31h],al 

做实验

1.能不能将二维数组名传递给二级指针?

1.把int类型二维数组cc传给

void change(int ** p)
{
    printf("%d\n",p);
    printf("%d\n",*p);
    printf("%d\n",**p);

}
change(cc); //这样调用: warning C4024: “change”: 形参和实参 1 的类型不同 为什么会报错?
//原因
//p是一个二级指针,它首先是一个指针,指向一个int*;
//cc是二维数组名,它首先是一个指针,指向一个含有2个元素的int数组;

//下方强转换类型时就可以使用了
change((int **)cc)

//当我们进行强转后看一下 p, *p ,**p,表示的值
//result:
p 1366256
*p 1
**p 出错
原因:
1)首先看一下p的值,p指向cc[0][0],即p的值为cc[0][0]的地址;

2)再看一下*p的值,p所指向的类型是int*,占4字节,根据前面所讲的解引用操作符的过程:从p指向的地址开始,取连续4个字节的内容。得到的正式cc[0][0]的值,即0。

3)再看一下**p的值,诶,报错了?当然报错了,因为你访问了地址为0的空间,而这个空间你是没有权限访问的。

但是有个问题真的没法访问吗 ?首先p 可以访问 *p也可以访问 只有**p不可以访问 那么只要能访问就可以得到数组里面的值
#include<stdio.h>

void change(int **p)
{
    int i = 0;
    for(i=0;i<4;i++)
    {   
    printf("%d\n",*(p+i));
    }
    *p = 5;
}
int  main()
{
    int cc[2][2] = {{1,2},{3,4}};

    change((int**)cc);

}
上述可以看到 是可以被访问和改变的,但是无法采用    printf("%d",p[0][0]);这种方式来访问,
这就引出来了一个问题,下标访问与指针间访问的关系 ,如果满足上方所说的p[0][0],这种关系那么肯定存在着二级指针
可以被有效访问的情况可是经过我们的试验发现,是不存在的!

//接下来我们从汇编的角度进行分析
00D63598  mov         dword ptr [ebp-18h],1 
00D6359F  mov         dword ptr [ebp-14h],2 
00D635A6  mov         dword ptr [ebp-10h],3 
00D635AD  mov         dword ptr [ebp-0Ch],4 
p 为ebp-18地址的值(因为整数在内存中占用四个字节实际上应该为14h-h18)
*p[ebp-18]堆栈里的值进行输出,为1
**p 为[1]的值进行寻址当然就报错了

经过以上的试验 ,int类型二维数组并不能那么做!
2.接下来我们用char 型二维数组str1传给change

void change(char ** p)
{
    printf("%d\n",p);
    printf("%d\n",*p);
    printf("%d\n",**p);

}
//change(str1);//和上面的不同 ,没报错
//change((char**)str1) //和change(str1)输出的结果相同
//同时运行上方的两句,在不运行**p的情况下是相同的,为什么?
1768488
1684234849
1768488
1684234849
//原因:
00D635C2  mov         eax,dword ptr [string "abg" (0D65808h)] 
00D635C7  mov         dword ptr [ebp-44h],eax 
00D635CA  xor         eax,eax 
00D635CC  mov         dword ptr [ebp-40h],eax 
00D635CF  mov         word ptr [ebp-3Ch],ax 
00D635D3  mov         ax,word ptr [string "cd" (0D657ACh)] 
00D635D9  mov         word ptr [ebp-3Ah],ax 
00D635DD  mov         cl,byte ptr ds:[0D657AEh] 
00D635E3  mov         byte ptr [ebp-38h],cl 
00D635E6  xor         eax,eax 
00D635E8  mov         dword ptr [ebp-37h],eax 
00D635EB  mov         word ptr [ebp-33h],ax 
00D635EF  mov         byte ptr [ebp-31h],al 
因为在压栈只是压栈为字符串的准确数值而不是地址,地址和地址里的值是有很大区别的,这一点很容易混淆!
例如
00D635C2  mov         eax,dword ptr [string "abg" (0D65808h)] 
00D635C7  mov         dword ptr [ebp-44h],eax 
意思就是把0D65808h入堆栈之中
,而准确数值用十六进制表示,那么首地址的指针为
int*型的指针,而在c语言中还指针都为四字节 那么传进去也不会报错了,但是str1还是指向字符数组的指针 !


然后继续回答我们的问题当做二级指针传进去后我们发现并不能打印出,char型二维数组的值 ,所以char型的也不可以

综上而得:其实声明为二级指针是可以进行取值的

2.二维数组的赋值与访问

``
//对于字符型数组的访问与修改
//1.常规访问


#include<stdio.h>

void change(char(*p)[3])
{
    p[0][0]='C';
    printf("%c\n",p[0][0]);


}
void change1(char p[3][3])
{
    p[0][0]='C';
    printf("%c\n",p[0][0]);


}
int main()
{
    char str1[3][3] = {"ab","\0","da"};

    change(str1);
    printf("%\n",str1[0]);

    return 0;


}


2.非常规访问(无法访问到整个值!)

#include<stdio.h>

void change(char *a)
{
    int i=0;
    for(i=0;i<10;i++)
    {
    
        printf("%c\n",*(a+i));
    }
}


int  main()
{
    char str1[3][3] = {"ab","\0","da"};
    char *a = &str1[0];
    change(a);
    //printf("%s\n",str1[0]);
    return 0;

}


#include<stdio.h>

void change(char ** p)
{
    //printf("%d\n",p);
    printf("%c\n",*p);
    //printf("%d\n",**p);

}
int  main()
{
    char str1[2][10] = {"abg","cd"};
    change((char **)str1);
    //printf("%s\n",str1[0]);
    return 0;

}
因为在内存中所有的数组地址都是按照线性排列 只要获取到了开头的一个地址通过地址加减的情况可以访问到所有的地址,但是都无法访问到整个的值得
3.二维数组和指针数组

从前面我们已经介绍二维数组了

那么指针数组的实现下

#include<stdio.h>

void change(char ** p)
{

    printf("%s\n",*p);

}
int  main()
{
    char * str1[] = {"abg","cd"};
    change(str1);
    //printf("%s\n",str1[0]);
    return 0;

}

//结果abg,是直接可以取到的 

因为什么呢

char *str[] = {"abg","cd"};
00D635B4  mov         dword ptr [ebp-28h],offset string "abg" (0D65808h) 
00D635BB  mov         dword ptr [ebp-24h],offset string "cd" (0D657ACh) 

指针数组首地址的里面存放的值 相当于*p 是一个 字符串偏移的地址

而在

    char str1[2][10] = {"abg","cd"};
00D635C2  mov         eax,dword ptr [string "abg" (0D65808h)] 
00D635C7  mov         dword ptr [ebp-44h],eax 
00D635CA  xor         eax,eax 
00D635CC  mov         dword ptr [ebp-40h],eax 
00D635CF  mov         word ptr [ebp-3Ch],ax 
00D635D3  mov         ax,word ptr [string "cd" (0D657ACh)] 
00D635D9  mov         word ptr [ebp-3Ah],ax 
00D635DD  mov         cl,byte ptr ds:[0D657AEh] 
00D635E3  mov         byte ptr [ebp-38h],cl 
00D635E6  xor         eax,eax 
00D635E8  mov         dword ptr [ebp-37h],eax 
00D635EB  mov         word ptr [ebp-33h],ax 
00D635EF  mov         byte ptr [ebp-31h],al 

相当于首地址单元模块存放的值为实际的值 ,所以多维指针的二级指针无法找到,这也是为什么平时不要对二维数组使用二级指针的问题!
QQ图片20191107232233.jpg