Разница между s [++ i];и с [я];++ I; - PullRequest
1 голос
/ 31 октября 2019

Я делаю некоторые упражнения из "языка программирования C" и не могу понять, что происходит, чтобы дать мне определенный результат. На самом деле это не препятствие, потому что я получил желаемый результат, но я не понимаю, почему изменение определенного фрагмента моего кода на самом деле дало мне нужный вывод. Просто искал объяснение.

Вот код, который работает так, как я хочу. Часть, которую я не понимаю, это s[++i] = ' '; в цикле 'k' for. До того, как я использовал s[++i], я использовал:

s[i] = ' ';

++i;

, который бы помещал только 1 пробел в массиве, независимо от того, сколько разпетля k побежал.

Затем, просто для тестирования, я поставил ++i; над s[i] = ' ';, и в выводе не было ни одного пробела.

#include <stdio.h>
#define MAXLINE 1000
#define TABSTOP 5

/* Write a program "detab" that replaces tabs in the input with a proper
number of blanks to space to the next tab stop. Assume a fixed set of tab
stops, say every n columnns. Should n be a variable or a synbolic parameter? */


int main() {

  char c;
  int i, j;
  int modTabStop, numTabs, k;
  char s[MAXLINE];

  i = 0;
  while((c = getchar()) != EOF) {
    if(c == '\t') {
      modTabStop = i % TABSTOP;
      numTabs = TABSTOP - modTabStop;
      for(k = 0;k <= numTabs; ++k)
        s[++i] = ' ';
    }
    else if(c == '\n') {
      ;
    }
    else {
      s[i] = c;
      ++i;
    }
  }

  for(j = 0;j <= i;++j)
    printf("%c", s[j]);

  return 0;
}

Мне просто интересно, почему s[++i]работал, и никто из других не сделал. Мой ожидаемый результат определен в комментарии над основной функцией. Но только для пояснения, я использовал тестовую строку «собака (табуляция)». Когда он работает правильно, вместо вкладки между «the» и «dog» должны быть помещены только 2 пробела, потому что моя точка табуляции равна 5, а «the» имеет длину в три буквы («the (space) (space) dog»)). Если я поставлю ++i; после s[i] = ' ', то получу один пробел между ("(пробел) собака"). И если я помещу это прежде, я не получаю пробелы ("thedog").

Я просто хочу убедиться, что я все это понимаю, прежде чем двигаться дальше. Спасибо, ребята!

Ответы [ 3 ]

4 голосов
/ 31 октября 2019

Для начинающих этот цикл

  for(k = 0;k <= numTabs; ++k)
              ^^^

неверен. Он должен выглядеть следующим образом:

  for(k = 0;k < numTabs; ++k)
              ^^^

В этом случае в массив будут вставлены ровно пробелы numTabs,

Это присвоение

    s[++i] = ' ';

также неверно, поскольку символ впозиция i не изменяется. Позиция пропускается из-за оператора предварительного увеличения ++i.

Вы должны написать вместо этого

    s[i++] = ' ';

Итак, наконец, цикл будет выглядеть так:

  for(k = 0;k < numTabs; ++k)
    s[i++] = ' ';

Обратите внимание, что этот цикл

while((c = getchar()) != EOF) {

неверно.

Вы должны написать вместо

while( i < MAXLINE && ( c = getchar() ) != EOF && c != '\n' ) {

или хотя бы как

while( i < MAXLINE && ( c = getchar() ) != EOF ) {

В последнем случае вы должны писать в цикле

else if(c == '\n') {
  s[i++] = ' ';
}

В противном случае, если вы вводите несколько операторов, они не будут разделены.

В первом случае оператор if должен быть удален.

И вместо объявления

char c;

Вы должны использовать объявление

int c;

, потому что тип char может вести себя как тип unsigned char (в зависимости от опций компилятора). И в этом случае сравнение c != EOF будет всегда верным.

3 голосов
/ 31 октября 2019

Существует большая разница между

s[i]
i++;

и

s[++i]

Прежде чем объяснить, позвольте мне упростить первую форму до s[i++], чтобы вы получили

s[i++]

и

s[++i]

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

Разница в том, что предварительное увеличение s[++i] увеличиваетзначение i перед его внедрением в выражение, которое в нашем случае является оператором доступа к массиву. В то время как постинкремент вводит значение i сначала в оператор доступа к массиву, а затем увеличивает его позже, точно так же, как вы изначально делали в расширенной форме из двух строк.

1 голос
/ 31 октября 2019

Рассмотрим код:

for(k = 0;k <= numTabs; ++k)
    s[i] = ' ';
    ++i;

это эквивалентно

for(k = 0;k <= numTabs; ++k){
    s[i] = ' ';
}
++i;

, поскольку только первый оператор находится в цикле for при использовании скобок.

Тогда это означает: записать пробел в s[i] для numTabs раз, затем увеличить i. Эффективно записывая один пробел.

Аналогично:

for(k = 0;k <= numTabs; ++k)
    ++i;
    s[i] = ' ';

увеличит i на numTabs раз, а затем запишет пробел. В результате в массиве остается numTabs символов тарабарщины и, возможно, завершающий NULL.

Решение простое: используйте фигурные скобки

...