C 代码编译后从不兼容的指针类型赋值

C 代码编译后从不兼容的指针类型赋值,c,C,我最近一直在学习C编程,并编写了一些代码。以下是我编写的代码: #include <stdio.h> int main(int argc, char ** argv){ int num[] = {10, 15, 25, 30, 45, 10}; char *names[][11] = {"Drew", "Larry Page", "Seggy", "Mark"}; //int *ip, i = 0; char **ip; int *p,

我最近一直在学习C编程,并编写了一些代码。以下是我编写的代码:

#include <stdio.h>

int main(int argc, char ** argv){


    int num[] = {10, 15, 25, 30, 45, 10};
    char *names[][11] = {"Drew", "Larry Page", "Seggy", "Mark"};
    //int *ip, i = 0;
    char **ip;
    int *p, i = 0, j = 0;

    for (ip = names; *(ip + i); i++)
        printf("%s ", *(ip + i));
    printf("\n\n");

    for (p = num; j < sizeof(num)/sizeof(num[0]); j++)
        printf("%d ", *(p + j));
    printf("\n");
    return 0;
}

我已经在各种IDE上测试了代码,但得到了类似的警告。感谢您的帮助。

问题出在这一行:

char *names[][11] = {"Drew", "Larry Page", "Seggy", "Mark"};
您不需要指向
char
的2d指针数组,您需要指向
char
的指针数组:

char *names[] = {"Drew", "Larry Page", "Seggy", "Mark"}; /* Don't hardcode 11 */

您需要的是
char*names[11]
字符指针数组,而不是
char*names[][11]

宣布它像

char *names[] = {"Drew", "Larry Page", "Seggy", "Mark"};

您收到此警告的原因是
char*names[][11]
属于
char*[1][11]
类型,而
char**ip
属于
char**
类型。 基本上,您所做的是创建指向char的指针的1x11数组(一行11列,11个指针)。 因为C中没有部分初始化,所以前4个指针将指向只读内存中静态字符串文本的地址,其余指针将为零

绕过编译器警告并使代码正常工作的最简单方法是在第一个for循环中强制转换
ip=(char**)名称。它将起作用,因为
ip
想要指向某个指针的地址,而
名称是什么
——它基本上是数组中第一个指针的地址。现在,当您取消引用
ip
时,您将获得4个指针,并在
标记后停止,因为第五个指针将为0

