0

The following is obviously very impractical but my lecturer insists on teaching us a very fundamental understanding of programming. The exercise he gave us goes like this:

Using only System.in.read, int, char, and loops, create a method that reads user input from the command line and returns a char[] that's exactly as big as the amount of characters that were entered. Do not use System.arraycopy() or other library methods.

I'm clueless. Since there seems to be no way of buffering System.in.read input, the array would have to be perfectly sized before any chars are parsed. How in the world is this supposed to work?

4

3 回答 3

1

创建一个从命令行读取用户输入并返回 char[] 的方法

再想一想,我假设您应该通过自己增长char[]数组来进行自己的输入缓冲。System.arraycopy()这应该是被提及的原因。

增长一个数组就像

  • 创建一个比现有数组长 1 项的新数组。
  • 对于旧数组中的每个字符
    • 将字符从旧数组复制到新数组,保持位置
  • 用成长的数组替换旧数组。

如果你将它与从输入流中读取所有字符的循环结合起来,你会得到以下内容,并且应该完成你的任务。

  • 从长度为 0 的数组开始
  • 而输入流中可用的字符
    • 将数组增大一倍
    • 将输入流中的字符放入数组的最后一个槽中
  • 返回数组

甚至可以在没有循环和不断增长的数组的情况下做到这一点。只需创建一个正确大小的新数组一次。

private static char[] readToCharArray(int length) throws IOException {
    int read = System.in.read();
    char[] result;
    if (read == -1 || read == '\r' || read == '\n' ) {
        result = new char[length];
    } else {
        result = readToCharArray(length + 1);
        result[length] = (char) read;
    }
    return result;
}

char[] myArray = readToCharArray(0);
于 2012-11-22T00:34:46.687 回答
0

手动arraycopy怎么样,文本没有说明什么?如果允许,您可以执行以下操作:

    private static char[] readInput() throws IOException {
      System.out.println("type something terminated with '|'");
      char[] input = new char[0];
      int count = 0;
      int read;
      for (; ; ) {
        read = System.in.read();
        if (read == '|') {
          break;
        } else {
          char[] tmp = new char[input.length + 1];
          for (int i = 0; i < input.length; i++) {
            tmp[i] = input[i];
          }
          input = tmp;
        }
        input[count] = (char) read;
        count++;
      }
      return input;
    }

你也可以检查read == -1而不是read == '|'但输入结束字符因系统而异。除了在每次迭代中复制 char[] 之外,您还可以在每 x 次迭代中执行一次,然后在最后创建一个正确大小的数组。你也可以使用while循环......

但是按照建议只返回一个正确大小的空数组肯定会更有趣zapl:)

于 2012-11-22T00:36:15.633 回答
0

我假设您的讲师的意思是:

  • char[] 应该包含从 System.in 读取的字符(不仅仅是正确的大小)
  • " System.in.read" 仅指InputStream#read()而不是指其他重载read方法 on InputStream,因此您只能一次读取一个字符。

你应该看看ArrayList是如何实现的。它由一个数组支持,但列表可以任意调整大小。当列表的大小超过数组大小时,ArrayList创建一个更大的新数组,然后将旧数组的内容复制到其中。以下是一些相关的摘录ArrayList

/**
 * Appends the specified element to the end of this list.
 *
 * @param e element to be appended to this list
 * @return <tt>true</tt> (as specified by {@link Collection#add})
 */
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 *
 * @param minCapacity the desired minimum capacity
 */
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

由于您不能使用System.arraycopy(),因此您需要编写自己的方法来执行此操作。那只是一个for循环。

这实际上并不是那么低效。正如 javadoc 所描述的,ArrayList#add(E)以摊销的常数时间运行。

如果您ArrayList完全遵循该策略,那么您的结果数组将比它需要的更大,所以最后,您需要在最后再进行一次数组调整大小以将其截断为精确的输入大小。或者,您可以在每次读取字符时将数组增加 1,但运行时间将是输入长度的二次 (n^2) 而不是线性 (n)。

于 2012-11-22T00:38:12.133 回答