C 字符[]和字符**之间的差异,为什么puts(字符串[0])无法打印(字符串定义为字符**字符串)

C 字符[]和字符**之间的差异,为什么puts(字符串[0])无法打印(字符串定义为字符**字符串),c,pointers,char,C,Pointers,Char,如何通过调用以下函数打印字符串数组: void function(char**string); //sample1 void function(char string[][LEN2], int size); //sample2 void function(char (*string)[LEN2], int size); //sample3 我认为2和3是正确的 这个问题的正确格式并不重要 我想知道,计算机是如何理解样本1的(特别是在内存中),而不仅仅是记录正确的答案 谢谢。(

如何通过调用以下函数打印字符串数组:

void function(char**string);    //sample1
void function(char string[][LEN2], int size);    //sample2
void function(char (*string)[LEN2], int size);    //sample3
我认为2和3是正确的

这个问题的正确格式并不重要

我想知道,计算机是如何理解样本1的(特别是在内存中),而不仅仅是记录正确的答案

谢谢。(我第一次使用,可能有点可笑。)

使用visual studio 2017,关闭安全检查。在PC上运行

#include<stdio.h>
#define LEN1 10
#define LEN2 100
void item1(char**string);
void print_initial_string(char**string);

int main(void)
{
    char string[LEN1][LEN2] = {"a", "ab", "abc", "abcd", "abcde",
            "c", "cd", "cde", "cdgh", "seids"};
    item1(string);
}