int main(int argc, char ** argv){


int num[] = {10, 15, 25, 30, 45, 10};
char *names[][11] = {"Drew", "Larry Page", "Seggy", "Mark"};
//int *ip, i = 0;
char **ip;
int *p, i = 0, j = 0;

for (ip = (char** )names; *(ip + i); i++)
    printf("%s ", *(ip + i));
printf("\n\n");

for (p = num; j < sizeof(num)/sizeof(num[0]); j++)
    printf("%d ", *(p + j));
printf("\n");
return 0;
}
以上两种解决方案都不清楚,我认为它们是“黑客”。我建议您使用下面最后两个示例中的一个。 简要说明:

  • 编译器允许您省略第一个维度大小,因为要计算数组元素的偏移量,您只需要第二个维度大小
  • 如果使用-Wall启用警告,编译器通常会发出警告:初始化器周围缺少大括号。所以总是使用大括号,比如So
    char*names[][11]={{{“Drew”,“Larry Page”,“Seggy”,“Mark”}
  • 除了上面的简单解释之外,我假设您希望以某种方式存储字符串数组并打印它们。 有几种方法可以实现这一点:

  • 制作一个指向字符串的指针数组-
    char*names[]={“Drew”、“Larry Page”、“Seggy”、“Mark”},但这样就无法更改字符串的内容,因为所有文本字符串都驻留在只读内存中。这就是为什么最好使用
    const
    限定符来更加明确您不能更改内容(
    const char*names[]={“Drew”、“Larry Page”、“Seggy”、“Mark”};
    ),如果您不使用它,编译器将允许您更改内容,但当程序执行时,它将生成分段错误,如果您使用
    const
    ,编译器甚至不允许您编译
  • 制作一个多维字符串数组-
    charnames[][11]={{{“Drew”}、{“Larry Page”}、{“Seggy”}、{“Mark”}。在这里,您必须确保知道字符串的大小。您可以在此处更改数组内容
  • 这是修改后的工作版本,没有警告,带有多维数组:

    int main(int argc, char ** argv){
    
    
    int num[] = {10, 15, 25, 30, 45, 10};
    char names[][11] = {{"Drew"}, {"Larry Page"}, {"Seggy"}, {"Mark"}};
    //int *ip, i = 0;
    char (*ip)[11];
    int *p, i = 0, j = 0;
    
    for (ip = names; i < sizeof(names)/sizeof(names[0]); i++)
        printf("%s ", *(ip + i));
    printf("\n\n");
    
    for (p = num; j < sizeof(num)/sizeof(num[0]); j++)
        printf("%d ", *(p + j));
    printf("\n");
    return 0;
    }
    
    int main(int argc,char**argv){
    int num[]={10,15,25,30,45,10};
    字符名[][11]={{“Drew”}、{“Larry Page”}、{“Seggy”}、{“Mark”};
    //int*ip,i=0;
    字符(*ip)[11];
    int*p,i=0,j=0;
    对于(ip=名称;i
    以下是带字符串指针数组的修改版本:

    int main(int argc, char ** argv){
    
    
    int num[] = {10, 15, 25, 30, 45, 10};
    char *names[11] = {"Drew", "Larry Page", "Seggy", "Mark"};
    //int *ip, i = 0;
    char **ip;
    int *p, i = 0, j = 0;
    
    for (ip = names; *(ip + i); i++)
        printf("%s ", *(ip + i));
    printf("\n\n");
    
    for (p = num; j < sizeof(num)/sizeof(num[0]); j++)
        printf("%d ", *(p + j));
    printf("\n");
    return 0;
    }
    
    int main(int argc,char**argv){
    int num[]={10,15,25,30,45,10};
    char*names[11]={“Drew”、“Larry Page”、“Seggy”、“Mark”};
    //int*ip,i=0;
    字符**ip;
    int*p,i=0,j=0;
    对于(ip=名称;*(ip+i);i++)
    printf(“%s”,*(ip+i));
    printf(“\n\n”);
    对于(p=num;j

    我已尝试修改您的代码。进一步的优化仍有可能。

    感谢@keine的快速回复。如果没有11,我会得到这个分段错误:
    bash:line 1:7分段错误(内核转储)bash-c'gcc-o jdoodle*.c&&./jdoodle'
    @Fokwa最佳检查循环condition@FokwaBest:
    NULL
    -终止指针数组:
    char*names[]={“Drew”、“Larry Page”、“Seggy”、“Mark”、NULL}大家好。我将for循环更新为
    for(ip=names;I
    ,错误消失了。谢谢大家。下次使用
    -Wall-Wextra
    编译时,您会看到更多的东西也可以用C来处理,而不是
    *(ip+i)
    我们编写
    ip[i]
    ;-)谢谢你的详细解释。对于第二个示例,我们可以省略大小,因为我们在声明时正在初始化数组
    char*names[]
    然后在for循环中使用
    i
    可以忽略大小,但我没有忽略它,因为我试图修改您的代码。请注意,您的代码保持不变,只更正其中不正确的部分。无需更改for循环条件,因为C中没有部分初始化,
    名称
    将在
    标记
    字符串后填充空指针,因此for循环将按预期终止。我已经测试了所有示例,它们按预期工作。
    int main(int argc, char ** argv){
    
    
    int num[] = {10, 15, 25, 30, 45, 10};
    char names[][11] = {{"Drew"}, {"Larry Page"}, {"Seggy"}, {"Mark"}};
    //int *ip, i = 0;
    char (*ip)[11];
    int *p, i = 0, j = 0;
    
    for (ip = names; i < sizeof(names)/sizeof(names[0]); i++)
        printf("%s ", *(ip + i));
    printf("\n\n");
    
    for (p = num; j < sizeof(num)/sizeof(num[0]); j++)
        printf("%d ", *(p + j));
    printf("\n");
    return 0;
    }
    
    int main(int argc, char ** argv){
    
    
    int num[] = {10, 15, 25, 30, 45, 10};
    char *names[11] = {"Drew", "Larry Page", "Seggy", "Mark"};
    //int *ip, i = 0;
    char **ip;
    int *p, i = 0, j = 0;
    
    for (ip = names; *(ip + i); i++)
        printf("%s ", *(ip + i));
    printf("\n\n");
    
    for (p = num; j < sizeof(num)/sizeof(num[0]); j++)
        printf("%d ", *(p + j));
    printf("\n");
    return 0;
    }