#c #arrays #function #pointers #char
#c #массивы #функция #указатели #символ
Вопрос:
функция моей программы состоит в том, чтобы просто иметь массив символов с именем и фамилией и переключать его так, чтобы это было имя last name. (Том, Круз —> Круз, Том). Я только начал использовать указатели и не могу найти способ изменить порядок в массиве символов. Я пробовал циклы for и while, но я действительно не знаю, как решить эту проблему. Мне не обязательно нужен жесткий код. Даже предложение помогло бы мне двигаться в правильном направлении. Я не получаю никаких ошибок. Из-за требований я не могу изменить основную функцию вообще, и заголовок функции должен быть
char *LastFirstName(char *ptr).
Спасибо
#include <iostream>
using namespace std;
char *LastFirstName(char *name);
int main()
{
char name[41];
char *ptr;
// Force user to enter full name, if not entered, ask again
while (true)
{
name[0] = '';
cout << "Enter your full name: ";
cin.getline(name, 40);
if (name[0] == '')
cout << "Name not entered. Re-enter full name.n";
else
break;
}
cout << "Before calling function LastFirstName(), name is " << name
<<endl;
ptr = LastFirstName(name);
cout << "After calling function LastFirstName(), name is " << ptr << endl;
system("pause");
return 0;
}
// This is where I am havinbg trouble
char *LastFirstName(char *ptr) {
char *p;
p = ptr;
int len = strlen(ptr);
return ptr;
}
Комментарии:
1. Я думаю, вы на самом деле не хотите переключать его на место. Лучше использовать новый массив символов, а затем впоследствии вернуть указатель на новый массив. Итак, найдите фамилию, поместите ее в свой новый массив, затем имя и поместите его в новый массив. Затем верните указатель на новый массив.
Ответ №1:
Вы можете использовать эту функцию:
void LastFirstName(char* first_last_name)
{
char first_name[41] = {0};
char last_name[41] = {0};
// Dunno what is your separator ' ' or ','...
char* sep_index = strchr(first_last_name, ','); // This return the first index of ','.
*sep_index = '';
strcpy(first_name, first_last_name); // Lets copy first name.
strcpy(last_name, first_last_name strlen(first_last_name) 1); // Lets copy last name.
// Lets copy it in reverse order.
strcpy(first_last_name, last_name);
strcpy(first_last_name strlen(last_name) 1, first_name);
first_last_name[strlen(last_name)] = ',';
}
Обратите внимание, что нам не нужно возвращать, char*
потому что функция изменяет массив, который она получила в качестве аргумента, так что на самом деле name
массив теперь изменен в соответствии с запросом.
Комментарии:
1. Что, если я хочу сохранить свой заголовок как есть? Есть ли какой-либо способ сделать это вместо этого? «strcpy» выглядит очень полезным, хотя я изучу это и, возможно, смогу что-нибудь придумать.
2. Да, просто измените мою функцию с
void
наchar*
и верните тот же указатель, который вы получили в качестве аргумента.3. В настоящее время я получаю сообщение об ошибке. «strcpy» может быть небезопасным. Поэтому я использую strcpy_s вместо этого, и он говорит: «Ни один экземпляр перегруженной функции strcpy_s не соответствует списку аргументов.
4. Я избавился от ошибки CTR, но теперь я получаю «sep_index был нулевым ptr»
5. Обратите внимание, что
strcpy
это может быть небезопасно, если вы не знаете размер строки, из которой копируете в целевой массив. Потому что вы можете превысить размер, который вы выделили для него. Это не наш случай, мы можем с уверенностью сказать, что наши массивы находятся в безопасных диапазонах размеров.
Ответ №2:
-
ptr = LastFirstName(name);
на самом деле это ничего не делает. Я имею в виду, что после этого обаptr
иname
указывают на одну и ту же область в памяти… так что это довольно бессмысленно (понял? ‘pointless’ … k, больше этого делать не буду.) для этого (LastFirstName
работает с памятью, на которую указываетname
, что означает, что после завершения функцииname
будут сохранены результаты. -
Было бы проще запросить имя, а затем фамилию, а затем просто поменять местами адреса, на которые указывают указатели… но это было бы неинтересно, и мы бы ничему из этого не научились, не так ли? (Я просто говорю, что есть другой вариант. Не поймите меня неправильно)
Теперь давайте перейдем к кодированию. Поскольку возвращать указатель в этом случае не имеет смысла (если только вы не хотите иметь 2 массива, каждый в разном порядке), поэтому давайте изменим объявление функции на void LastFirstName(char *ptr)
. Теперь нам нужно знать, где заканчивается имя. Нам нужно найти первое вхождение пробела (или любого другого символа, которым вы хотите их разделить), что легко сделать с помощью strchr(char*, int)
функции.
После этого, поскольку имя и фамилия не обязательно должны быть одинаковой длины, мы не можем просто поменять местами их буквы, было бы удобно просто скопировать имя куда-нибудь (в другой массив), затем заменить имя на фамилию, скопировать имя сразу после этого и завершить на ''
.
Код будет выглядеть примерно так (не тестировался, используйте с осторожностью):
void LastFirstName(char *ptr)
{
char name[41], ptr2(ptr);
const size_t nameLen(strchr(ptr, ' ')); // Change the space for whatever you want. btw, I used constructor here.
strncpy(name, ptr, nameLen); // Copy the name from "ptr" to "name"
ptr = nameLen 1; // Move pointer to the first character of the last name
/* We could use some pre-made functions to avoid doing the for loop below
but that's not the point in learning, is it? */
for(size_t i(strlen(ptr) - nameLen - 1); i>0; --i) // I also used constructor here
{
*ptr2 = *ptr;
ptr2;
ptr;
}
*ptr2 = ' ' // Again, you can change it to whatever you want
ptr2; // it's better to do it that way - compiles into faster code
strncpy(ptr2, name, nameLen); // let's copy the name back into our array
ptr2 = nameLen; // Move the pointer to the end and append ''
*ptr2 = ''; /* We would have passed nameLen 1 previously (and now)
to get the null terminator copied within the strncpy, but it's better
that way - it helps you to understand what happens behind the
courtain. */
return; // unnecessary, but it's a good habit imho
}
/**
Since you pass a copy of pointer, and not a pointer itself, to a function,
you don't have to worry about getting it back to the position it was before.
*/
Как вы можете видеть, я также использовал strncpy(char*, char*, size_t)
функцию.
О, и size_t
это просто целое число без знака, используемое для выражения размера в памяти. На самом деле он не отличается от любого другого целого числа без знака. Это просто псевдоним.
И небольшой совет в конце: используйте массивы в стиле C ( char array[]
) везде, где только можете. Поскольку их размер известен во время компиляции, компилятор может оптимизировать его лучше. Не говоря уже о динамическом распределении (о котором, я полагаю, вы узнаете далее, это то, для чего мы используем указатели, в основном… осталось? Я имею в виду, верно?) просто медленнее.
Надеюсь, я помог.