【问题标题】:swap multiple objects in char array with one another at the same time同时交换 char 数组中的多个对象
【发布时间】:2016-03-04 21:38:00
【问题描述】:

我正在尝试使用 c 字符串(这个字符串不允许 std:string)制作程序,其中 c 字符串的内容是格式化的名称:lastName、firstName middleName 或程序将处理的名称它是姓氏,firstMiddleName。

我想要做的只是将格式切换为 firstMiddleName lastName。

我想知道是否有一些优雅的方法可以通过可能使用索引来查找逗号以分隔 c 字符串的两个部分,然后只是类似于 str.substr(0, index)为了轻松交换两者。这可能吗?我觉得我已经用尽了这件事的每一个线索

非常感谢任何帮助

【问题讨论】:

  • 并非如此。创建另一个字符串并将新字符串保存到该字符串,然后将其复制回来。
  • 使用交换来切换内联名称并不是一个优雅的解决方案。找到名称然后用它们构建一个新字符串会更优雅。请注意,您提到的substr 函数实际上构建了一个新字符串。
  • 那么你尝试过什么,优雅与否?如果您提供一些努力的证据,我可能会提供最微小的递归来帮助您。糟糕,我只是给了你一个提示。

标签: c++ arrays char c-strings


【解决方案1】:

我认为最好为有姓氏和名字的人创建struct。

typedef struct {
    char* firstname;
    char* lastname;
} person_t;

要通过一些分隔符分割字符串,你可以使用strtok这样的函数

char* last = strtok(str, ",");

其中str 是源字符串,, 是分隔符。

现在您需要创建person_t 的实例并复制值

person_t create_person(char* firstname, char* lastname) {
    person_t person;
    int length;

    length = strlen(firstname);
    person.firstname = malloc(sizeof(char) * (length + 1));
    person.firstname[length] = '\0';

    length = strlen(lastname);
    person.lastname = malloc(sizeof(char) * (length + 1));
    person.lastname[length] = '\0';

    strcpy(person.firstname, firstname);
    strcpy(person.lastname, lastname);

    return person;
}

现在您可以根据需要输出这些值。完整代码见下方

#include <stdio.h>
#include <string.h>

typedef struct {
    char* firstname;
    char* lastname;
} person_t;

person_t create_person(char* firstname, char* lastname) {
    person_t person;
    int length;

    length = strlen(firstname);
    person.firstname = malloc(sizeof(char) * (length + 1));
    person.firstname[length] = '\0';

    length = strlen(lastname);
    person.lastname = malloc(sizeof(char) * (length + 1));
    person.lastname[length] = '\0';

    strcpy(person.firstname, firstname);
    strcpy(person.lastname, lastname);

    return person;
}

int main(void) {
    char str[] = "Surname, Firstname Middlename";
    char* last = strtok(str, ",");
    char* first = strtok(NULL, ",") + 1;
    person_t person = create_person(first, last);
    printf("firstname: %s\nlastname: %s\n", person.firstname, person.lastname);
    return 0;
}

上面代码的输出是

名字:名字中间名

姓氏:姓氏

别忘了清理 ;)

void remove_person(person_t person) {
    free(person.firstname);
    free(person.lastname);
}

【讨论】:

  • malloc(1 + sizeof(char) * strlen(firstname)) ;-)
【解决方案2】:

您已将此问题标记为 C++。

这里我介绍两个版本。

t266a() 符合 c++ 和流,但仅使用 c-string(无 std::string)

t266b() 符合 c++ 和流,并使用 std::string(无 c-string)

我有意使用空格将代码与 c 字符串的部分对齐到代码与 std::strings,但您需要将其加载到功能强大的编辑器中以并排显示它们。

//  1 & 2 of 3 c++ includes
#include <iostream>    // cout, cin, istream
#include <algorithm>   // std::fill

// removed: include <cstring> - not needed

// forward

// c++, but limited to c-string, no std::string
int t266a(std::istream& ss);

// c++, using std::string
int t266b(std::istream& ss);

const int MAX_BUFF = (1024*1024); // for c-string, how big should this be?
// default stack size ubuntu 15.10 (64) is 8MB, so plenty of room


// ///////////////////////////////////////////////////////////////////////
size_t getLine (std::istream& ss, char* buff, size_t& buffLen)
{
   size_t karCount  = 0;
   for (size_t i=0; i<MAX_BUFF; ++i) // limit read to MAX_BUFF chars
   {
      char kar  = 0;

      ss.read(&kar, 1);  // binary stream read, 1 char at a time

      if (ss.eof()) break;

      if(ss.bad()) { // either fail or bad
         std::cerr << "stream bad x " << std::endl;
         break;
      }

      buff[i]   = kar;  // capture kar to buff
      karCount += 1;    // count kar's

      if ('\n' == buff[i])  // end-of-line within stream
      {
         buffLen = i;
         buff[i] = 0; // null-terminate in buff
         break;  // line complete
      }
   }
   return(karCount);
}

// ///////////////////////////////////////////////////////////////////////
size_t buffFind(const char* buff, size_t buffLen, const char kar)
{
   size_t commaAt  =  buffLen + 1; // not found

   for (size_t i=0; i<buffLen; ++i)
   {
      if(kar == buff[i])
      {
         commaAt = i;   // found comma
         break;
      }
   }

   return (commaAt);
}

