Как перевернуть массив символов с помощью указателей в C

#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:

  1. ptr = LastFirstName(name); на самом деле это ничего не делает. Я имею в виду, что после этого оба ptr и name указывают на одну и ту же область в памяти… так что это довольно бессмысленно (понял? ‘pointless’ … k, больше этого делать не буду.) для этого ( LastFirstName работает с памятью, на которую указывает name , что означает, что после завершения функции name будут сохранены результаты.

  2. Было бы проще запросить имя, а затем фамилию, а затем просто поменять местами адреса, на которые указывают указатели… но это было бы неинтересно, и мы бы ничему из этого не научились, не так ли? (Я просто говорю, что есть другой вариант. Не поймите меня неправильно)

Теперь давайте перейдем к кодированию. Поскольку возвращать указатель в этом случае не имеет смысла (если только вы не хотите иметь 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[] ) везде, где только можете. Поскольку их размер известен во время компиляции, компилятор может оптимизировать его лучше. Не говоря уже о динамическом распределении (о котором, я полагаю, вы узнаете далее, это то, для чего мы используем указатели, в основном… осталось? Я имею в виду, верно?) просто медленнее.

Надеюсь, я помог.