char**和char[][]的问题

rongxiaojun 2014-01-13 04:30:37
长话短说:
void output(char **buffer){
printf(“%s\n”,buffer[0]);
}

void main(){
char buffer[100][1024] = {0};
int len = sprintf(buffer[0],"i am a bastard...");
buffer[0][len] = '\0';
output(buffer);
}

程序出现“段错误” 求解答!
...全文
2015 37 打赏 收藏 转发到动态 举报
写回复
用AI写文章
37 条回复
切换为时间正序
请发表友善的回复…
发表回复
skyliuxu 2014-02-18
  • 打赏
  • 举报
回复
引用 22 楼 rongxiaojun 的回复:
[quote=引用 17 楼 dcw0402 的回复:] 这里,二维数组其实是一个一维数组的加长版.... 改成这样也可以 void output(char *buffer){ printf("%s\n",buffer); } 我也不知道为啥,感觉7楼说有的些道理
这是因为char buffer[100][1024]中,buffer的值即char[0][0]的地址,(真不可思议,二维数组地址即第一个数组中第一个元素地址,而非第一个数组的地址),然后调用函数output(buffer),此时buffer的值传进参数中,参数类型char*,则参数为char* 类型且指向了首字符'i',然后printf打印字符串直到'\0'出现,一切都解释通了。[/quote] 你的理解还是有问题,buffer是一个数组名,当你将buffer作为指针使用时,其被转化为一个指向数组首元素的指针。这里数组首元素是什么?是一个包含1024个char的数组(因为本质上所有数组都是一维数组),buffer[0]可以当做它的数组名!
lm_whales 2014-01-21
  • 打赏
  • 举报
回复
void output(char **buffer){
   printf(“%s\n”,buffer[0]);
       // output::buffer == ((char**) (main::buffer);
       // output::buffer[0] == ((char**) (&main::buffer ))[0];
       // 
       // 这是把 main::buffer 当作储存指针的数组使用,
       // output::buffer[0]是该指针数组的第一个元素
       // 该指针其实是把 
       // main::buffer[0][0],main::buffer[0][1],main::buffer[0][2],main::buffer[0][3]。。。。
       // 这4(指针长度)个字符,组成的一个整型数据,当作指针使用
       // 这样 output::buffer[0] 其实是个野指针。
       // 出错是正常,不错是巧合。
       // 这里借用一下,C++的作用域限定符:: 表示作用域  
}                               

void main(){
   char buffer[100][1024] = {0};
   int len = sprintf(buffer[0],"i am a bastard...");
   buffer[0][len] = '\0';
   output(buffer);//传递buffer 即 &buffer[0],这里类型不对,应该报错,或者警告。 
}
多级指针,需要指针数组做中转,或者动态分配数据 才能和多维数组匹配
//维持这种函数定义,需要传如指针地址,指针数组,和二级指针
void output(char **buffer){
   printf(“%s\n”,buffer[0]);
   
}                               

void main(){
   char buffer[100][1024] = {0};
   int len = sprintf(buffer[0],"i am a bastard...");
   buffer[0][len] = '\0';
  
   /************* 1 ***************/
   { char *p[100];
     int i;
     for(i=0;i<100;i++)p[i] = buffer[i];
     output(p);
   }
    /************* 1 ***************/
   { char *p[100];
     char **pp = &p;
     int i;
     for(i=0;i<100;i++)p[i] = buffer[i];
     output( pp );//
   }
   /*********** 3**********/
   {
     char **pp = malloc(sizeof(char *)*100);//c++ 替换为 char ** =new char*[100];
     int i;
     for(i=0;i<100;i++)pp[i] = buffer[i];
     output( pp );//
     free(pp);   //c++ 替换为 delete[]pp;
   }
}
多级指针,多维数组 数组维度,和指针的级别是不同的概念,虽然有对应关系。 指针级别,就是间接访问的次数, 数组维度,指的是数组层次,是一层套一层的概念,这个就是多维数组,递归定义的含义。 数组访问是逐层查找, 就像中央---省 ---县----镇----村--- 家-----个人 这样的查找的,不过是按照每一层次的大小(改维度的大小)数数而已。 数组每个维度,只是大块和小块的关系,整个数组是在一起的。 变量(所谓对象),和数据是直接对应的,所以是直接访问的。 指针,访问所指地址中的数据,是间接访问的。 多级指针,就是不断找到下级地址访问数据。每一级指针,只能找到下级指针。 指针分级,并不需要放在一起存储,除了一级一级找到地址,无法一次到位访问。 如果,某级指针未定义(初始化),就不能向下级访问了。 比如 int *p;// int **pp =& p;// 可以访问 *pp ;不可以访问 *p; 因为 p ;没有初始化----定义时候,没有初始化,也没有赋值,让他指向对象(变量)的地址。 数组,已经定义,各个维度都定义好了。 即 int a[M][N];//二维数组 a 已经定义。 a[0].........a[M-1] 都是定义好的一维子数组。 a[0][1].........a[M-1][N-1]; //都是定义好的数组元素(变量)。
lm_whales 2014-01-21
  • 打赏
  • 举报
