C++ 本地数组在循环中重复!C++;

C++ 本地数组在循环中重复!C++;,c++,arrays,loops,C++,Arrays,Loops,current\u name是以下循环中的本地char数组。我在循环中声明了它,所以每次从文件中读取新行时,它都会更改。但是,由于某些原因,以前的数据不会从当前名称中删除!如果未被下一行的新字符覆盖,它将打印旧数据 有什么想法吗 while (isOpen && !file.eof()) { char current_line[LINE]; char current_name[NAME]; file.getline(current_line, LIN

current\u name
是以下循环中的本地
char
数组。我在循环中声明了它,所以每次从文件中读取新行时,它都会更改。但是,由于某些原因,以前的数据不会从当前名称中删除!如果未被下一行的新字符覆盖,它将打印旧数据

有什么想法吗

  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;
  }
while(isOpen&&!file.eof()){
字符当前_行[行];
字符当前_名称[名称];
file.getline(当前_行,行);
int i=0;
while(当前_行[i]!=';'){
当前_名称[i]=当前_行[i];
i++;
}

cout填充后,您没有终止
current\u name
。在
cout
之前的内环后面添加
current\u name[i]=0
。如果您阅读
abcdef
然后阅读
jkl
,可能会看到这一点,并且可能会获得
jkldef
作为输出


更新

你想知道是否有更好的方法。有——我们会找到的。但是,来自Java,你的问题和后续行动确定了一些更大的问题,我相信你应该注意。小心你想要的——你可能真的得到它(以及更多):-)。以下所有这些都基于爱


所有Java程序员注意!欢迎来到“勇敢的新世界”!


基本概念

在我们讨论
C
语言之前,我们需要先讨论几个概念

计算机体系结构:

计算机程序的内存布局:

内存地址/指针与Java引用之间的差异:


Java程序员不熟悉的概念

C语言让您可以直接访问底层的计算机体系结构。它不会做任何您没有明确指定的事情。在这里,我要提到
C
[为简洁起见],但我真正谈论的是内存布局和计算机体系结构的结合

  • 如果您读取未初始化的内存,您将看到看似随机的数据
  • 如果你从堆中分配了一些东西,你必须显式地释放它。当它“超出范围”时,垃圾收集器不会神奇地将其标记为删除
  • C中没有垃圾收集器
  • C指针比Java引用的指针强大得多。您可以向指针添加和减去值。您可以减去两个指针,并将差值用作索引值。您可以在数组中循环,而无需使用索引变量——只需遵从指针并递增指针
  • Java中自动变量的数据存储在堆中。每个变量都需要单独的堆分配。这既慢又耗时
  • 在C语言中,存储在堆栈帧中的自动变量的数据。堆栈帧是一个连续的字节区域。为了给堆栈帧分配空间,C只需从堆栈指针[硬件寄存器]中减去所需的大小。堆栈帧的大小是给定函数范围内所有变量的总和,而不管它们是否在函数内的循环中声明
  • 它的初始值取决于前一个函数使用该区域的内容以及存储在该区域的字节值。因此,如果
    main
    调用函数
    fnca
    ,它将用任何数据填充堆栈。如果
    main
    调用
    fncb
    ,它将看到fnca的值,就fncb而言,这些值是半随机的。fnca和fncb在使用堆栈变量之前都必须初始化它们
  • 不带initializer子句的C变量声明不会初始化该变量。对于bss区域,它将为零。对于堆栈变量,必须显式执行该操作
  • C中没有数组索引的范围检查[或指向数组或数组元素的指针]。如果您在定义的区域之外写入,您将写入下一个映射/链接到内存区域的内容。例如,如果您有一个内存区域:
    int x[10];int y;
    ,并且您[无意中]写入
    x[10]
    [最后一个]您将损坏
    y
  • 无论阵列位于哪个内存段(例如数据、bss、堆或堆栈),这都是正确的
  • C没有字符串的概念。当人们谈论“C字符串”时,他们真正谈论的是一个
    char
    数组,该数组在有用数据的末尾有一个“字符串结束”(又称EOS)哨兵字符。“标准”EOS char几乎被普遍定义为0x00[自1970年以来]
  • 体系结构支持的唯一内在类型是:
    char
    short
    int
    long
    /
    指针
    long
    float/double
    。在给定的拱门上可能还有一些其他类型,但这是通常的列表。其他所有类型都有(例如,
    结构
    由编译器“构建”,以方便程序员使用arch内部类型)
下面是一些关于C[和C++]的内容:
-C有预处理器宏。Java没有宏的概念。预处理器宏可以被认为是元编程的一种粗糙形式。
-C有
内联
函数。它们看起来就像普通函数,但编译器会尝试将它们的代码直接插入到任何调用函数的函数中。如果函数定义清晰但很小(例如几行),这很方便。这样可以节省实际调用函数的开销


示例

以下是您的原始程序的几个版本作为示例:

// 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);
}

建议

  • 在你尝试“绕过”c字串之前,先拥抱它。
    // 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);
    }
    
         #define LINE 1000
    
        int j = 0;
        while (!file1.eof()) {
            j++;
            if( j > 20){break;} // back up escape for testing, in the event of an endless loop
    
            char current_line[LINE];
            //string current_name = ""; // see redefinition below
    
            file1.getline(current_line, LINE, '\n');
    
            stringstream ss(current_line); // stringstream works better in this case
    
            while (!ss.eof()) {
    
                string current_name;
                ss >> current_name;
                if (current_name != ";")
                { 
                    cout << current_name << endl;
                } // End if(current_name....
    
                } // End while (!ss.eof...
    
        } // End while(!file1.eof() ...
    
        file1.close();
    
        cout << "Done \n";