Есть ли лучший способ напечатать строку с cout до N символов? - PullRequest
6 голосов
/ 15 февраля 2009

-edit- Я посылаю двоичный файл, а не строку. Мой тест использует HTML-страницы, поэтому в этом примере я использую только строку, но мой вопрос о двоичном, векторах и отладке с помощью ostream Я делаю это очищает некоторую путаницу.

У меня есть следующий код:

cout << string(&v[0]).substr(0, len);

Есть ли лучший способ напечатать строку v с указанием длины len ? Я думал сделать v [len] = 0, но я выбрасываю утверждение размером 1. Мой код:

vector<char> v;
v.reserve(1024*16); //required
v.resize(1); //so we can do &v[0]
recv(sockfd, &v[0], v.capacity(), 0);
while (l > 0)
{
    cout << string(&v[0]).substr(0, l);
    recv(sockfd, &v[0], v.capacity(), 0);
}
cout << "the size is " << v.size();

Ответы [ 4 ]

7 голосов
/ 15 февраля 2009

Вы можете использовать метод ostream :: write для объекта cout:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  vector<char> test;
  test.push_back('a');
  test.push_back('b');
  test.push_back('c');

  cout.write(&test[0], 3);
  cout << endl;
}

Выходы:

а

Поскольку ostream :: write возвращает ostream и содержит * this, вы даже можете сделать

cout.write(&test[0], 3) << endl;

но я не уверен, что на самом деле лучше (или яснее).

5 голосов
/ 15 февраля 2009
vector<char> v;
v.reserve(1024*16); //required
v.resize(1); //so we can do &v[0]
recv(sockfd, &v[0], v.capacity(), 0);

В этом коде есть ошибка. Вызов reserve только гарантирует, что вы можете push_back как минимум столько же элементов, пока ссылки и итераторы на вектор снова не будут признаны недействительными (через возможное перераспределение используемого буфера). Это не позволит вам писать в v [0..1024 * 16-1], как вы делаете с recv. Вы должны сделать

v.resize(1024*16); //required

чтобы фактически иметь столько доступных элементов и передавать v.size() вместо v.capacity().

Для вашей подстроки, я бы, наверное, сделал

std::string str(&v[0], n);
std::cout << str;

Где n находится в диапазоне от 0 до v.size (). Вы можете использовать std::min(n, v.size()), чтобы гарантировать, что если n может быть больше в вашем случае, и вам нужен верхний предел.

(на боковом узле я бы не использовал там переменную с именем "l" (ell), потому что она может очень сильно походить на "1" (одну), которая может запутать людей)

0 голосов
/ 15 февраля 2009

Почему вы устанавливаете размер 1?
Когда вы резервируете пространство, пространство становится доступным для роста вектора (без перераспределения). Но кто сказал, что безопасно использовать напрямую? Я видел (отладочные) реализации, которые добавляют буфер предупреждений сразу после того, как size () изменил эти биты, и он будет генерировать утверждение при следующей проверке. Вы должны читать / писать только с 0 -> size ().

NB. Это также позволит вам использовать v [len] = '\ 0';

vector<char> v(1024*16);

std::size_t  len = recv(sockfd, &v[0], v.size(), 0);
while (len > 0)
{
    v[len] = '\0';
    cout << &v[0];
    len = recv(sockfd, &v[0], v.size(), 0);
}

Обратите внимание, что это, вероятно, не лучший способ прочитать строку.
Я бы передавал информацию о длине по потоку, чтобы вы знали, когда нет больше информации для чтения, чем для чтения столько, сколько требуется.

0 голосов
/ 15 февраля 2009

См. Комментарии: Я исправлен. Я был миниинформирован. Тем не менее, я все еще думаю, что это чокнутый - полагаться на такие внутренние органы. Последний компилятор Microsoft, который я использовал, нарушал стандарты C99, и мне не было конца печали. Если они не могут получить возвращаемые значения прямо в vsnprinf () или new, Вы действительно хотите полагаться на подобные ошибки?

Вы делаете предположения относительно того, как реализован вектор. Вы предполагаете, что v [1] появляется сразу после v [0] в памяти.

Существует разница между char buf []; & buf [1] == & buf [0] + 1 и vector v; & v [1] == & v [0] + 1 . Массив char использует арифметику указателей. Вектор использует оператор []. То, как вектор хранит данные внутри, независимо от того, являются ли они смежными или нет, зависит от этого класса векторов.

Хотя ваш код все еще может работать, это все-таки вещь ПЛОХАЯ ! Это делает ваше программное обеспечение ломким, заставляя его ломаться странными и ожидаемыми способами, когда вы меньше всего этого ожидаете!

Это идеальная ситуация для временного массива char в локальном стеке. Размер маленький. У вас жестко задан максимальный размер.

Если бы размер не был постоянным, я бы по-прежнему использовал небольшой локальный буфер массива символов в стеке. Я бы просто добавил его в C ++ std :: string после каждой итерации. (Да, std :: strings может хранить двоичные значения, включая несколько нулевых символов.)

recv () возвращает количество прочитанных байтов. Вектор v не подхватывает это автоматически. Поэтому вам нужно сохранить и использовать это значение.

Я предлагаю:

#define BUFFER_SIZE  (1024*16)
#define FLAGS        0

int  received = 0;
int  total    = 0;
char buffer [ BUFFER_SIZE + 1 ];

memset( buffer, 0, BUFFER_SIZE + 1 );

received = recv( sockfd, buffer, BUFFER_SIZE, FLAGS );

if ( received > 0 )
{
  copy( buffer + total,
        buffer + total + received,
        ostream_iterator<char>(cout) );

  total += received;
}

while( (received > 0) && (total < BUFFER_SIZE) )
{
  received = recv( sockfd, buffer + total, BUFFER_SIZE - total, FLAGS );

  if ( received > 0 )
  {
    copy( buffer + total,
          buffer + total + received,
          ostream_iterator<char>(cout) );

    total += received;
  }
}

buffer [ total ] = '\0';
buffer [ BUFFER_SIZE ] = '\0';

cout << "The total size is " << total << endl;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...