2009-02-15 2 views
6

-edit- Я отправляю двоичный код, а не строку. Мой тест использует html-страницы, поэтому в этом примере я использую только строку, но мой вопрос касается двоичных, векторов и отладки с помощью ostream. Я делаю это смущение.Есть ли лучший способ напечатать строку cout до N символов?

Я следующий код:

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(); 
+0

Этот код не работает. Ужасно. Использование вектора для выделения массива (что в действительности происходит там) не только опасно (векторы MEANT перераспределяют свои внутренние массивы!), Но также бессмысленно. –

+0

По крайней мере, используйте v.resize (1024 * 16), если вы * должны * использовать вектор, но, как упоминалось dionadar, делать это таким образом не является хорошей идеей и в принципе не защищает вас от чего-либо в любом случае и может привести к некоторые интересные ночи отлаживают этот код. –

+0

что не так с его использованием вектора? если размер динамический, я не вижу ничего плохого с ним –

ответ

7

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

#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; 
} 

Выходы:

ABC

С ostream :: записи возвращает ostream &, содержащий * этот, вы можете сделать даже

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

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

5
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; 

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

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

+0

из того, что я читал, вы можете записать в 0-1024 * 16-1 элементов, и он гарантированно будет непрерывным, однако элементы от размера к емкости не будут построены/инициализированы. – 2009-02-15 12:58:11

+0

это неправильно, потому что в векторе не так много элементов. вы можете только писать/читать от до v [0..v.size() - 1], конечно. –

+0

btw, если вам нужен буфер с постоянным размером, лучше использовать boost :: array v; затем передайте v.data() и v.size(). или массив в стеке - хотя необработанных массивов следует избегать ... u знаете, опасность за углом –

-2

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

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

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

Пока ваш код все еще может работать, это все равно BAD вещь! Это делает ваше программное обеспечение хрупким, заставляя его ломаться странными и ожидаемыми способами, когда вы меньше всего этого ожидаете!

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

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

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; 
+0

хорошо. фактически непрерывный вектор является одной из его ключевых особенностей. вам гарантировано, что & v [1] == & v [0] + 1 истинно, если вектор содержит не менее 2 элементов. –

+0

это было не так в C++ 98. но он был исправлен в C++ 03. прочитайте http://herbsutter.wordpress.com/2008/04/07/cringe-not-vectors-are-guaranteed-to-be-contiguous/ –

+0

Я стою исправлен. Обновлено исходное сообщение. Но я все еще думаю, что орехи полагаются на такие внутренние структуры. Последний компилятор microsoft, который я использовал, нарушал стандарты C99, не вызывающие у меня конца горя. Вы действительно хотите полагаться на такие ошибки? Особенно, когда нет необходимости? –

0

Почему вы настройка размера 1?
Когда вы зарезервируете пространство, пространство будет доступно для вектора, в который будет расти (без перераспределения). Но кто сказал, что безопасно использовать напрямую? Я видел (debug) реализации, которые добавляют буфер предупреждения сразу после того, как 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

Если я использую do v.clear(); v.push_back (данные) кучу раз. Мне нужно будет снова изменить его емкость? который построил бы все мои символы, а в случае с символами нет ctor, но сначала он заполнил Data? thats раздражает, особенно если я пишу/отправляю много 128 байт и нуждаюсь в buf не менее 16k. Есть ли способ ... – 2009-02-16 07:52:36

+0

Есть ли способ изменить размер без инициализации данных для fillValue? если бы не этот debug impl не раздражал меня в этом prj, и он был бы debug imple vs, избегая потенциально больших накладных расходов с изменением размера. также, ostream.write (ptr, len); решает мой вопрос. – 2009-02-16 07:55:58

Смежные вопросы