添加到char数组不起作用

时间:2011-11-05 20:56:35

标签: c++ c libcurl

我正在尝试逐行读取文本文件,并将每行添加到char数组中。但是根本没有添加这些行。

//This is the default char array that comes with the cURL code.
char *text[]={
  "one\n",
  "two\n",
  "three\n",
  " Hello, this is CURL email SMTP\n",
  NULL
};

/*Now we're going to replace that char array, with an array that holds the contents of a textfile. 
  We'll read a textfile out line by line, and add each line to the char array. 
*/
void makemailmessage()
{
    text[0] = '\0'; //Clear text
    text[0] = "testy\n"; //First line in new char array

    //Read the text file, add each line to the char array.
    string line;
    ifstream myfile ("C:\\Users\\admin\\Downloads\\bbb.txt");
    int counter;
    counter = 1;
    if (myfile.is_open())
    {
        while ( myfile.good() )
        {
          getline (myfile,line);

            //Convert the string variable "line" to a char (a)
            char *a=new char[line.size()+1];
            a[line.size()]=0;
            memcpy(a,line.c_str(),line.size());

            //Add \n to the end of "a" (new char will be "str")
            char str[80];
            strcpy (str,a);
            strcat (str,"\n");

            //Add "str" to the char array "text"
            text[counter] = str;
            text[counter+1] = "test\n"; //Also added this for testing purposes

            write_data("C:\\Users\\admin\\Downloads\\checkit.txt", str); //Also for testing purposes

        //Increase counter by 2 because we added two new items to the char array "text"
        counter++;
        counter++;
        }
    myfile.close();

    text[counter-1] = "testy2\n"; //Ad another text line
    text[counter] = NULL; //End char array
}

每个str都正确写入checkit.txt但由于某种原因它没有添加到char数组中,因为我最终得到的char数组如下所示:

testy

test

test

testy2

我做错了什么?

UPDATE2: 我尝试创建一个char数组的原因是因为我使用的cURL函数需要一个char数组来形成电子邮件正文。这是cURL代码的重要部分。

static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
{
  struct WriteThis *pooh = (struct WriteThis *)userp;
  const char *data;

  if(size*nmemb < 1)
    return 0;

  data = text[pooh->counter]; //This part is using the char array.

  if(data) {
    size_t len = strlen(data);
    memcpy(ptr, data, len);
    pooh->counter++;
    return len;
  }
  return 0;
}

Here's完整代码

3 个答案:

答案 0 :(得分:2)

  

我正在尝试逐行读取文本文件,并将每行添加到a   char数组。

由于这是C ++,为什么不使用std::vector<string>并使用std::string version of getline

std::string类将负责保存任意长度的字符串所需的内存,std::vector类将担心保存“数组”所需的内存,可以这么说,字符串。

编辑:实际上再次查看您的代码,您确实使用std::string,然后分配内存以将其存储为char s,和然后存储指向某些固定大小的数组test中的字符串的指针。如上所述,为什么要解决所有麻烦,您可以使用std::vector<string>来保存所有std::string个对象?心灵=难以置信。

EDIT2:您是否也可以使用cURLpp作为cURL的C ++包装器?我没有使用过,所以我不能评论它的有效性。

答案 1 :(得分:2)

好的,在聊了一下之后,这里有一个修复:

C ++版

此处的完整代码文件:https://gist.github.com/1342118#file_test.cpp

将相关代码替换为:

#include <vector>
#include <fstream>

// ...

std::vector<std::string> text;

static int read_text(char* fname)
{
    //Read the text file, add each line to the char array.
    std::ifstream myfile (fname);

    std::string line;
    while (std::getline(myfile, line))
        text.push_back(line + '\n');

    return 0;
}

static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
{
    /* This was already in. */
  struct WriteThis *pooh = (struct WriteThis *)userp;

  if(size*nmemb < 1)
    return 0;

  if (pooh->counter < text.size())
  {
      const std::string& data = text[pooh->counter];

      memcpy(ptr, data.data(), data.length());
      pooh->counter++; /* advance pointer */
      return data.length();
  }
  return 0;                         /* no more data left to deliver */
}

纯C版

此处的完整代码文件:https://gist.github.com/1342118#file_test.c

替换

//This is the default char array that comes with the cURL code.
char *text[]={
  "one\n",
  "two\n",
  "three\n",
  " Hello, this is CURL email SMTP\n",
  NULL
};

使用

char **text = 0;

static int read_text(char* fname)
{
    unsigned capacity = 10;
    int linecount = 0;

    // free_text(); see below
    text = realloc(text, capacity*sizeof(*text));

    FILE* file = fopen(fname, "r");
    if (!file)
        { perror("Opening file"); return 1; }

    char buf[2048];
    char* line = 0;

    while (line = fgets(buf, sizeof(buf), file))
    {
        if (linecount>=capacity)
        {
            capacity *= 2;
            text = realloc(text, capacity*sizeof(*text));
        }
        text[linecount++] = strdup(line);
    } 

    fclose(file);

    return 0;
}

将其与main函数挂钩,例如像这样

if (argc<2)
{
    printf("Usage: %s <email.eml>\n", argv[0]);
    exit(255);
} else
{
    printf("Reading email body from %s\n", argv[1]);
    if (0 != read_text(argv[1]))
        exit(254);
}

或者,如果您愿意,只需致电read_text("C:\\Users\\admin\\Downloads\\bbb.txt"):)