/*implements of functions*/
void item1(char**string)
{
    print_initial_string(string);
}
void print_initial_string(char**string)
{
    char (*c)[LEN2] = string[0];
    for (int i = 0; i < LEN1; i++)
        puts(c);     /*-- stopped at here --*/
}
#包括
#定义LEN1 10
#定义LEN2 100
无效项1(字符**字符串);
无效打印\初始\字符串(字符**字符串);
内部主(空)
{
字符字符串[LEN1][LEN2]={a”、“ab”、“abc”、“abcd”、“abcde”,
“c”、“cd”、“cde”、“cdgh”、“seids”};
项目1(字符串);
}
/*功能的实现*/
无效项1(字符**字符串)
{
打印首字母字符串(字符串);
}
无效打印\u初始\u字符串(字符**字符串)
{
char(*c)[LEN2]=字符串[0];
对于(int i=0;i
我想它会打印字符串,但失败了


并返回一个代码-1073741819

如果我编译时执行
gcc-pedantic-Wextra ar.c
我会收到很多指示问题的消息:

pi@raspberrypi:~/Downloads $ gcc -pedantic -Wextra ar.c
ar.c: In function ‘main’:
ar.c:11:11: warning: passing argument 1 of ‘item1’ from incompatible pointer type [-Wincompatible-pointer-types]
     item1(string);
           ^~~~~~
ar.c:4:6: note: expected ‘char **’ but argument is of type ‘char (*)[100]’
 void item1(char**string);
      ^~~~~
ar.c: In function ‘print_initial_string’:
ar.c:21:23: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
     char (*c)[LEN2] = string[0];
                       ^~~~~~
ar.c:23:14: warning: passing argument 1 of ‘puts’ from incompatible pointer type [-Wincompatible-pointer-types]
         puts(c);     /*-- stopped at here --*/
              ^
In file included from ar.c:1:0:
/usr/include/stdio.h:697:12: note: expected ‘const char *’ but argument is of type ‘char (*)[100]’
 extern int puts (const char *__s);
            ^~~~

char**string
是一个由
char*
组成的数组,这意味着字符串中的每个条目都是一个
char*
(指针),这不是char string[LEN1][LEN2]的含义,因为它不包含指针

所以
void item1(char(*string)[LEN2])
void print_initial_string(char(*string)[LEN2])

char(*c)[LEN2]=字符串[0]也不正常,c是一个字符*但是你说它是指向
char[LEN2]
的指针,你想要
char(*c)[LEN2]=&string[0]或仅
字符(*c)[LEN2]=字符串。在这种情况下,
put(c)
必须是
put(c[i])
最后:

#include<stdio.h>

#define LEN1 10
#define LEN2 100

void item1(char (*string)[LEN2]);
void print_initial_string(char (*string)[LEN2]);

int main(void)
{
    char string[LEN1][LEN2] = {"a", "ab", "abc", "abcd", "abcde",
                               "c", "cd", "cde", "cdgh", "seids"};
    item1(string);
}

/*implements of functions*/
void item1(char (*string)[LEN2])
{
    print_initial_string(string);
}
void print_initial_string(char (*string)[LEN2])
{
  char (*c)[LEN2] = string;

  for (int i = 0; i < LEN1; i++)
    puts(c[i]);
}
在valgrind下执行:


char**
正确的示例:

#include <stdio.h>
#include <stdlib.h>

#define LEN 10

void pr(const char ** a, int sz)
{
  for (int i = 0; i != sz; ++i)
    puts(a[i]);
}

int main()
{
  const char *a[LEN] = { "a", "ab", "abc", "abcd", "abcde",
                         "c", "cd", "cde", "cdgh", "seids"};

  pr(a, LEN);
}

这是我为理解这个问题而编写的程序,答案在评论中

#include<stdio.h>
#define LEN1 10
#define LEN2 100
int main(void)
{
    //first method to define a string array(using array)
    char string0[LEN1][LEN2] = {"a", "ab", "abc", "abcd", "abcde",
                           "c", "cd", "cde", "cdgh", "seids"};
    //char(*c0)[LEN2] = string0;    //right
    char ** c1 = string0;    //wrong!

    //second method to define a string array(using pointer)
    char *string1[LEN1] = { "a", "ab", "abc", "abcd", "abcde",
                        "c", "cd", "cde", "cdgh", "seids" };
    char **c3 = string1;

    //for using array:
    printf("string0 = %p\n", string0);
    printf("string0 + 1 = %p\n", string0 + 1);
    printf("sizeof(string0) = %u\n", sizeof(string0));    //1000
    printf("string0[0] = %p\n", string0[0]);
    printf("string0[0] + 1 = %p\n", string0[0] + 1);
    printf("sizeof(string0[0]) = %u\n", sizeof(string0[0]));    //100

    printf("\n");
    printf("c1 = %p\n", c1);
    printf("sizeof(c1[0]) = %d\n", sizeof(c1[0]));
    printf("c1[0] = %p\n", c1[0]);    //suppose c1[0] is a pointer
    //61
    printf("'a' = %x\n", 'a');    //some thing has been clear
    //61
    /*
    my thinking:
        In c program, the value of a pointer just indecate which memory cell it 
    refers. And what program looks a pointer like may be embodied in the value of
    "sizeof" operator. For example:
        sizeof(string0) = 1000, so string0 is a whole reference of the array.
        sizeof(string0[0]) = 100, so string0[0] is a row in that array.
        If add one to string0, we find it is bigger 100 than old one.
        If add one to string0[0], we find it is bigger 1 than old one.
        Though both of string0 and string0[0] has the same content.

        So, it is not important that string0's and string0[0]'s same content.
        But what will hapen when string0 + 1 and string0[0] + 1.
        pointer + integer = value(pointer) + sizeof(pointer)*integer;
        value(a):the content of a;

        c1's content is same as string0, program regard c1[0] as a pointer.
    But c1[0]'s value is character 'a'. So, the program failed.
    */
    return 0;
}
#包括
#定义LEN1 10
#定义LEN2 100
内部主(空)
{
//定义字符串数组的第一个方法(使用数组)
char string0[LEN1][LEN2]={“a”、“ab”、“abc”、“abcd”、“abcde”,
“c”、“cd”、“cde”、“cdgh”、“seids”};
//char(*c0)[LEN2]=string0;//右
char**c1=string0;//错误!
//定义字符串数组的第二种方法(使用指针)
char*string1[LEN1]={“a”、“ab”、“abc”、“abcd”、“abcde”,
“c”、“cd”、“cde”、“cdgh”、“seids”};
char**c3=string1;
//要使用阵列,请执行以下操作:
printf(“string0=%p\n”,string0);
printf(“string0+1=%p\n”,string0+1);
printf(“sizeof(string0)=%u\n”,sizeof(string0));//1000
printf(“string0[0]=%p\n”,string0[0]);
printf(“string0[0]+1=%p\n”,string0[0]+1);
printf(“sizeof(string0[0])=%u\n”,sizeof(string0[0]);//100
printf(“\n”);
printf(“c1=%p\n”,c1);
printf(“sizeof(c1[0])=%d\n”,sizeof(c1[0]);
printf(“c1[0]=%p\n”,c1[0]);//假设c1[0]是指针
//61
printf(“'a'=%x\n','a');//有些事情已经很清楚了
//61
/*
我的想法是:
在c程序中,指针的值只指示它所属的存储单元
而程序看起来像指针的内容可能体现在
“sizeof”运算符。例如:
sizeof(string0)=1000,因此string0是数组的整个引用。
sizeof(string0[0])=100,因此string0[0]是该数组中的一行。
如果将一个添加到string0,我们发现它比旧的要大100。
如果将一个添加到string0[0],我们发现它比旧的1大。
虽然string0和string0[0]的内容相同。
因此,string0和string0[0]的内容是否相同并不重要。
但是当string0+1和string0[0]+1时会发生什么呢。
指针+整数=值(指针)+sizeof(指针)*整数;
值(a):a的内容;
c1的内容与string0相同,程序将c1[0]视为指针。
但是c1[0]的值是字符“a”。因此,程序失败。
*/
返回0;
}

emmm,忘记返回0;a
返回0在main末尾是隐式的。我解释了您的错误,并在执行过程中提供了问题的更正版本。编译时请查看我的答案,始终启用警告,然后修复这些警告。(对于
gcc
,至少使用:
-Wall-Wextra-Wconversion-pedantic-std=gnu11
)注意:其他编译器使用不同的选项来执行相同的功能。感谢您的回答!看了你的答案后,我写了一个程序来理解它们之间的区别。我知道为什么char**a和char string[][]不能一起使用。因为“a=string”引用了字符串[0]的第一个字符。然后,程序将“a”视为指针。因此,它将使用字符值emmm找到一个新地址,听起来很可笑。
#include <stdio.h>
#include <stdlib.h>

#define LEN 10

void pr(const char ** a, int sz)
{
  for (int i = 0; i != sz; ++i)
    puts(a[i]);
}

int main()
{
  const char *a[LEN] = { "a", "ab", "abc", "abcd", "abcde",
                         "c", "cd", "cde", "cdgh", "seids"};

  pr(a, LEN);
}
pi@raspberrypi:/tmp $ gcc -pedantic -Wall aa.c
pi@raspberrypi:/tmp $ ./a.out
a
ab
abc
abcd
abcde
c
cd
cde
cdgh
seids
#include<stdio.h>
#define LEN1 10
#define LEN2 100
int main(void)
{
    //first method to define a string array(using array)
    char string0[LEN1][LEN2] = {"a", "ab", "abc", "abcd", "abcde",
                           "c", "cd", "cde", "cdgh", "seids"};
    //char(*c0)[LEN2] = string0;    //right
    char ** c1 = string0;    //wrong!

    //second method to define a string array(using pointer)
    char *string1[LEN1] = { "a", "ab", "abc", "abcd", "abcde",
                        "c", "cd", "cde", "cdgh", "seids" };
    char **c3 = string1;

    //for using array:
    printf("string0 = %p\n", string0);
    printf("string0 + 1 = %p\n", string0 + 1);
    printf("sizeof(string0) = %u\n", sizeof(string0));    //1000
    printf("string0[0] = %p\n", string0[0]);
    printf("string0[0] + 1 = %p\n", string0[0] + 1);
    printf("sizeof(string0[0]) = %u\n", sizeof(string0[0]));    //100

    printf("\n");
    printf("c1 = %p\n", c1);
    printf("sizeof(c1[0]) = %d\n", sizeof(c1[0]));
    printf("c1[0] = %p\n", c1[0]);    //suppose c1[0] is a pointer
    //61
    printf("'a' = %x\n", 'a');    //some thing has been clear
    //61
    /*
    my thinking:
        In c program, the value of a pointer just indecate which memory cell it 
    refers. And what program looks a pointer like may be embodied in the value of
    "sizeof" operator. For example:
        sizeof(string0) = 1000, so string0 is a whole reference of the array.
        sizeof(string0[0]) = 100, so string0[0] is a row in that array.
        If add one to string0, we find it is bigger 100 than old one.
        If add one to string0[0], we find it is bigger 1 than old one.
        Though both of string0 and string0[0] has the same content.

        So, it is not important that string0's and string0[0]'s same content.
        But what will hapen when string0 + 1 and string0[0] + 1.
        pointer + integer = value(pointer) + sizeof(pointer)*integer;
        value(a):the content of a;

        c1's content is same as string0, program regard c1[0] as a pointer.
    But c1[0]'s value is character 'a'. So, the program failed.
    */
    return 0;
}