同时在char数组中交换多个对象

时间:2015-12-01 04:01:45

标签: c++ arrays char c-strings

我正在尝试使用c-string(没有std:string允许这个字符串)创建程序,其中c-string的内容是格式化的名称:lastName,firstName middleName或者程序将处理的它是lastName,firstMiddleName。

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

我想知道是否有一些优雅的方法可以通过使用索引来查找逗号以便将c-string的两个部分分开,然后只是类似于str.substr(0,index)为了轻松交换两个。这有可能吗?我觉得我已经用尽了所有关于此事的帖子

非常感谢任何帮助

2 个答案:

答案 0 :(得分: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;
}

上述代码的输出是

  

firstname:Firstname Middlename

     

姓氏:姓氏

另外别忘了清理;)

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

答案 1 :(得分:0)

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

这里我提出了两个版本。

t266a()符合c ++和stream,但只使用c-string(没有std :: string)

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

我故意使用空格来将code-with-c-strings的各个部分与code-with-std :: strings对齐,但是你需要将它加载到一个功能强大的编辑器中以便并排显示它们。 / p>

//  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&)