C 解决指向字符串的指针中的分段错误

C 解决指向字符串的指针中的分段错误,c,arrays,string,multidimensional-array,C,Arrays,String,Multidimensional Array,当我想在动态数组中保存字符串时,我遇到了分段错误 我有一个这样做的程序: 用户插入字符“s” 程序进入循环并将字符串保存在数组中(名称:cod)。 当用户插入字符“t”时,它停止 之后,我将该数组保存在新动态数组(名称:vec)的第一个位置。 然后如果用户再次插入字符“s” 程序进入循环并将字符串保存在数组中。 当用户插入字符“t”时,它停止 之后,我将该数组保存在新动态数组的第二个位置。 还有一个。 这是我的代码: int main(){ 返回0 } 这是代码中起作用的部分:

当我想在动态数组中保存字符串时,我遇到了分段错误

我有一个这样做的程序:

用户插入字符“s”
程序进入循环并将字符串保存在数组中(名称:cod)。
当用户插入字符“t”时,它停止

之后,我将该数组保存在新动态数组(名称:vec)的第一个位置。

然后如果用户再次插入字符“s”
程序进入循环并将字符串保存在数组中。
当用户插入字符“t”时,它停止

之后,我将该数组保存在新动态数组的第二个位置。

还有一个。


这是我的代码:

int main(){

返回0

}

这是代码中起作用的部分:

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


int main(){

    char Cod[30][11];
    char tmp[11];
    int i = 0;


    strcpy (tmp, "p");


    do {

        scanf("%s", tmp);

        while( (strcmp (tmp, "p")) != 0){

            strcpy ( Cod[i] , tmp ); 

            scanf("%s", tmp);

            i++;
        }

        scanf("%s", tmp);

    }

    while((strcmp (tmp, "s")) == 0);

        printf("%s", Cod[0]);

return 0;

}
#包括
#包括
#包括
int main(){
煤焦Cod[30][11];
char-tmp[11];
int i=0;
strcpy(tmp,p”);
做{
scanf(“%s”,tmp);
而((strcmp(tmp,“p”)!=0){
strcpy(Cod[i],tmp);
scanf(“%s”,tmp);
i++;
}
scanf(“%s”,tmp);
}
而(strcmp(tmp,s))=0 ;;
printf(“%s”,Cod[0]);
返回0;
}
三星级

char ***vec;
您需要3
malloc
s(C中的强制转换最多是冗余的,可能会隐藏错误)

三星级

char ***vec;
您需要3
malloc
s(C中的强制转换最多是冗余的,可能会隐藏错误)

在这两行中:

vec = (char ***) realloc (vec, sizeof ( char *) * (i + 1));
vec[i + 1] = (char ** ) realloc (vec[i + 1], sizeof ( char *) * (30));
如果i=1,则保留到“vec”i+1=2个指针。然后在第二行中调用第三行(vec[i+1]=vec[2]是大小表2中的第三个元素)。

在这两行中:

vec = (char ***) realloc (vec, sizeof ( char *) * (i + 1));
vec[i + 1] = (char ** ) realloc (vec[i + 1], sizeof ( char *) * (30));

如果i=1,则保留到“vec”i+1=2个指针。在第二行中,您可以调用第三行(vec[i+1]=vec[2]是大小表2中的第三个元素)。

我开始修复此代码,但很快意识到其中有太多错误,我不知道从哪里开始。所以,事实证明,这是一个答案,如果它是详细和挑剔的,我首先道歉

  • C语言中有一条经验法则,即如果需要两级以上的指针间接寻址,那么代码就会变得模糊,应该重写(参考MISRA-C:2004 17.5)

  • 在这种情况下,使用动态内存分配没有任何意义,因为在程序启动时,您已经知道没有任何字符串大于11个字符,也不会有超过30个字符串。如果此条件不成立,则需要编写一个更安全的输入方法,最好是使用fgets(),这样可以防止缓冲区溢出。确保输入没有超出数组“Cod”的范围。您可以静态地分配30*11=330字节,而不会感到内疚。这将使代码更快

  • 对于一个字符串数组,有3级间接寻址是没有意义的。您甚至不需要使用动态内存来保存字符串的副本,只需要分配指针。这毫无意义。如果需要指向
    Cod
    的指针查找表,则静态分配它,它只需要sizeof(char*)*30字节

  • 如前所述,您只能在以前被malloc/calloc:ed处理过的指针上使用realloc

  • <> >前面已经说过,不要在C中键入MalC/C的结果。这是C++实践。在C中,它破坏类型安全性并隐藏类型兼容性错误。这里有无数详细的讨论,如果你想知道细节的话

  • 如果在用户字符串中找不到“p”,该怎么办?这项计划将遭到严重破坏

  • 不要将影响基本程序功能的变量命名为抽象的东西,如tmp、vec等。tmp可以重命名为input_buf或其他东西

  • 避免在代码中使用幻数,对数组长度常量使用常量或#define

  • 您可以在C中初始化字符串,而不需要strcpy这样做<代码>字符输入[INP\u buf\u N]=“p”

  • 要在字符串中搜索字符,请使用strhr()

  • 您不需要让用户在外部do while循环中使用scanf()两次输入相同的内容,这可能是一个打字错误

  • 您不能在指向指针的静态数组与指向指针的指针之间执行野生类型转换。这取决于指针指向的对象的结构。因为一个典型的哑教科书动态2D数组(malloc(Xsizeof(char)…malloc(Y*sizeof(char))不会相邻地分配内存

(您可以使用数组指针或“mangling”在相邻内存中分配动态2D数组,但这些都是相当高级的主题)

  • free()在使用完动态内存后释放它

正如你所希望的那样,明智的选择是从头开始重写这段代码。

我开始修复这段代码,但很快意识到其中有太多错误,我不知道从哪里开始。因此,这是一个答案,如果它是详细和挑剔的,我首先道歉

  • C语言中有一条经验法则,即如果需要两级以上的指针间接寻址,那么代码就会变得模糊,应该重写(参考MISRA-C:2004 17.5)

  • 在这种情况下,使用动态内存分配没有任何意义,因为在程序启动时,您已经知道任何字符串都不会超过11个字符,也不会超过30个字符串。如果此条件不成立,您需要编写一个更安全的输入法,最好使用fgets()这对缓冲区溢出是安全的。确保输入不会超出数组“Cod”的界限。您可以静态分配30*11=330字节,而不会感到内疚。这将使代码更快

  • 对于一个字符串数组来说,有3个级别的间接寻址是没有意义的
    char Cod[30][11];
    char tmp[11];
    char ***vec;
    int i = 0;
    
    
    strcpy (tmp, "p");
    vec = (char***)malloc(sizeof(char *));
    vec[0] = (char**)malloc(sizeof(Cod));
    
    
    do {
        scanf("%s", tmp);        
        int j = 0;
        while(strcmp(tmp, "p")) {
            strcpy(Cod[j], tmp);
            scanf("%s", tmp);
            j++;
        }
        vec = (char ***)realloc(vec, sizeof(char *) * (i+1));
        vec[i] = (char **)malloc(sizeof(Cod));
        memcpy(vec[i], Cod, sizeof(Cod));//you need to copy results since next time the Cod will be rewritten
        scanf("%s", tmp);
        i++;
    } while((strcmp(tmp, "s")) == 0);