在指向char的指针数组中输入单词时出错

时间:2018-10-14 22:06:50

标签: c arrays pointers

此程序检查指向char **s的指针数组中的单词(应首先加载)是否与函数fun中的单词相同。由于某些原因,我无法在main函数中正确加载单词,而且我也不知道为什么。

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

int fun(char **s,int j)
{
    int i, num=0;

    for(i=0;i<j;i++)
    {
       if(strcmp(s[i],"first")==0)
        num++;
        if(strcmp(s[i],"second")==0)
         num++;

    }

    if(num==j)
      return 1;
    else
      return 0;

}
int main(int argc,char *argv[])
{
    char **s=(char**)malloc(20*sizeof(char*)); // alloc
    char ss[20];
    int i=0,ret;

    while(1)  // while string 'ss' is different from string "stop"
    {
       scanf("%s",ss);

       if(strcmp(ss,"stop")==0)
        break;
       else
     {    s[i]=ss; // if ss is different from "stop"
          i++;

     }

}

ret=fun(s,i); // returns 1 if words are the same as words in function fun

if(ret)
 printf("Matching\n");

else
 printf("Doesn't matches\n");

for(int t=0;t<i;t++)
   free(s[i]);
free(s);    

}

3 个答案:

答案 0 :(得分:0)

char **s=(char**)malloc(20*sizeof(char*)); // alloc

这为20个指向char的指针腾出了空间。实际存储char的空间不大。

s[i]=ss; // if ss is different from "stop"

在循环中执行此操作只会导致指向char的相同基础序列的一堆指针。您需要使用循环或类似strncpy的函数来实际复制char

for(int t=0;t<i;t++)
   free(s[i]);

这应该是一个明显的错误迹象,因为与此malloc没有对应的free。 (您只有malloc与此下方的free(s);相对应。)

答案 1 :(得分:0)

按照您的所有说明,我使用功能strcpy解决了可能有相同问题的人:

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

 int fun(char **s,int j) 
 {
    int i;

    int num=0,numm=0;

    for(i=0;i<j;i++)
    {
        if(strcmp(s[i],"first")==0)
        num=1;
        if(strcmp(s[i],"second")==0)
        numm=1;

    }

    if(num!=0 && numm!=0)
     return 1;
    else
     return 0;

   }

   int main(int argc,char *argv[])
   {
       char **s; //  pointer to pointer to char
       char ss[20];
       int i=0,ret; // i-number of words we entered

       scanf("%s",ss);
       if(strcmp(ss,"stop")!=0)
       {
          s=(char**)malloc(1*sizeof(char*));
          s[i]=malloc(20*sizeof(char));
          strcpy(s[i],ss);
          i++;
       }

       while(1)  // while string 'ss' is different from string "stop"
       {
           scanf("%s",ss);

           if(strcmp(ss,"stop")!=0)
           {
              s=(char**)realloc(s,(i+1)*sizeof(char*));
              s[i]=malloc(20*sizeof(char));
              strcpy(s[i],ss);

              i++;
           }
           else
             break;

         }  

         ret=fun(s,i); // returns 1 if words are the same as words in function fun  

      if(ret)
        printf("\nMatching\n");
      else
        printf("\nDoesn't matches\n");

       for(int t=0;t<i;t++)
         free(s[i]);

       free(s);

}

答案 2 :(得分:0)

简单的解决方案,如果有,请使用strdup

您的问题是您只分配了20指针。您分配的指针是未初始化的,它们本身也不指向任何有效的存储。为了在每个s[i]指针处存储字符串,您必须分配足以存储ssstrlen(ss) + 1个字符)的存储空间,然后将ss复制到分配的新内存块中。如果您拥有strdup函数,该函数既可以为您分配又可以为您复制,但是由于已分配,因此您需要验证分配成功,例如

#define NPTR 20     /* if you need a constant, #define one (or more) */

int main (int argc, char *argv[])
{
    char **s = NULL;    /* initialize all variables */
    char ss[20] = "";
    int i = 0,
        ret = 0;

    s = malloc (NPTR * sizeof *s);  /* allocate NPTR pointers to char */
    if (s == NULL) {                /* validate EVERY allocation */
        perror ("malloc-s");
        return 1;
    }

    /* fill up to NPTR pointers with strings read from stdin */
    while (i < NPTR && scanf ("%19s", ss) == 1) {
        /* compare for stop */
        if (strcmp (ss, "stop") == 0)
            break;
        /* strdup will allocate for s[i] and copy ss */
        s[i] = strdup (ss);
        if (s[i] == NULL) {         /* it allocates -> you must validate */
            perror ("strdup-s[i]");
            break;
        }
        i++;
    }
}

注意:您必须通过在ss调用中加入 filed width 修饰符来保护scanf的数组边界,例如{{ 1}})

如果您没有scanf ("%19s", ss),只需strdupmalloc(或更好的strcpy

在没有memcpy的情况下,您只需获取strdup中字符串的长度,分配ss个字符,并将新内存块的起始地址分配给length+1,然后将s[i]复制到新的内存块中。上面的唯一更改是:

ss

注意:,您已经用 ... /* fill up to NPTR pointers with strings read from stdin */ while (i < NPTR && scanf ("%19s", ss) == 1) { size_t len = 0; /* compare for stop */ if (strcmp (ss, "stop") == 0) break; len = strlen (ss); /* get length of string in ss */ s[i] = malloc (len + 1); /* allocate length + 1 chars */ if (s[i] == NULL) { /* you allocate / you validate */ perror ("malloc-s[i]"); break; } memcpy (s[i], ss, len + 1); /* you have length, just memcpy */ i++; } ... 扫描了ss以获取长度,因此不需要strlen(再次扫描末尾),只需使用strcpy长度的memcpy复制 nul-termination 字符,这会更有效率)。

这两种方法均有效。然后释放已分配的内存。

+1

也请注意:for (int j = 0; j < i; j++) free (s[j]); /* free storage for each string */ free (s); /* free pointers */ 检查可防止存储超出分配的指针数量的字符串。您不必i < NPTR停下来,而只需i == NPTR指针的数量,然后继续。一般的方法是跟踪已分配的指针的数量,当达到极限时,realloc将指针的数量加倍(或将当前数量乘以{{ 1}}或其他任何方法),验证重新分配是否成功,并更新分配给新指针数量的当前数字,并继续操作直到再次达到指针限制,然后根据需要重复...)