帮忙看看这段c程序为何链表输出的不正确?

发布于 2021-11-21 12:07:38 字数 1631 浏览 808 评论 16


程序:
#include <stdio.h>
#include <stdbool.h>
#include<stdlib.h>
struct tell{
	char *num;
	int n;
	struct tell *next;
};
struct tell *head = NULL;

void cre_list(){  
    head = (struct tell *)malloc(sizeof(struct tell));  
    head->next = NULL;
    head->num = NULL;
}
void add_list(char *num,int n){
  struct tell *pre = (struct tell *)malloc(sizeof(struct tell));
  pre->num = num;
  pre->n = n;
  struct tell *p = head->next;
  head->next = pre;
  pre->next = p;
}
void pri_list(){
	struct tell *p = head;
	for (; p->next != NULL; )
	{
		p = p->next;
		printf("%s  %dn",p->num,p->n);
	}
}
void dosomething(char *p){
	char c[7];
  int j=0,i = 0;
	for (i; i < 20; i++)
	{
		if (j>6)
		{
			break;
		}
		//printf("%Cn",p[i]);
		if (p[i]>='0' && p[i]<='9'){
			c[j] = p[i];
			// printf("%cn",c[j]);
			++j;
		}else if (p[i]>='A' && p[i]<='Z')
		{
			c[j] = ((p[i]-65)/3)+48;
			++j;
		}
	}
	add_list(c,1);
}
int main(void)
{
	int count;
	char ch[20];
	cre_list();
	scanf("%d",&count);
	int i = 0;
	for(; i < count; i++){
		getchar();
		fgets(ch,20,stdin);
		dosomething(ch);
	}
        pri_list();
	return 0;
}

例如:

输入:
2
1234567
2345678
希望输出:
1234567
2345678
实际输出:
2345678
2345678

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

离去的眼神 2021-11-22 18:01:06

回复
多谢~以后多指教~

坏尐絯 2021-11-22 18:01:06

回复
你肯学,我就肯教,从来不强迫人。哈。

浮生未歇 2021-11-22 18:01:06

牢记鬼哥指点,不瞒鬼哥~不才顶多也就大一时间一年的c++学龄,而且还是再学校环境下~如今学习c其实是为了想参加acm大赛,现在看来c果然是够“低级”,以至于我这等做“高级”语言的头大啊~

秉烛思 2021-11-22 18:01:06

复古式 2021-11-22 18:01:06

菜鸟路过:昨天我也看了这个程序半天才看明白问题所在,最后看到上面一楼已经详细回答了就没有回答。今天看到上面的讨论想说两句。

堆与栈在程序执行的时候,函数malloc所分配的空间是在堆中,函数内部中直接定义的auto型变量应该是在栈中,每一个函数执行完了之后,关于这个函数在栈中分配的一个stack frame 区域就会被释放,这个区域存储的就是这个函数中使用的一些变量。而上面函数dosomething每次执行结束后, c[]这个数组的空间就会被释放。栈的性质都明白,所以执行下一个函数的时候这个区域很可能就会被下一个函数占用,然后里面的数据就......了。

总的来说全局变量,静态变量,malloc 这些的空间在堆中的量在函数间可调用(只要有地址),对其他函数栈中的变量的操作---只能是对前面层的函数的变量通过地址进行操作。

菜鸟路过,说得不对的地方还请指正。

掩饰不了的爱 2021-11-22 18:01:06

咱不是这个圈里的。。。打酱油路过,不过近日有心再重新涉足下底层C、数据结构、算法等方面的知识,基础再打扎实些。

酷到爆炸 2021-11-22 18:01:06

这段函数的关键问题所在一楼说的已经很清楚。就是指针指向空间的问题,代码中每次创建一个节点其num指向的都是一片不可靠的栈空间,栈空间当程序离开该函数后理论上是不可用的。

根据代码的流程应该是输出乱码,至于为什么输出两次相同的内容完全是应为PC在内存是使用上虽然说是随机的,但连续调用同一个函数时其使用的栈内存地址一般不会变。

