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

独-奏 发布于 2013/01/14 21:50
阅读 676
收藏 1

程序:
#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  %d\n",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("%C\n",p[i]);
		if (p[i]>='0' && p[i]<='9'){
			c[j] = p[i];
			// printf("%c\n",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

加载中
0
xu4v
xu4v

错误有两处,

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

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  %d\n",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("%C\n",p[i]);
		if (p[i]>='0' && p[i]<='9'){
			c[j] = p[i];
			// printf("%c\n",c[j]);
			++j;
		}else if (p[i]>='A' && p[i]<='Z')
		{
			c[j] = ((p[i]-65)/3)+48;
			++j;
		}
	}
	c[j] = '\0'; // #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;
}

独-奏
独-奏
回复 @xu4v : 再add_list()中传的是另一个char *c的首地址啊,c是一个函数中的局部变量,在第二次执行dosomething()时难道不是重新申请空间么?大哥的意思是,执行两次dosomething()中调用的add_list()传的参数c指向的是同一个地址,也就是说char *c没有被释放?
xu4v
xu4v
回复 @独-奏 : 这是因为num为 char* 型,char*只是一个指针,它只指向字符串实际地址,并不保存字符串上的那些字符;而你的程序中2次传给它的都是main中char ch[20]的首地址。这两次的num所指的都是这个ch[20],而这个ch[20]的值被修改了
独-奏
独-奏
不才还是不太明白,为何会出现链表中节点数目正常,但是每个节点的值都是最后一次的结果这种情况,希望能给解释一下~Thanks !
0
xu4v
xu4v
#5 num为char*型,最好命名为 str
0
xu4v
xu4v

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


0
中山野鬼
中山野鬼
这代码写的,是不是楼主抄书的???哈。
独-奏
独-奏
不是抄书~不才学过一年c++,对c的精髓指针还不太理解,想借此机会补补c的知识,献丑了~
0
中山野鬼
中山野鬼

 ++j; 能不用就不用。、malloc 尽可能归整到一个函数里,这样便于你对malloc free进行测试。

(structtell *)malloc(sizeof(structtell)) 有这种情况发生,则尽快用typedef 替换掉,省得书写错误。

voidpri_list() 尽可能加static 表示是局部函数,否则以外调用,会因为head为空而出问题。

(p[i]>='0'&& p[i]<='9')

记得()都加上。

 scanf("%d",&count); 尽可能不要用,从文件IO口读取输入数据,养成管道来去的好习惯,测试时,键盘最多是输入参数,但不是入口数据。

其他暂时没什么意见了。。哈。


独-奏
独-奏
回复 @中山野鬼 : 多谢~以后多指教~
中山野鬼
中山野鬼
回复 @独-奏 :你肯学,我就肯教,从来不强迫人。哈。
独-奏
独-奏
牢记鬼哥指点,不瞒鬼哥~不才顶多也就大一时间一年的c++学龄,而且还是再学校环境下~如今学习c其实是为了想参加acm大赛,现在看来c果然是够“低级”,以至于我这等做“高级”语言的头大啊~
0
小吃店
小吃店

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

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

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

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

0
陶邦仁
陶邦仁

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

0
fcsong000833
fcsong000833

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

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

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

0
独-奏
独-奏

@小吃店 @fcsong000833 @爪哇老妖

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

返回顶部
顶部