要真正做到最好,不要忘记在完成后回收记忆 - 正确:

#include "curl/curl.h" 

#include <stdio.h> 
#include <stdlib.h> 

#include <unistd.h> 
#include <memory.h>
#include <string.h>
#define GetCurrentDir getcwd 

#define USERNAME "obscured@gmail.com"
#define PASSWORD "obscured"
#define SMTPSERVER "smtp.gmail.com"
#define SMTPPORT ":587"
#define RECIPIENT "<obscured@gmail.com>"
#define MAILFROM "<obscured@gmail.com>"

#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000

/* Note that you should include the actual meta data headers here as well if
   you want the mail to have a Subject, another From:, show a To: or whatever
   you think your mail should feature! */
char **text = 0;

void free_text()
{
    if (text)
    {
        char** it;
        for (it = text; *it; ++it)
            free(*it);
        free(text);
        text = 0;
    }
}

static int read_text(char* fname)
{
    unsigned capacity = 10;
    int linecount = 0;

    free_text();
    text = realloc(text, capacity*sizeof(*text));

    FILE* file = fopen(fname, "r");
    if (!file)
        { perror("Opening file"); return 1; }

    char buf[2048];
    char* line = 0;

    while (line = fgets(buf, sizeof(buf), file))
    {
        if (linecount>=capacity)
        {
            capacity *= 2;
            text = realloc(text, capacity*sizeof(*text));
        }
        text[linecount++] = strdup(line);
    } 

    if (linecount>=capacity)
        text = realloc(text, (++capacity)*sizeof(*text));

    text[linecount] = 0; // terminate

    fclose(file);

    return 0;
}

struct WriteThis {
  int counter;
};

static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
{
    /* This was already in. */
  struct WriteThis *pooh = (struct WriteThis *)userp;
  const char *data;

  if(size*nmemb < 1)
    return 0;

  data = text[pooh->counter];

  if(data) {
    size_t len = strlen(data);
    memcpy(ptr, data, len);
    pooh->counter++; /* advance pointer */
    return len;
  }
  return 0;                         /* no more data left to deliver */
}

static struct timeval tvnow(void)
{
  /*
  ** time() returns the value of time in seconds since the Epoch.
  */
  struct timeval now;
  now.tv_sec = (long)time(NULL);
  now.tv_usec = 0;
  return now;
}

static long tvdiff(struct timeval newer, struct timeval older)
{
  return (newer.tv_sec-older.tv_sec)*1000+
    (newer.tv_usec-older.tv_usec)/1000;
}