内存非安全使用是C语言中常遇到的问题,有时也很难定位。且不同的内存问题其PC和单片机上造成的影响还不一样,要写出比较健壮的C代码需要对内存的知识有个比较好的理解。

做个少女永远怀春 2021-11-22 18:01:06

@小吃店 @fcsong000833 @爪哇老妖

感谢指导,开始对c的内存不是很重视~所以觉得很诡异,但是经过几位的指点,貌似明白了出现这种情况的原因了。看来以后写c要格外小心,规范一点儿了~

无法言说的痛 2021-11-22 18:01:04

不是抄书~不才学过一年c++,对c的精髓指针还不太理解,想借此机会补补c的知识,献丑了~

情场扛把子 2021-11-22 18:00:44

这代码写的,是不是楼主抄书的???哈。

带上头具痛哭 2021-11-22 18:00:41

出现这种现象的原因就出在18行的赋值上

无法言说的痛 2021-11-22 18:00:26

#5 num为char*型,最好命名为 str

谢绝鈎搭 2021-11-22 17:58:57

不才还是不太明白,为何会出现链表中节点数目正常,但是每个节点的值都是最后一次的结果这种情况,希望能给解释一下~Thanks !

只为守护你 2021-11-22 17:57:14

回复
这是因为num为 char* 型,char*只是一个指针,它只指向字符串实际地址,并不保存字符串上的那些字符;而你的程序中2次传给它的都是main中char ch[20]的首地址。这两次的num所指的都是这个ch[20],而这个ch[20]的值被修改了

风苍溪 2021-11-22 17:23:49

回复
再add_list()中传的是另一个char *c的首地址啊,c是一个函数中的局部变量,在第二次执行dosomething()时难道不是重新申请空间么?大哥的意思是,执行两次dosomething()中调用的add_list()传的参数c指向的是同一个地址,也就是说char *c没有被释放?

柳若烟 2021-11-22 04:05:00

错误有两处,

1)35行 for (i; i < 20; i++)结束处应该给c[]加一个结束标志 ''

2)18行的字符指针不能直接赋值

建议改的地方一共5处,已加注释,代码如下:

#include <stdio.h>
// #include <stdbool.h>
#include <stdlib.h>
#include <string.h>
struct tell{
	char *str;
	int n;
	struct tell *next;
};
struct tell *head = NULL;

void cre_list(){  
    head = (struct tell *)malloc(sizeof(struct tell));  
    head->next = NULL;
    head->str = NULL;
}
void add_list(char *str,int n){
  struct tell *pre = (struct tell *)malloc(sizeof(struct tell));
  // pre->str = str; // #4 没有分配字符串空间,应该这样:
  pre->str = (char*)malloc( (strlen(str)+1)*sizeof(char) );
  strcpy(pre->str, str);
  
  pre->n = n;
  struct tell *p = head->next;
  head->next = pre;
  pre->next  = p;
}
void pri_list(){
	struct tell *p = head;
	for (; p->next != NULL; )
	{
		p = p->next;
		printf("%s  %dn",p->str,p->n);
	}
}
void dosomething(char *p){
	char c[8]; // #3 c[]应该多一个字符
  int j=0,i = 0;
	for (i; i < 20; i++)
	{
		if (j>6)
		{
			break;
		}
		//printf("%Cn",p[i]);
		if (p[i]>='0' && p[i]<='9'){
			c[j] = p[i];
			// printf("%cn",c[j]);
			++j;
		}else if (p[i]>='A' && p[i]<='Z')
		{
			c[j] = ((p[i]-65)/3)+48;
			++j;
		}
	}
	c[j] = ''; // #2 没有加结束标志, c[]也应该多一个字符
	add_list(c,1);
}
int main(void)
{
	int count;
	char ch[20];
	cre_list();
	scanf("%d",&count);
	int i = 0;
	for(; i < count; i++){
		// getchar();
		// fgets(ch,20,stdin);
		scanf("%s", ch); // #1 这里最好用scanf()上下一致,就可以不用管行尾的字符了
		dosomething(ch);
	}
    pri_list();
	return 0;
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文