【问题标题】:Printing struct shows garbage打印结构显示垃圾
【发布时间】:2013-09-27 22:26:51
【问题描述】:

我正在尝试做一个简单的练习,我应该在哪里使用指针和 malloc 在结构中输入 2 个输入(monto 和 loc)。当我尝试打印数据时,它显示垃圾。我试图检查发生了什么,所以我在输入后打印数据并显示如下内容 -1414812757 -158839287345460020000000000000000000000.00

struct transaccion{
    int loc;
    float monto;
    char nombre[50];
} cliente,*pcliente;

int cargadatos (struct transaccion*);
void mostrarlocalidad(struct transaccion*,int);
void mostrarestructura(struct transaccion*);

void main()
{
    int tam=50,ll;
    struct transaccion *pTrans;
    pTrans=(struct transaccion*)malloc(sizeof(struct transaccion)*tam);
    pTrans[0].monto=5;
    if(pTrans==NULL){
        puts("Falta memoria");
        exit(3);
    }

    ll=cargadatos(pTrans);
    mostrarlocalidad(pTrans,ll);
    free(pTrans);
    system("pause");
}

int cargadatos (struct transaccion *pTrans)
{
    int i=0;
    while (pTrans[i].loc!=0){
        puts ("ingrese numero de localidad");
        scanf("%d", &pTrans[i].loc); fflush (stdin);
        puts ("ingrese monto");
        scanf("%.2f",&pTrans[i].monto); fflush(stdin);
        int j=0;
        for (j=0; j<=i; j++)  {
            if (pTrans[j].loc==pTrans[i].loc){
                pTrans[j].monto=pTrans[j].monto+pTrans[i].monto;
                i--;
            }
        }
        printf("%d %.2f \n",pTrans[i].loc,pTrans[i].monto);
        i++;
    }
    return;
}

我已经尝试了好几个小时,但我无法弄清楚错误在哪里。

【问题讨论】:

  • malloc 没有初始化分配的内存块!
  • 谁/什么建议使用fflush(stdin)
  • (1) void main() 错误; (2)fflush(stdin)是未定义的行为; (3) 将i 设置为0,每循环递减一次,然后检查j &lt;= i 是否为真,这只会在第一个循环中为真,然后你尝试打印pTrans[-1]; (4) 你没有#include 任何标题; (5) 你称它为“C++”,但你使用的是malloc()free(); (6) 等等等等等等,你从哪里弄来的这些奇怪的东西?
  • @chux 这是微软特有的 hack 来吞下换行符(符合标准的解决方案是让 scan 调用本身吞下尾随空格)
  • 附带问题:ll=cargadatos(pTrans);,但cargadatos(pTrans) 不返回值,只是一个return;

标签: c


【解决方案1】:

您看到垃圾的原因是您的 j 循环错误。由于您正在迭代

最简单的解决方法是将 j 循环更改为 j

【讨论】:

  • 只是更改为j &lt; i 不太可能是“修复”。那里有一个外部循环,它至少会尝试增加i,因此该检查仅在通过该外部循环的第一次迭代时为真。显然代码完全被破坏了,在内部循环中递减i,然后在外部循环中尝试将其递增1几乎肯定不会导致所需的行为,printf() 在第一次迭代后可能是错误的正如你所说,整个事情永远不会初始化,等等等等。
  • 我不明白您所说的“检查仅在第一次交互时为真”是什么意思。鉴于他正在尝试做的事情,即将刚刚输入的值添加到先前输入的值然后丢弃刚刚添加的条目,该错误正在检查他刚刚输入的数据。您永远不希望 j 循环命中当前条目,因此 j
  • 我的措辞可能不清楚,但是当且仅当i &lt;= 0(它在外循环的第一次迭代中,但可能不在)时,j &lt;= i 保证为真由于i++while 循环结束时的后续迭代。 i 可能在for 循环中递减的事实使i 到处都是,因此for 循环条件可能会在您到达输入的数据之前很长时间满足,即@入口点的 987654333@ 和检查 for 循环条件点的 i 可能不一样。
  • j 是一个循环计数器。假设一切正常, j 将始终
  • 如果你做了j = 0i = 0然后你去i--,那么j &lt;= i是真的,即使你没有去@ 987654340@ 在每次循环迭代中,您执行(或者,更确切地说,OP 执行)。在外部循环的后续迭代中,它可能为真,因为i 可能不会从0 开始,因为i++ 在外部循环的末尾。我没有任何进一步解释这个基础数学的冲动。
【解决方案2】:

这里有三个问题是由同一个错误引起的——j循环上的一个错误条件。 我假设您正在尝试做的是读入一个数组元素,并且 扫描所有以前的数组元素,看看你是否已经在那个位置有东西——在这种情况下,你想使用“旧”元素进行计数,然后重用新元素。 现在 j 循环的范围错误会导致 3 个问题:

  1. 您将始终读入元素 0。

  2. 你将永远拥有应有的两倍

  3. 您总是会打印未初始化的数组元素 [-1],这不是您想要的。

这是因为当 i=0 时,您的 j(即

现在 i 在尝试重用时递减 - 使 i==-1。

您现在打印这个未初始化的意外 [-1] 元素,为您提供该内存位置中发生的任何内容。 现在你受到第三种效果的影响——你增加 i 使其为 0,并再次使用 0 元素迭代 while。 所有这一切都是一个小错误的结果:在 j 循环中使用条件 j

for (j = 0 ; j < i ; j++)

您的程序可能会正常运行。

【讨论】:

    【解决方案3】:
    struct transaccion{
        int loc;
        float monto;
        char nombre[50];
    } cliente,*pcliente;
    

    您声明了两个在任何地方都不使用的变量。

    pTrans=(struct transaccion*)malloc(sizeof(struct transaccion)*tam);
    

    不需要从 malloc 进行强制转换。

    下面的块应该放在之前你使用指针。

    if(pTrans==NULL){
        puts("Falta memoria");
        exit(3);
    }
    

    这个循环可能会被执行,也可能不会被执行,这取决于你会在指定的内存区域中找到的随机值。

    while (pTrans[i].loc!=0){
    

    其他答案中所说的也是正确的。

    【讨论】:

      【解决方案4】:

      非常感谢大家,现在我意识到我犯了很多错误。我也知道有些变量我没有使用它,因为我还没有实现。我会更正它并发布工作代码。

      【讨论】: