Ошибка при вводе слов в массив указателей на символ - PullRequest
0 голосов
/ 15 октября 2018

Эта программа проверяет, совпадают ли слова в массиве указателей на символ **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 голосов
/ 15 октября 2018

Следуя всем вашим инструкциям, я решил ее, используя функцию 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);

}

0 голосов
/ 15 октября 2018

Простое решение, используйте strdup, если оно у вас есть

Ваша проблема заключалась в том, что вы выделяли только 20 указатели.Выделенные указатели неинициализированы и сами по себе не указывают на какое-либо действительное хранилище.Чтобы хранить строки в каждом указателе s[i], необходимо выделить хранилище, достаточное для хранения ss (strlen(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, например, scanf ("%19s", ss))

Если у вас нет strdup, просто malloc и 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 с длиной, которая у вас есть +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 количество указателей и продолжить. Общий подход состоит в том, чтобы отслеживать количество выделенных вами указателей, а когда вы достигнете своего предела, realloc, чтобы удвоить количество указателей (илиумножьте текущее число на 3/2, или как вам угодно), проверьте успешность перераспределения, обновите текущее число, назначенное новому количеству указателей, и продолжайте, пока не достигнете предела указателя снова, и повторите при необходимости ...)

0 голосов
/ 15 октября 2018
char **s=(char**)malloc(20*sizeof(char*)); // alloc

Это дает место для 20 указателей на char.Это не оставляет места для фактического хранения char s.

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

. Выполнение этого в вашем цикле просто приведет к связке указателей на одну и ту же базовую последовательность char s.Вам нужно использовать либо цикл, либо функцию типа strncpy, чтобы фактически скопировать char s.

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

Это должно быть явным признаком ошибки, так как естьнет malloc, соответствующий этому free.(Ваш единственный malloc соответствует free(s); ниже этого.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...