Копирование строки в C

Я смущен этим кодом: (http://www.joelonsoftware.com/articles/CollegeAdvice.html)

while (*s++ = *t++);

Каков порядок выполнения? *s = *t сначала сделан, и затем каждый из них увеличен? Или наоборот?

Спасибо.

Править: И что, если это было:

while(*(s++) = *(t++));

и

while(++*s = ++*t);

7
задан Lazer 7 March 2010 в 19:16
поделиться

7 ответов

while (*s++ = *t++);

Из таблицы старшинства ясно видно, что ++ имеет более высокий приоритет, чем *. Но ++ используется здесь как оператор пост-инкремента, поэтому инкремент происходит после выражения присваивания. Поэтому *s = *t происходит первым, затем s и t инкрементируются.

EDIT:

while(*(s++) = *(t++));

То же самое, что и выше. Вы делаете это более явным с помощью круглых скобок. Но помните, что ++ - это все еще инкремент после.

while(++*s = ++*t);

Здесь только один оператор рядом с s. Поэтому сначала применяется *, а затем ++, что приводит к ошибке lvalue required.

while(*++s = *++t);

Снова просто оператор рядом с s,t. Поэтому сначала происходит инкрементация, а затем копирование. Поэтому мы фактически пропускаем копирование первого символа из t в s.

14
ответ дан 6 December 2019 в 08:42
поделиться

EDIT ::

@chrisgoyal

Порядок выполнения - неоднозначный термин. Здесь есть две разные вещи. Синтаксический порядок и семантика выражения.

Синтаксически сначала применяется оператор ++. Если сначала применяется * s, то следующее эквивалентно тому, что сказал @Hogan:

(*s)++ = (*t)++

Что очень отличается от образца Джоэла.

Семантика оператора ++ такова, что он выполняется после выражения.

Надеюсь, это проясняет, что я мясо.


Фактически, сначала применяются s ++ и t ++ . Не забывайте, что оператор после исправления выполняется после выражения. Обычно для обоих применяется оператор ++ , затем выполняется * s = * t .

1
ответ дан 6 December 2019 в 08:42
поделиться

Приращение - это пост-приращение. Публикация не только потому, что она идет после увеличения переменной, но и потому, что она идет после оценки выражения. Таким образом, порядок выполнения

*s = *t

, затем s ++ и t ++

2
ответ дан 6 December 2019 в 08:42
поделиться

Вы правы. Сначала выполняется * s = * t, а затем они увеличиваются.

4
ответ дан 6 December 2019 в 08:42
поделиться

В операции пост-инкрементная переменная используется сначала, а затем после ее изменения.

0
ответ дан 6 December 2019 в 08:42
поделиться

Код: (в то время как * s ++ = * t ++); примерно эквивалентен:

while (*s = *t) {
    ++s;
    ++t;
}

Второй точно такой же - лишние скобки ничего не меняют (в данном случае). Чтобы парены могли что-либо делать, они должны быть такими: while ((* s) ++ = (* t) ++); . Это будет примерно то же, что и ваш третий пример (описанный в абзаце ниже).

Последний пример: while (++ * s = ++ * t); совершенно другой. Поскольку разыменование ( * ) ближе к операнду, это разыменовывает операнд и увеличивает результат разыменования, что означает, что оно увеличивает то, что указатель указывает на AT, вместо увеличения самого указателя. В результате это будет копировать первый символ, затем увеличивать этот символ, затем проверять, был ли этот символ отличным от нуля, и продолжать то же самое, пока оно не станет нулевым. В результате и источник, и место назначения станут пустыми строками (поскольку первым символом обоих теперь будет ноль, который используется для завершения строк).

0
ответ дан 6 December 2019 в 08:42
поделиться

Ник прав, но я хотел немного лучше объяснить в тексте этого вопроса именно почему .

Проблема не в закрытии; это for-loop. Цикл создает только одну переменную «i» для всего цикла. Он не создает новую переменную «i» для каждой итерации. Примечание: Это, как сообщается, изменилось для C # 5.

Это означает, что, когда ваш анонимный делегат захватывает или закрывает эту переменную «i», он закрывает одну переменную, совместно используемую всеми кнопками. К тому времени, когда вы действительно получите, чтобы нажать на любую из этих кнопок, цикл уже закончил приращение этой переменной до 7.

Единственное, что я могу сделать иначе, чем код Ника, это использовать последовательность для внутренней переменной и строить все эти последовательности спереди, а не во время нажатия кнопки, как это:

for (int i = 0; i < 7; i++)
{
    var message = string.Format("I am button number {0}.", i);

    Button newButton = new Button();
    newButton.Text = "Click me!";
    newButton.Click += delegate(Object sender, EventArgs e)
    {
        MessageBox.Show(message);
    };
    this.Controls.Add(newButton);
}

Это просто торгует немного памяти (держась за более крупные последовательности вместо целых чисел) для немного cpu времени позже на... это зависит от вашего приложения, что имеет большее значение.

Другой вариант состоит в том, чтобы вообще не кодировать цикл вручную:

this.Controls.AddRange(Enumerable.Range(0,7).Select(i => 
{ 
    var b = new Button() {Text = "Click me!", Top = i * 20};
    b.Click += (s,e) => MessageBox.Show(string.Format("I am button number {0}.", i));
    return b;
}).ToArray());

Мне нравится этот последний вариант не столько потому, что он удаляет цикл, сколько потому, что он начинает думать о построении этого элемента управления из источника данных.

-121--2110178-

Существует несколько стратегий масштабирования при использовании ServiceMix/Camel/ActiveMQ. Поскольку каждая часть программного обеспечения предлагает так много вариантов, вы можете выбрать различные пути в зависимости от того, какую часть приложения необходимо масштабировать. Ниже приведен список нескольких стратегий высокого уровня:

  • Увеличение числа входящих экземпляров Jetty - это требует запуска большего количества экземпляров веб-сервера и либо распределения нагрузки между несколькими экземплярами, либо предоставления нескольких URL-адресов и отправки всех запросов в одну входящую очередь в ActiveMQ.

  • Увеличьте число экземпляров ActiveMQ. Запуская дополнительные экземпляры ActiveMQ и объединяя их в сети, вы создаете сеть брокеров. В некоторых кругах это называется распределенными очередями, поскольку данная очередь может быть доступна для всех брокеров в сети. Но если вы собираетесь запустить несколько экземпляров ActiveMQ, вы должны просто рассмотреть возможность запуска дополнительных экземпляров ServiceMix.

  • Увеличение количества экземпляров ServiceMix - каждый экземпляр ServiceMix встраивает экземпляр ActiveMQ. Увеличивая число экземпляров ServiceMix, вы не только увеличиваете число экземпляров ActiveMQ (которые могут быть объединены в сеть для формирования сети брокеров), но и можете развернуть больше копий приложения в этих экземплярах ServiceMix. Если необходимо увеличить количество экземпляров ActiveMQ или ServiceMix, можно развернуть приложение-потребитель с соответствующим количеством одновременно работающих пользователей для каждого экземпляра. Сообщения не разделяются или дублируются, они распространяются круговым способом среди всех потребителей в очереди,независимо от того, где они находятся, исходя из потребительского спроса. То есть, если один экземпляр ActiveMQ в сети не имеет потребителей, он не будет иметь никаких сообщений в своем экземпляре очереди для использования. Это приводит к моему последнему предложению, увеличивая число потребителей, опрашивающих входящую очередь.

  • Увеличение числа потребителей JMS во входящей очереди - это, вероятно, самый простой, мощный и наиболее управляемый способ увеличения пропускной способности. Это проще всего, поскольку вы развертываете дополнительные экземпляры приложения-потребителя, чтобы они конкурировали за сообщения из входящей очереди (независимо от того, конкурируют ли они за локальную очередь или очередь, распространяемую через сеть брокеров). Это может быть так же просто, как увеличение числа одновременных потребителей или немного больше, если разделить часть приложения, которая содержит потребителей, и развернуть его во многих экземплярах ServiceMix. Она является самой мощной, поскольку обычно не является сложной, и масштабирование приложений, управляемых событиями, всегда выполняется за счет увеличения числа потребителей. Это наиболее управляемое приложение, так как вы можете изменить способ упаковки приложений, чтобы приложение-потребитель было полностью отдельным, предоставляя ему возможность распространения.

Это последнее предложение - самый мощный способ масштабирования вашего приложения. До тех пор, пока входящая конечная точка HTTP может обрабатывать большой объем трафика, может потребоваться только увеличить количество потребителей во входящей очереди. Большая причина для этого заключается в том, что либо потребители, либо бобы, которым они сдают, делают весь тяжелый подъем, основной объем обработки и проверки. Как правило, именно этот процесс в конечном итоге требует наибольшего объема ресурсов.

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

Брюс

-121--3003430-

Так что существуют две формы приращения

++s // increment before using value
s++ // increment after using value

И результат их можно обособить:

*++s // or...
*s++

Это действительно хорошо сработало на одной из самых первых машин для запуска C, PDP-11, которая имела режим косвенной адресации регистров, которые увеличивают регистр после. В аппаратном обеспечении были доступны следующие операции:

*--s // or
*s++

Вы можете сделать либо

*x++ = *y++; // or
*--x = *--y; // or some combination

И если вы сделали, вся строка произошла в одной инструкции. Поскольку//comments были введены C99, однако, вы не смогли избежать моего комментария синтаксис.

0
ответ дан 6 December 2019 в 08:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: