gpt4 book ai didi

c++ - 局部数组在循环内重复! C++

转载 作者:行者123 更新时间:2023-11-30 03:47:31 24 4
gpt4 key购买 nike

current_name是以下循环内的本地char数组。我在循环中声明了它,因此每次我从文件中读取新行时它都会更改。但是,由于某种原因,先前的数据并未从current_name中删除!如果下一行没有被新字符覆盖,它将打印出旧数据。

有任何想法吗?

  while (isOpen && !file.eof()) {
char current_line[LINE];
char current_name[NAME];

file.getline(current_line, LINE);

int i = 0;
while (current_line[i] != ';') {
current_name[i] = current_line[i];
i++;
}

cout << current_name << endl;
}

最佳答案

您无需在填充current_name后终止它。在current_name[i] = 0之前的内循环之后添加cout。如果您阅读abcdef然后阅读jkl并可能获得jkldef作为输出,则可能会看到此信息

更新

您想知道是否有更好的方法。有-我们将会解决。但是,来自Java,您的问题和跟进发现了一些我认为您应该意识到的较大问题。小心您想要的东西-您可能会得到[更多] :-)。以下所有内容都是基于爱...

Attention All Java Programmers! Welcome to "A Brave New World"!



基本概念

在我们甚至开始对 语言进行 C编码之前,我们需要首先讨论一些概念。

计算机架构:
https://en.wikipedia.org/wiki/Computer_architecture
https://en.wikipedia.org/wiki/Instruction_set

计算机程序的内存布局:
http://www.geeksforgeeks.org/memory-layout-of-c-program/

内存地址/指针与Java引用之间的区别:
Is Java "pass-by-reference" or "pass-by-value"?
https://softwareengineering.stackexchange.com/questions/141834/how-is-a-java-reference-different-from-a-c-pointer

Concepts Alien to Java Programmers



C语言使您可以直接访问底层的 计算机体系结构。它不会执行您未明确指定的任何操作。在这里,为了简洁起见,我提到的是 C,但是我真正要说的是内存布局和计算机体系结构的结合。
  • 如果读取未初始化的内存,则会看到看似随机的数据。
  • 如果从堆中分配了某些内容,则必须显式释放它。当它“超出范围”时,它不会神奇地被垃圾收集器标记为删除。
  • C中没有垃圾收集器
  • C指针比Java引用要强大得多。您可以添加和减去指针值。您可以减去两个指针,并将差值用作索引值。您可以在不使用索引变量的情况下遍历数组-只需引用一个指针并递增该指针即可。
  • Java中自动变量的数据存储在堆中。每个变量都需要单独的堆分配。这是缓慢且耗时的。
  • 在C中,自动变量的数据存储在堆栈帧中。堆栈帧是字节的连续区域。为了为堆栈帧分配空间,C只需从堆栈指针[硬件寄存器]中减去所需的大小即可。堆栈帧的大小是给定函数范围内所有变量的总和,无论是否在函数内部的循环内声明它们。
  • 其初始值取决于该区域使用的先前函数是什么以及其存储在其中的字节值。因此,如果main调用函数fnca,它将使用任何数据填充堆栈。如果然后main调用fncb,它将看到fnca的值,就fncb而言,该值是半随机的。在使用fnca和fncb之前,都必须初始化堆栈变量。
  • 没有初始化程序子句的C变量声明不会初始化该变量。对于bss区域,它将为零。对于堆栈变量,必须明确地执行此操作。
  • 没有对C中的数组索引(或与此相关的指向数组或数组元素的指针)进行范围检查。如果您写的内容超出了定义的区域,则接下来将写到已映射/链接到内存区域中的任何内容。例如,如果您有一个存储区:int x[10]; int y;,并且[无意间]写到x[10] [末尾一个],则会破坏y
  • 不管数组位于哪个内存部分(例如,数据,bss,堆或堆栈),这都是正确的。
  • C没有字符串的概念。当人们谈论“c字符串”时,他们真正在说的是char数组,该数组在有用数据的末尾具有“字符串结尾”(又名EOS)标记字符。 “标准” EOS字符几乎普遍定义为0x00 [〜1970年以来]
  • 架构支持的唯一固有类型是:charshortintlong / pointerlong longfloat/double。给定的拱门上可能还有其他一些,但这是通常的列表。
  • 其他所有内容(例如 classstruct由编译器“构建”,以方便程序员从arch内在类型开始)

    以下是有关C [和C++]的一些信息:
    -C具有预处理器宏。 Java没有宏的概念。预处理器宏可以认为是元编程的一种粗略形式。
    -C具有 inline函数。它们看起来像常规函数,但是编译器将尝试将其代码直接插入到任何调用该函数的函数中。如果函数定义明确但很小(例如几行),这将很方便。它节省了实际调用函数的开销。

    示例

    以下是原始程序的多个版本作为示例:
    // myfnc1 -- original
    void
    myfnc1(void)
    {
    istream file;

    while (isOpen && !file.eof()) {
    char current_line[LINE];
    char current_name[NAME];

    file.getline(current_line, LINE);

    int i = 0;

    while (current_line[i] != ';') {
    current_name[i] = current_line[i];
    i++;
    }

    current_name[i] = 0;

    cout << current_name << endl;
    }
    }

    // myfnc2 -- moved definitions to function scope
    void
    myfnc2(void)
    {
    istream file;
    int i;
    char current_line[LINE];
    char current_name[NAME];

    while (isOpen && !file.eof()) {
    file.getline(current_line, LINE);

    i = 0;

    while (current_line[i] != ';') {
    current_name[i] = current_line[i];
    i++;
    }

    current_name[i] = 0;

    cout << current_name << endl;
    }
    }

    // myfnc3 -- converted to for loop
    void
    myfnc(void)
    {
    istream file;
    int i;
    char current_line[LINE];
    char current_name[NAME];

    while (isOpen && !file.eof()) {
    file.getline(current_line, LINE);

    for (i = 0; current_line[i] != ';'; ++i)
    current_name[i] = current_line[i];
    current_name[i] = 0;

    cout << current_name << endl;
    }
    }

    // myfnc4 -- converted to use pointers
    void
    myfnc4(void)
    {
    istream file;
    const char *line;
    char *name;
    char current_line[LINE];
    char current_name[NAME];

    while (isOpen && !file.eof()) {
    file.getline(current_line, LINE);

    name = current_name;
    for (line = current_line; *line != ';'; ++line, ++name)
    *name = *line;
    *name = 0;

    cout << current_name << endl;
    }
    }

    // myfnc5 -- more efficient use of pointers
    void
    myfnc5(void)
    {
    istream file;
    const char *line;
    char *name;
    int chr;
    char current_line[LINE];
    char current_name[NAME];

    while (isOpen && !file.eof()) {
    file.getline(current_line, LINE);

    name = current_name;
    line = current_line;
    for (chr = *line++; chr != ';'; chr = *line++, ++name)
    *name = chr;
    *name = 0;

    cout << current_name << endl;
    }
    }

    // myfnc6 -- fixes bug if line has no semicolon
    void
    myfnc6(void)
    {
    istream file;
    const char *line;
    char *name;
    int chr;
    char current_line[LINE];
    char current_name[NAME];

    while (isOpen && !file.eof()) {
    file.getline(current_line, LINE);

    name = current_name;
    line = current_line;
    for (chr = *line++; chr != 0; chr = *line++, ++name) {
    if (chr == ';')
    break;
    *name = chr;
    }
    *name = 0;

    cout << current_name << endl;
    }
    }

    // myfnc7 -- recoded to use "smart" string
    void
    myfnc7(void)
    {
    istream file;
    const char *line;
    char *name;
    int chr;
    char current_line[LINE];
    xstr_t current_name;
    xstr_t *name;

    name = &current_name;
    xstrinit(name);

    while (isOpen && !file.eof()) {
    file.getline(current_line, LINE);

    xstragain(name);

    line = current_line;
    for (chr = *line++; chr != 0; chr = *line++) {
    if (chr == ';')
    break;
    xstraddchar(name,chr);
    }

    cout << xstrcstr(name) << endl;
    }

    xstrfree(name);
    }

    这是一个“智能”字符串[buffer]类,类似于您惯常使用的类:
    // xstr -- "smart" string "class" for C

    typedef struct {
    size_t xstr_maxlen; // maximum space in string buffer
    char *xstr_lhs; // pointer to start of string
    char *xstr_rhs; // pointer to start of string
    } xstr_t;

    // xstrinit -- reset string buffer
    void
    xstrinit(xstr_t *xstr)
    {

    memset(xstr,0,sizeof(xstr));
    }

    // xstragain -- reset string buffer
    void
    xstragain(xstr_t xstr)
    {

    xstr->xstr_rhs = xstr->xstr_lhs;
    }

    // xstrgrow -- grow string buffer
    void
    xstrgrow(xstr_t *xstr,size_t needlen)
    {
    size_t curlen;
    size_t newlen;
    char *lhs;

    lhs = xstr->xstr_lhs;

    // get amount we're currently using
    curlen = xstr->xstr_rhs - lhs;

    // get amount we'll need after adding the whatever
    newlen = curlen + needlen + 1;

    // allocate more if we need it
    if ((newlen + 1) >= xstr->xstr_maxlen) {
    // allocate what we'll need plus a bit more so we're not called on
    // each add operation
    xstr->xstr_maxlen = newlen + 100;

    // get more memory
    lhs = realloc(lhs,xstr->xstr_maxlen);
    xstr->xstr_lhs = lhs;

    // adjust the append pointer
    xstr->xstr_rhs = lhs + curlen;
    }
    }

    // xstraddchar -- add character to string
    void
    xstraddchar(xstr_t *xstr,int chr)
    {

    // get more space in string buffer if we need it
    xstrgrow(xstr,1);

    // add the character
    *xstr->xstr_rhs++ = chr;

    // maintain the sentinel/EOS as we go along
    *xstr->xstr_rhs = 0;
    }

    // xstraddstr -- add string to string
    void
    xstraddstr(xstr_t *xstr,const char *str)
    {
    size_t len;

    len = strlen(str);

    // get more space in string buffer if we need it
    xstrgrow(xstr,len);

    // add the string
    memcpy(xstr->xstr_rhs,str,len);
    *xstr->xstr_rhs += len;

    // maintain the sentinel/EOS as we go along
    *xstr->xstr_rhs = 0;
    }

    // xstrcstr -- get the "c string" value
    char *
    xstrcstr(xstr_t *xstr,int chr)
    {

    return xstr->xstr_lhs;
    }

    // xstrfree -- release string buffer data
    void
    xstrfree(xstr_t *xstr)
    {
    char *lhs;

    lhs = xstr->xstr_lhs;
    if (lhs != NULL)
    free(lhs);

    xstrinit(xstr);
    }

    推荐
  • 在尝试“避开”“c字符串”之前,请拥抱它。您会在很多地方遇到它。这是不可避免的。
  • 了解如何像索引变量一样轻松地操作指针。它们更加灵活,并且[一旦您掌握了它们,就更容易使用]。我见过的编程人员编写的代码没有学到这些,他们的代码总是比需要的复杂得多(通常充满了我需要修复的错误)。
  • 在任何语言中,良好的注释都很重要,但是对于某些事情,也许在C语言中比Java语言更重要。
  • 始终使用-Wall编译-Werror并修复所有警告。您已被警告:-)
  • 我会讲一些我给你的myfnc示例。这会有所帮助。
  • 在开始学习之前,请牢牢掌握基础知识。


  • 现在,关于C++的一句话...

    以上大部分内容与体系结构,内存布局和C有关。所有这些仍然适用于C++。

    当函数返回并且超出范围时,C++确实对堆栈变量进行了更有限的回收。这有其优点和缺点。

    C++有许多类可以减轻常见功能/习惯用法/样板的繁琐。它具有 std标准模板库。它还具有 boost。例如, std::string可能会做您想要的。但是,首先将其与我的xstr进行比较。

    但是,我再次提醒您。在您目前的水平上,从基础开始工作,而不是围绕基础工作。

    关于c++ - 局部数组在循环内重复! C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33661457/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com