// ///////////////////////////////////////////////////////////////////////
// c++, but limited to c-string, no std::string
int t266a(std::istream& ss)
{
   std::cout << "t266a() C++, but limited to c-string, no std::string" << std::endl;

   std::cout << "MAX_BUFF: " << MAX_BUFF << std::endl;

   char buff[MAX_BUFF];

   size_t buffCount = 0;
   size_t buffLen   = 0;

   do
   {
      // buff[0] = '\0';                      // a c-string terminates with the 1st 0 ... need to clear all?
      // (void)::memset(buff, 0, MAX_BUFF);   // from   <cstring> lib.  clear all  c-style
      std::fill(buff, buff+MAX_BUFF, '\0');   // from <algorithm> lib.  clear all  c++style

      (void)getLine(ss, buff, buffLen);  // local function

      if(ss.eof()) break;

      if(ss.bad()) { // either fail or bad
         std::cerr << " " << ss.good()
                   << " " << ss.eof()
                   << " " << ss.fail()
                   << " " << ss.bad()
                   << std::endl;
         break;
      }

      buffCount += 1;

      if (ss.eof()) break;

      //std::cout << "  Input: " << buffCount << "  (" << buffLen << ")  '" << buff << "'" << std::endl;

      // find comma
      size_t commaAt  =  buffFind(buff, buffLen, ',');

      if(commaAt > buffLen)
      {
         std::cerr << " Err: invalid input: no comma on line "<< std::endl;
         break;
      }

      if(commaAt < 1)
      {
         std::cerr << " Err: invalid input: comma at beginning of line "<< std::endl;
         break;
      }

      buff[commaAt] = 0;              // take advantage of c-string
      std::cout << " Output:          "
                << &buff[commaAt+1]  // Firstname Middlename [(where comma was) .. (end of buff)]
                << "  "
                << &buff[0]          // Surname [0..(where comma was)]
                << "  (bufLen: " << buffLen << ")"  << std::endl;

      if (ss.eof()) { break;}

   }while (true);

   return(0);

} // int t266a(std::istream&)


// ///////////////////////////////////////////////////////////////////////
// 3 of 3 c++ includes
#include <sstream>

// ///////////////////////////////////////////////////////////////////////
// ///////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[] )
{
   std::cout << "argc: " << argc << std::endl;
   for (int i=0; i<argc; i+=1) std::cout << argv[i] << " ";
   std::cout << std::endl;

   setlocale(LC_ALL, "");

   std::stringstream ssTest;
   {
      for (int i=1; i<=8; ++i) // 8 entries
      {
         ssTest  << "Surname" << i << ", Firstname" << i << " Middlename" << i << "\n";
      }
      // add test cases here
      // trailing spaces --------------------------------vv
      // ssTest <<  " SurnameX,   FirstnameX  MiddlenameX  \n" ;
      //             ^--leading spaces
      // ssTest <<  "SnameY, FnameY MnameY\n" ;
      // different size names
   }

   int retVal = 0;
   {
      std::stringstream ss (ssTest.str()); // load ss

      std::cout << "\nistream (input): \n" << ss.str() << std::endl;

      retVal += t266a(ss); // run c++ using c-strings
   }

   {
      std::stringstream ss(ssTest.str()); // load ss

      std::cout << "\n\nistream (input): \n" << ss.str() << std::endl;

      retVal += t266b(ss); // run c++ using std::string
   }

   std::cout << "\n\nFINI " << std::endl;
   return(retVal);
}


// ///////////////////////////////////////////////////////////////////////
// c++, but using std::string (no c-strings)
int t266b(std::istream& ss)
{
   std::cout << "t266b() C++, using std::string (no c-strings)" << std::endl;



   std::string buff; // buff grows as needed

   size_t buffCount = 0;     // line count
   //size_t buffLen = 0;     // now buff.size()

   do
   {


      buff.clear();

      (void)std::getline(ss, buff); // uses default delim ('\n')

      if(ss.eof()) break;

      if(ss.bad()) { // bad or fail bit set
         std::cerr << " " << ss.good()
                   << " " << ss.eof()
                   << " " << ss.fail()
                   << " " << ss.bad()
                   << std::endl;
         break;
      }

      buffCount += 1;

      if (ss.eof()) break;

      //std::cout << "  Input: " << buffCount << "  (" << buff.size() << ")  '" << buff << "'" << std::endl;

      // find comma
      size_t commaAt = buff.find(',');

      if(commaAt == std::string::npos)
      {
         std::cerr << " Err: invalid input: no comma  " << std::endl;
         break;
      }

      if(commaAt < 1)
      {
         std::cerr << " Err: invalid input: comma at beginning of line "<< std::endl;
         break;
      }


      std::cout << " Output:          "
                << buff.substr(commaAt+1)  // Firstname Middlename [(where comma was) .. (end of buff)]
                << "  "
                << buff.substr(0, commaAt) // Surname [0..(where comma was)]
                << "  (buff.size(): " << buff.size() << ")"  << std::endl;

      if (ss.eof()) { break;}

   }while (true);

   return(0);

} // int t266b(std::istream&)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多