2010-09-08 3 views
0

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

Проблема заключается в том: У меня есть структура называется человек

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)?

+1

В чем проблема? Помимо отсутствующей точки с запятой после имени [25]? – EboMike

+0

http://www.learn-programming.za.net/programming_c_learn07.html –

+0

Использовать «int main()»; Стандарт гарантирован. Ваш 'struct person' работает так, как есть. Если вы изменили на 'char * name;', вам понадобится 'malloc()' memory для него, а затем запомните 'free()' it. Ваш способ чтения имен в произведениях, пока 'scanf()' читает только 24 символа (вам нужен один для нулевого ограничителя строк), но 'scanf()' не очень безопасная функция для использования. Вы можете узнать более безопасные способы ввода данных позже. –

ответ

4
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 не тип, это глобальный veriable типа struct person. Изменение кода на:

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

// Шоуда я сделать что-то с этим "вход", как вход [STRLEN (вход) -1] =

Нет, зсапЕ будет NUL прекратить строка для вас.

Помните, что обработка строк в 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);, зЬгср может счастливо писать мимо буфера, если name больше, чем то, что p->name может держать. В этом конкретном случае с указанной выше модификацией scanf длина всегда будет равна 24 или меньше, чтобы она была безопасной. Но будьте очень осведомлены об этом в целом.

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

struct person *newPerson = addNewPerson(input); 

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

+2

Чтобы добавить к этому ответу: scanf может вызвать некоторые проблемы безопасности с переполнением буфера. Проверьте http://www.cprogramming.com/tutorial/secure.html и попробуйте использовать fgets w/stdin. –

+0

Параметры scanf принимают тип ширины, который остановит входной массив, который будет перезаписан двумя большими вводами. «% 24s» –

+0

Непроверенные вызовы 'strcpy()' также могут вызывать переполнение буфера. –

1

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

strcpy(p->name, name); 

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

1
  1. Вы можете назначить name элемент по sprintf(p->name, "%s", name);, но вы должны быть осторожны переполнения буфера 25 символов. Например, вы могли бы сделать snprintf(p->name, 25, "%s", name);

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

+0

Использование 'sprintf' здесь является излишним; мы имеем дело с строковой копией, а не с форматированием строки. Хорошо сделано, указывая на 'malloc' /' free' вещь. – You

0

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

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

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

EDIT: Как было отмечено в комментариях, это по своей сути плохо, и вы должны скопировать байты. Я слишком долго работал в ссылке, подсчитывая землю.

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

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

если таковые имеются, в противном случае используйте:

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

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

+0

Первое принципиально ошибочное: указание на буфер, переданный параметром функции, нет. – Codism

0

Я скорее называю метод 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; 
} 
+1

Переполнение буфера: 'strlen (name) + 1' или' strdup (name) '. –

+0

правый !, tks для указание. Я исправил сообщение –

2

Существует фундаментальный изъян в вашем коде, который никто не не подобран на еще что стоит отметить. 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

Вы не нуждаетесь в STRCPY, вам не нужен таНос, вам не нужен никакие 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

Это довольно смелое заявление. Так не безопасно играть с указателями. –

+0

Он будет работать во всех средах ANSI C; скажите мне одну нерабочую систему/компилятор, пожалуйста, – user411313

+0

Извините, плохой выбор слов с тех пор, как я последний раз редактировал свой комментарий. Да, это сработает, но я бы счел этот подход более взломанным, чем правильный способ справиться с этим вопросом. Конечно, если «Лицо» было более сложным, это потребовало бы ухищрений, но это все равно взлома. –

Смежные вопросы