回复
void output(char **buffer){ printf(“%s\n”,buffer[0]); // output::buffer == ((char**) (main::buffer); // output::buffer[0] == ((char**) (&main::buffer ))[0]; // // 这是把 main::buffer 当作储存指针的数组使用, // output::buffer[0]是该指针数组的第一个元素 // 该指针其实是把 // main::buffer[0][0],main::buffer[0][1],main::buffer[0][2],main::buffer[0][3]。。。。 // 这4(指针长度)个字符,组成的一个整型数据,当作指针使用 // 这样 output::buffer[0] 其实是个野指针。 // 出错是正常,不错是巧合。 // 这里借用一下,C++的作用域限定符:: 表示作用域 } void main(){ char buffer[100][1024] = {0}; int len = sprintf(buffer[0],"i am a bastard..."); buffer[0][len] = '\0'; output(buffer);//传递buffer 即 &buffer[0],这里类型不对,应该报错,或者警告。 } 多级指针,需要指针数组做中转,或者动态分配数据 才能和多维数组匹配 //维持这种函数定义,需要传如指针地址,指针数组,和二级指针 void output(char **buffer){ printf(“%s\n”,buffer[0]); } void main(){ char buffer[100][1024] = {0}; int len = sprintf(buffer[0],"i am a bastard..."); buffer[0][len] = '\0'; /************* 1 ***************/ { char *p[100]; int i; for(i=0;i<100;i++)p[i] = buffer[i]; output(p); } /************* 1 ***************/ { char *p[100]; char **pp = &p; int i; for(i=0;i<100;i++)p[i] = buffer[i]; output( pp );// } /*********** 3**********/ { char **pp = malloc(sizeof(char *)*100);//c++ 替换为 char ** =new char*[100]; int i; for(i=0;i<100;i++)pp[i] = buffer[i]; output( pp );// free(pp); //c++ 替换为 delete[]pp; } }
14号选手 2014-01-21
  • 打赏
  • 举报
回复
参数类型的原因,你可以参考下我的这篇博文,希望能让你找到答案 http://blog.csdn.net/xuchao1229/article/details/8223518
  • 打赏
  • 举报
回复
无论一维,二维,三维,四维,五维...数组,本质上,它的首地址,都只是寻一次地址,大概可以说等价于一维指针。 但是一维,二维,三维...指针就不一样了。n维指针,要寻找n次地址。
初見的畫面 2014-01-21
  • 打赏
  • 举报
回复
引用 27 楼 rongxiaojun 的回复:
[quote=引用 26 楼 lwouyang 的回复:] 说了,技术上相等,因为算出来的都是同一个地址,不让它们相等能怎么办?
怎么算出来的? &地址符不就是取变量地址吗?都取了地址了buffer又怎么能和&buffer相等呢?buffer[0]是值,&buffer[0]是它的地址,值和地址是一回事吗? int a = 14; 你怎么不让a和&a相等?[/quote] 因为是同一个地址,只不过类型不一样,
SKATE11 2014-01-21
  • 打赏
  • 举报
回复
这个只能弄成数组指针
dcw0402 2014-01-21
  • 打赏
  • 举报
回复
赵4老师 2014-01-21
  • 打赏
  • 举报
回复
//在堆中开辟一个4×5的二维int数组
#include <stdio.h>
#include <malloc.h>
int **p;
int i,j;
void main() {
    p=(int **)malloc(4*sizeof(int *));
    if (NULL==p) return;
    for (i=0;i<4;i++) {
        p[i]=(int *)malloc(5*sizeof(int));
        if (NULL==p[i]) return;
    }
    for (i=0;i<4;i++) {
        for (j=0;j<5;j++) {
            p[i][j]=i*5+j;
        }
    }
    for (i=0;i<4;i++) {
        for (j=0;j<5;j++) {
            printf(" %2d",p[i][j]);
        }
        printf("\n");
    }
    for (i=0;i<4;i++) {
        free(p[i]);
    }
    free(p);
}
//  0  1  2  3  4
//  5  6  7  8  9
// 10 11 12 13 14
// 15 16 17 18 19
//在堆中开辟一个3×4×5的3维int数组
#include <stdio.h>
#include <malloc.h>
int ***p;
int i,j,k;
void main() {
    p=(int ***)malloc(3*sizeof(int **));
    if (NULL==p) return;
    for (i=0;i<3;i++) {
        p[i]=(int **)malloc(4*sizeof(int *));
        if (NULL==p[i]) return;
        for (j=0;j<4;j++) {
            p[i][j]=(int *)malloc(5*sizeof(int));
            if (NULL==p[i][j]) return;
        }
    }
    for (i=0;i<3;i++) {
        for (j=0;j<4;j++) {
            for (k=0;k<5;k++) {
                p[i][j][k]=i*20+j*5+k;
            }
        }
    }
    for (i=0;i<3;i++) {
        for (j=0;j<4;j++) {
            for (k=0;k<5;k++) {
                printf(" %2d",p[i][j][k]);
            }
            printf("\n");
        }
        printf("---------------\n");
    }
    for (i=0;i<3;i++) {
        for (j=0;j<4;j++) {
            free(p[i][j]);
        }
        free(p[i]);
    }
    free(p);
}
//  0  1  2  3  4
//  5  6  7  8  9
// 10 11 12 13 14
// 15 16 17 18 19
//---------------
// 20 21 22 23 24
// 25 26 27 28 29
// 30 31 32 33 34
// 35 36 37 38 39
//---------------
// 40 41 42 43 44
// 45 46 47 48 49
// 50 51 52 53 54
// 55 56 57 58 59
//---------------
Adol1111 2014-01-20
  • 打赏
  • 举报
回复
楼主来这里看看吧http://blog.csdn.net/code_crash/article/details/4855010 如果想了解的更清晰点,直接问supermegaboy本人
rongxiaojun 2014-01-20
  • 打赏
  • 举报
回复
引用 26 楼 lwouyang 的回复:
说了,技术上相等,因为算出来的都是同一个地址,不让它们相等能怎么办?
怎么算出来的? &地址符不就是取变量地址吗?都取了地址了buffer又怎么能和&buffer相等呢?buffer[0]是值,&buffer[0]是它的地址,值和地址是一回事吗? int a = 14; 你怎么不让a和&a相等?
lwouyang 2014-01-20
  • 打赏
  • 举报
回复
说了,技术上相等,因为算出来的都是同一个地址,不让它们相等能怎么办?
rongxiaojun 2014-01-20
  • 打赏
  • 举报
回复
引用 23 楼 lwouyang 的回复:
[quote=引用 22 楼 rongxiaojun 的回复:] [quote=引用 17 楼 dcw0402 的回复:] 这里,二维数组其实是一个一维数组的加长版.... 改成这样也可以 void output(char *buffer){ printf("%s\n",buffer); } 我也不知道为啥,感觉7楼说有的些道理
这是因为char buffer[100][1024]中,buffer的值即char[0][0]的地址,(真不可思议,二维数组地址即第一个数组中第一个元素地址,而非第一个数组的地址),然后调用函数output(buffer),此时buffer的值传进参数中,参数类型char*,则参数为char* 类型且指向了首字符'i',然后printf打印字符串直到'\0'出现,一切都解释通了。[/quote] 错!准确的讲,二维数组名的值是指向第一个数组的指针值,buffer == &buffer[0]。 二维数组在概念上是数组的数组,第一个数组 buffer[0] 的值才是指向 buffer[0][0] 的指针值。这些概念是实在的,因此 buffer+1 和 buffer[0]+1 都有各自确切的意义。技术上,这几个地址值是相等的,buffer == &buffer[0] == buffer[0] == &buffer[0][0]。但是 buffer 和 buffer[0] 类型是不同的。二维数组名 buffer 和 char* buffer 之间必有一个强制类型转换,而 buffer[0] 与 char* buffer 则是兼容类型。[/quote] 真不可思议: buffer==&buffer==&buffer[0] == buffer[0] == &buffer[0][0]真的相等,为什么?buffer==&buffer 和 buffer[0]==&buffer[0]就明显不一样吧,明显取了地址的,为什么?
derekrose 2014-01-20
  • 打赏
  • 举报
回复
lwouyang 2014-01-20
  • 打赏
  • 举报
回复
引用 22 楼 rongxiaojun 的回复:
[quote=引用 17 楼 dcw0402 的回复:] 这里,二维数组其实是一个一维数组的加长版.... 改成这样也可以 void output(char *buffer){ printf("%s\n",buffer); } 我也不知道为啥,感觉7楼说有的些道理
这是因为char buffer[100][1024]中,buffer的值即char[0][0]的地址,(真不可思议,二维数组地址即第一个数组中第一个元素地址,而非第一个数组的地址),然后调用函数output(buffer),此时buffer的值传进参数中,参数类型char*,则参数为char* 类型且指向了首字符'i',然后printf打印字符串直到'\0'出现,一切都解释通了。[/quote] 错!准确的讲,二维数组名的值是指向第一个数组的指针值,buffer == &buffer[0]。 二维数组在概念上是数组的数组,第一个数组 buffer[0] 的值才是指向 buffer[0][0] 的指针值。这些概念是实在的,因此 buffer+1 和 buffer[0]+1 都有各自确切的意义。技术上,这几个地址值是相等的,buffer == &buffer[0] == buffer[0] == &buffer[0][0]。但是 buffer 和 buffer[0] 类型是不同的。二维数组名 buffer 和 char* buffer 之间必有一个强制类型转换,而 buffer[0] 与 char* buffer 则是兼容类型。
rongxiaojun 2014-01-20
  • 打赏
  • 举报
回复
引用 17 楼 dcw0402 的回复:
这里,二维数组其实是一个一维数组的加长版.... 改成这样也可以 void output(char *buffer){ printf("%s\n",buffer); } 我也不知道为啥,感觉7楼说有的些道理
这是因为char buffer[100][1024]中,buffer的值即char[0][0]的地址,(真不可思议,二维数组地址即第一个数组中第一个元素地址,而非第一个数组的地址),然后调用函数output(buffer),此时buffer的值传进参数中,参数类型char*,则参数为char* 类型且指向了首字符'i',然后printf打印字符串直到'\0'出现,一切都解释通了。
rongxiaojun 2014-01-20
  • 打赏
  • 举报
回复
引用 11 楼 skyliuxu 的回复:
[quote=引用 楼主 rongxiaojun 的回复:] 长话短说: void output(char **buffer){ printf(“%s\n”,buffer[0]); } void main(){ char buffer[100][1024] = {0}; int len = sprintf(buffer[0],"i am a bastard..."); buffer[0][len] = '\0'; output(buffer); } 程序出现“段错误” 求解答!
是linux下gcc编译系统吗?在vs下错误信息就是write access violation at address 0xblablabla(大概是这么个错误提示吧,记不清了)。 为什么会出现这样的错误呢?这就值得好好探讨了。 首先,指针和数组是根本不同的两个东西!尽管它们有着千丝万缕的联系! 第二,要理解为什么出现上面这样的错误,需要理解两个最基本的东西: (1)数组名称出现在表达式中时(除用于sizeof外),会被看成一个指向该数组第一个元素的指针。注意,本质上讲,C中所有数组都是一维数组,所以第一个元素是什么是非常明确的。比如,int a[10]的第一个元素是一个整型数,而int a[10][10]的第一个元素是一个包含10个整型数的数组。 (2)指针可以与整型数进行加减法,结果是新的指针,而加减的单位是指针所指向元素的大小。比如,int *p, p = a;(注意体会(1)在这儿的作用),则p + 1指向的是a[1],p+4指向的是a[4]. 下面可以看一下为什么出现上面的错误了。 char buffer[100][1024]表示buffer是一个二维数组,output(buffer)中的buffer会被看做指向该二维数组第一个元素的指针,即被看作指向一个包含1024个char的数组的指针,char (*)[1024]是这个指针的类型。而在output的定义中,其期望的参数类型是char **,所以编译结果会有warning。当然,你依然可以运行,因为存在强制类型转换。这也是为什么4楼做法没用的原因,你显式的进行类型转换除了消除了warning外(机器是很好糊弄的),基本没有什么意义。接着分析出现错误的原因,output函数的参数声明是char **,即二级指针(pointer to pointer)。注意,强制类型转换不会改变指针的值。这样,buffer的值与main中定义的buffer的值是一样,不过output里的buffer是二级指针。那么buffer[0]是什么,buffer是二级指针,buffer[0]当然就是一级指针!buffer[0]等于多少?buffer[0]实际上是*(buffer+0),前面说过,指针是可以与整数进行加减法的(这是array index的基础),而加减的单位是该指针指向的元素的大小,buffer指向的是什么元素?char*!所以*(buffer+0)的值是0x6d612069(i am所占的四个字节的值对应的地址,注意little endian),因此,出现write access violation就不足为奇了。 大概就是这么个意思,有一些地方的表述是不够准确的,欢迎进一步探讨。[/quote] 说的太好了,几乎完全消化了 我总结一下(我系统是64位): GDB显示的结果如下: buffer=0x7ffffffe5180 buffer[0][0]=0x7ffffffe5180 output (buffer=0x7ffffffe5480) at b.c:22 如上三条说明了两个问题: 1.buffer其实是buffer[100][1024]中首元素buffer[0][0]的地址,即‘i’的地址 2.强制类型转换确实不会改变指针的值,尽管函数外buffer是char(*)[1024]类型、函数参数char**类型,外buffer还是将buffer[0][0]地址传给了参数char**。 此时问题来了,函数内buffer为二级指针,buffer[0]类型char*,为指针,64位系统指针8字节,则buffer[0]指针的值为buffer所指内存单元向下共8个内存单元内容组成的值。是不是很绕,这8个内存单元内容是什么呢,此时函数内buffer值就是函数外buffer[0][0]即字符'i'的地址,则从‘i’开始依次取八个字节得到的是'i am a b',将其转化为数值即为0x6d612069,故buffer[0]的值为0x6d612069,printf(“%s\n”,buffer[0]),故发生地址越界。
rongxiaojun 2014-01-20
  • 打赏
  • 举报
回复
引用 19 楼 lwouyang 的回复:
编译时编译器没抱怨吗?如果是,你可以把编译器扔了。 如果有报怨的话,你没看就轻易放过了?
得饶人处且饶人,我看不是大错只是警告,想放它条生路
lwouyang 2014-01-20
  • 打赏
  • 举报
回复
编译时编译器没抱怨吗?如果是,你可以把编译器扔了。 如果有报怨的话,你没看就轻易放过了?
mujiok2003 2014-01-20
  • 打赏
  • 举报
回复
char**p是一个指向char*的指针,*p或p[0]必须是一个地址。你的实参不满足这要求。
加载更多回复(17)

69,382

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