int main(int argc, char** argv)
{
    if (argc<2)
    {
        printf("Usage: %s <email.eml>\n", argv[0]);
        exit(255);
    } else
    {
        printf("Reading email body from %s\n", argv[1]);
        if (0 != read_text(argv[1]))
            exit(254);
    }

   CURL *curl;
   CURLM *mcurl;
   int still_running = 1;
   struct timeval mp_start;
   char mp_timedout = 0;
   struct WriteThis pooh;
   struct curl_slist* rcpt_list = NULL;

   pooh.counter = 0;

   curl_global_init(CURL_GLOBAL_DEFAULT);

   curl = curl_easy_init();
   if(!curl)
     return 1;

   mcurl = curl_multi_init();
   if(!mcurl)
     return 2;

   rcpt_list = curl_slist_append(rcpt_list, RECIPIENT);
   /* more addresses can be added here
      rcpt_list = curl_slist_append(rcpt_list, "<others@example.com>");
   */

   curl_easy_setopt(curl, CURLOPT_URL, "smtp://" SMTPSERVER SMTPPORT);
   curl_easy_setopt(curl, CURLOPT_USERNAME, USERNAME);
   curl_easy_setopt(curl, CURLOPT_PASSWORD, PASSWORD);
   curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
   curl_easy_setopt(curl, CURLOPT_MAIL_FROM, MAILFROM);
   curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt_list);
   curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
   curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER,0);
   curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
   curl_easy_setopt(curl, CURLOPT_READDATA, &pooh);
   curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
   curl_easy_setopt(curl, CURLOPT_SSLVERSION, 0);
   curl_easy_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0);
   curl_multi_add_handle(mcurl, curl);

   mp_timedout = 0;
   mp_start = tvnow();

  /* we start some action by calling perform right away */
  curl_multi_perform(mcurl, &still_running);

  while(still_running) {
    struct timeval timeout;
    int rc; /* select() return code */

    fd_set fdread;
    fd_set fdwrite;
    fd_set fdexcep;
    int maxfd = -1;

    long curl_timeo = -1;

    FD_ZERO(&fdread);
    FD_ZERO(&fdwrite);
    FD_ZERO(&fdexcep);

    /* set a suitable timeout to play around with */
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;

    curl_multi_timeout(mcurl, &curl_timeo);
    if(curl_timeo >= 0) {
      timeout.tv_sec = curl_timeo / 1000;
      if(timeout.tv_sec > 1)
        timeout.tv_sec = 1;
      else
        timeout.tv_usec = (curl_timeo % 1000) * 1000;
    }

    /* get file descriptors from the transfers */
    curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);

    /* In a real-world program you OF COURSE check the return code of the
       function calls.  On success, the value of maxfd is guaranteed to be
       greater or equal than -1.  We call select(maxfd + 1, ...), specially in
       case of (maxfd == -1), we call select(0, ...), which is basically equal
       to sleep. */

    //rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);

    if (tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) {
      fprintf(stderr, "ABORTING TEST, since it seems "
              "that it would have run forever.\n");
      break;
    }

    switch(rc) {
    case -1:
      /* select error */
      break;
    case 0: /* timeout */
    default: /* action */
      curl_multi_perform(mcurl, &still_running);
      break;
    }
  }

  curl_slist_free_all(rcpt_list);
  curl_multi_remove_handle(mcurl, curl);
  curl_multi_cleanup(mcurl);
  curl_easy_cleanup(curl);
  curl_global_cleanup();
  free_text();
  return 0;
}

答案 2 :(得分:1)

What am I doing wrong?

首先,这个:

    char str[80];
    strcpy (str,a);
    strcat (str,"\n");

    //Add "str" to the char array "text"
    text[counter] = str;

str在堆栈上分配,具有块范围。然后在具有更大范围的数组中输入该指针。这通常是灾难的一个方法 - 一个相当令人印象深刻的分段错误或平台上的等价物。

在这种情况下,由于它在循环中的使用,你的程序会崩溃,或者 - 如果星星有正确的对齐 - 你最终会得到阵列中指向同一范围外的所有指针字符串,即上次读取的字符串。

为什么当你已经在堆中动态分配a时,你甚至会遇到麻烦?

顺便说一句,将char[]数组(以及相关的标准C库函数)与C ++字符串混合起来并不是一个好主意。甚至不是一个可接受的人。好吧,这是糟糕的想法。坚持使用C ++字符串......