【问题标题】:K&R: Array of pointers to strings with newlinesK&R:指向带有换行符的字符串的指针数组
【发布时间】:2015-04-17 21:43:03
【问题描述】:

我有一个关于 K&R 示例的小问题(排序行示例,第 108 页)。

我不明白当我取消注释 readlines 中的行时看到的行为,这会删除使用 getline 读取输入时添加的换行符。

int main()
{
    int nlines;

    if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
        my_qsort(lineptr, 0, nlines-1);
        writelines(lineptr, nlines);
        return 0;
    } else {
        printf("error: input too big \n");
        return 1;
    }
}

int readlines(char *lineptr[], int maxlines)
{
    int len, nlines;

    char *p, line[MAXLEN];

    nlines = 0;
    while ((len = my_getline(line, MAXLEN)) > 0)
        if (nlines >= maxlines || (p = alloc(len)) == NULL)
             return -1;
        else {
            line[len-1] = '\0'; //delete newline. 
            my_strcpy(p, line);
            lineptr[nlines++] = p;
        }
    return nlines;
}

void writelines(char *lineptr[], int nlines)
{
    while (nlines-- > 0)
        printf("%s\n", *lineptr++);
}

例如,如果我随后输入以下内容:

linje1
linje2
linje3
linje4

然后writelines会输出:

linje1
linje2
linje3
linje4

linje2
linje3
linje4

linje3
linje4

linje4
"and one last newline..."

从中我推断 lineptr[0] 指向所有行。 lineptr[1] 指向除第一行之外的所有内容 ... , lineptr[3] 仅指向“linje4”

我不明白我们如何通过将行存储为“linje1\n”而不是“linje1”来获得这种行为。

澄清: 在 writelines 中(当 lineptr 指向数组的开头时) 呼叫printf("%s", *lineptr) 如何打印所有行?

编辑 2

啊,我明白了,但这是来自 K&R 的 getline 函数

int my_getline(char s[], int lim)
{
    int c, i;

    for (i=0; i < lim-1 && (c=getchar()) != EOF && c != '\n'; i++)
        s[i] = c;
    if (c == '\n') {
        s[i] = c;
        ++i;
    }
    s[i] = '\0';
    return i;
}

而且我确信它总是会给我一个以 null 结尾的字符串,不管它是否以换行符结尾?

这是K&R的alloc:

#define ALLOCSIZE 10000

static char allocbuf[ALLOCSIZE]; // Storeage for alloc
static char *allocp = allocbuf; // Next free position

char *alloc(int n) // Return pointer to n characters
{
    if (allocbuf + ALLOCSIZE - allocp >= n) { // it fits
        allocp += n;
        return allocp - n;
    } else
        return 0;
}

编辑 3: 感谢所有的cmets。但是整个程序的输入与 K&R 中的完全一样,并且运行良好(我已经将输出与 grep 进行了比较),因此所有外围功能都按预期工作(例如 my_strcpy 的工作方式与 strcpy 完全相同,并复制字符串直到并包括空终止符)。 alloc 函数只是一个指向 K&R 的 char 大数组的指针。

我还是不明白的是:

C 读入一些文本行,复制它,将行 i 存储在内存中的某处,并让lineptr[i] 指向该内存位置:

使用 my_getline 读取行,读取整行(包括换行符),然后以空字符终止字符串。

如果我跳过line[len-1] = '\0'; 步骤,readlines 然后将指向该行副本的指针存储在lineptr[i] 中。在记忆中,我认为字符串(for i=1)看起来像这样"linje1\n\0"

但正如@DanJAB 指出的那样,很可能缺少空字符,因此字符串存储为"linje1\n",因此当 writelines 打印时(通过 lineptr) 这一行,它会在内存中打印出这之后的所有内容,因为缺少空字符,而这恰好是其余的行。

但我无法理解的是为什么 line[len-1] = '\0'; 显然需要将字符串 (i=1) 存储为 "linje1\0",而 my_getline 总是返回一个以 null 结尾的字符串?

再次感谢,对于任何潜在的不明确之处,我们深表歉意。

最终编辑 整个问题在于 alloc(len) 没有为最终的空字符分配空间!谢谢你帮助我。

【问题讨论】:

  • 也许空终止符丢失的问题在另一个函数中。也许my_strcpy 做得不对。
  • @DanJAB 不,如果我用库版本替换该函数,我会得到完全相同的结果。不过还是谢谢。
  • MAXLEN 是什么类型/值?
  • 一种基本的调试技术是使用打印语句。例如,在行:line[len-1] = '\0'; //delete newline. 之后,您可以添加:printf("line: &lt;&lt;%s&gt;&gt;\n", line); 以检查换行符是否已被删除。当然,如果没有换行符,您已经删除了其他最后一个字符,但这不应该是您的数据的问题。

标签: c


【解决方案1】:

1) 对于char line[MAXLEN]; ... my_getline(line, MAXLEN) ... my_getline(char s[], int lim)lim 是缓冲区的大小

但是函数my_getline()被设计成lim是最大字符串长度
C 字符串 lengthchar 数组驻留所需的最小 size 小 1。

使用char line[MAXLEN+1]; 或将my_getline(line, MAXLEN) 代码更改为i &lt; lim-2

2) my_getline(line, MAXLEN) 的结果可以是 ""(但 len &gt; 0 测试会处理这个问题),而且该行可能不会以 '\n' 结尾。

line[len-1] = '\0'; //delete newline. 

更好用

if (len > 0 && line[len-1] == '\n') {
  line[len-1] = '\0'; //delete newline. 
}

3) p = alloc(len) 不够用。使用p = alloc(len+1u)

4) 建议注释掉 my_qsort(lineptr, 0, nlines-1);,直到所有其他代码都正常工作。

5) 这一切让我也怀疑未发帖的my_strcpy()/my_qsort()

代码可能有其他问题,但发布的内容不可编译。

【讨论】:

  • 是的,我明白保持直言不讳很重要。例如,如果最后一行不是空行,而是一行文本,则 "line[len-1] = '\0'" 将删除该行的最后一个字符,例如将 "linje4" 转换为 "linje"
  • 在执行 alloc(len+1) 时,整个缺失的空字符行为得到了修复!我终于明白了!非常感谢
【解决方案2】:

如果您谈论的是line[len-1] = '\0'; 行,它不是删除新行,而是用空终止符替换它。这意味着如果你没有那一行,那么你就没有那个标记字符串结尾的东西,因此当你打印它时,你也会在内存中得到它后面的任何东西(下一个字符串)。

【讨论】:

  • 但我认为 getline (正如 K&R 所写的那样)总是返回一个以空字符结尾的字符串?所以当我从 getline 得到一个字符串时,我虽然最后有一个 '\n' ,但仍然是空终止的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-28
  • 2014-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多