C строка проблема - PullRequest
       1

C строка проблема

0 голосов
/ 09 сентября 2010

Моя проблема очень проста, но я действительно не знаю, как манипулировать строками в C

Проблема в том, что у меня есть структура с именем person

struct person
{
  char name[25] // use char *name better?
}p;

У меня также естьфункция с именем p *addNewPerson(char *name)

p *addNewPerson(char *name)
{
  p *newPerson = (p *)malloc(sizeof(person));
  //here how can I assign the name to this new person?
  ...
  return newPerson;
}

Итак, в основной функции

void main()
{
   for(; ;)
  {
    char input[25];
    scanf("%s", input); // is this way possible?
    //shoud I do something with this "input", like input[strlen(input)-1] = '\0'
    //call addNewPerson()
    p *newPerson = addNewPerson(&input);
    //store this newPerson in some data structure
    ...
  }
}

Уточнение: вопрос в том, как я могу присвоить имя этому новомучеловек внутри p *addNewPerson(char *name)?

Ответы [ 7 ]

4 голосов
/ 09 сентября 2010
p *newPerson = (p *)malloc(sizeof(person));
//here how can I assign the name to this new person?

Вы должны сделать это:

strcpy(p->name,name);

Вы также должны изменить использование p на struct person, поскольку p не тип, это глобальный типstruct person.Измените код на:

struct person *addNewPerson(char *name)
{
   struct person *newPerson = malloc(sizeof *newPerson);

// Я должен что-то сделать с этим «вводом», например, input [strlen (input) -1] =

НетScanf не завершит строку за вас.

Имейте в виду, однако, что обработку строки в C должна выполняться очень и очень осторожно.например, когда вы делаете scanf("%s", input);, что произойдет, если вы введете имя длиной более 24 символов?

Может произойти все что угодно.scanf может переполнить ваш буфер, и вы получите неопределенное поведение.Вы должны сделать по крайней мере это:

  int ret = scanf("%24s",buffer);  //read max 24 chars, to make space for a final '\0'
  if(ret == EOF) { //end of input reached.
     break; 
  if(ret != 1) {
    // for whatever reason, the conversion failed. exit, or alert the user, or whatever
  }

Аналогично, внутри вашего addNewPerson в strcpy(p->name,name);, strcpy может с радостью записать за буфер, если name длиннее, чем может удержать p->name.В этом конкретном случае с вышеупомянутой модификацией для scanf длина всегда будет 24 или меньше, так что это безопасно.Но имейте это в виду в общем.

Вызов addNewPerson должен просто передать имя buffer напрямую, при использовании в качестве значения имя массива затухает до указателя на первый элементэтот массив;

 struct person *newPerson = addNewPerson(input);

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

2 голосов
/ 09 сентября 2010

В вашем коде есть фундаментальный недостаток, который еще никто не уловил, который стоит отметить. p не является типом, это объявление переменной типа struct person. Ваша addNewPerson() функция просто не будет работать вообще. Либо измените функцию addNewPersion() соответствующим образом:

struct person *addNewPerson(char *name)
{
    ...
}

или определите тип p:

typedef struct person { ... } p;

Затем используйте strcpy() (скорее, я бы предложил strncpy() вместо), как предлагали другие.

struct person *addNewPerson(char *name)
{
    struct person *newPerson = (struct person *)malloc(sizeof(struct person));
    //strcpy(newPerson->name, name);
    strncpy(newPerson->name, name, sizeof(newPerson->name)); //more safe
    return newPerson;
}
1 голос
/ 09 сентября 2010
  1. Вы можете назначить элемент name с помощью sprintf(p->name, "%s", name);, но вам следует опасаться переполнения буфера из 25 символов.Например, вы могли бы сделать snprintf(p->name, 25, "%s", name);

  2. Самое важное, что вы должны выучить при написании этой программы, это то, что все, что вы используете malloc (), должно быть свободно () 'd.В противном случае вы будете вызывать утечки памяти.В конце main () обязательно наберите free(newPerson);.Если вы измените элемент структуры на указатель, вам нужно будет разместить его malloc, а затем освободить при необходимости.

1 голос
/ 09 сентября 2010

Используйте strcpy, чтобы скопировать строку и сохранить ее в своей структуре:

strcpy(p->name, name);

Также не забудьте проверить длину строки, чтобы она соответствовала name без переполнения.

0 голосов
/ 09 сентября 2010

Вам не нужен strcpy, вам не нужен malloc, вам не нужен sizeof и т. Д. Если вы используете в своей структуре массив символов, например:

typedef struct {
char name[25];
} Person;

main() {
  Person person;
  char name[25];
  if( 1==scanf("%24s",name) )
    person=*(Person*)name;
  return 0;
}

или если вам нужно больше людей:

main() {
  Person person[2]={{"firstperson"}};
  char name[25];

  if( 1==scanf("%24s",name) )
    person[1]=*(Person*)name;

  puts( person[0].name );
  puts( person[1].name );

return 0;
}
0 голосов
/ 09 сентября 2010

Я скорее вызываю метод constructPerson.Это на самом деле конструктор в ООП жаргон

struct person
{
  char *name; //can hold string of different sizes
}p;

p *addNewPerson(char *name)
{
  p *newPerson = (p *)malloc(sizeof(person));
 p->name= (char *) malloc(sizeof(char)*(strlen(name)+1));//don't forget to claim space for the '/0' character at the end of the string
 strcpy(p->name,name);
  return newPerson;
}
0 голосов
/ 09 сентября 2010

Вы можете сделать это двумя способами.

Во-первых, как вы предлагаете, вы можете изменить член name человека из массива на указатель. Затем в addNewPerson вы просто сделаете:

p *newPerson = (p *)malloc(sizeof(person));
p->name = name;

РЕДАКТИРОВАТЬ: Как отмечено в комментариях, это по сути плохо, и вы должны копировать байты. Я слишком долго работаю в подсчете ссылок.

В противном случае вам нужно будет скопировать байты из переданного имени в ваш массив struct. Я бы использовал strlcpy как таковой:

strlcpy(p->name, name, sizeof(p->name));

если доступно, в противном случае используйте:

strncpy(p->name, name, sizeof(p->name));

Единственное отличие состоит в том, что вам придется завершать нулем p->name, если name был слишком длинным, чтобы поместиться в p->name.

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