fmd*_*dub 2 c segmentation-fault
我很抱歉,如果这是浪费时间和/或不应该在这个网站上应该是什么,但我有点想法...我仍然是编程新手,无法掌握我的老师为了指导,所以...到互联网!
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void months( FILE* monthfp, char** monthGroup );
int main (void){
FILE *monthfp; /*to be used for reading in months from months.txt*/
char** monthGroup;
int i;
if (( monthfp = fopen ( "months.txt", "r" )) == NULL ){
printf( "unable to open months.txt. \n" );
exit ( 1 );
}
months( monthfp, monthGroup );
/*test so far*/
for ( i = 0; i < 12; i++ ){
printf( "%s", monthGroup[i] );
}
fclose( monthfp );
}
void months ( FILE* monthfp, char** monthGroup ){
/*****************************************
name: months
input: input file, data array
returns: No return. Modifies array.
*/
char buffer[50];
int count = 0;
while ( fgets( buffer, sizeof(buffer), monthfp ) != NULL ){
count++;
monthGroup = malloc( count * sizeof ( char* ));
monthGroup[count] = malloc( sizeof( buffer ) * sizeof( char ));
strcpy(monthGroup[ count - 1 ], buffer );
}
}
Run Code Online (Sandbox Code Playgroud)
我在C89编译,一切似乎都有效,除了分段错误.非常感谢任何指导.
编辑 感谢所有花时间提供一些洞察力的人,我一直无法理解.在异乡的一个长老村里,我感觉自己像个小孩子.非常感谢礼貌和指导.
我担心你没有意识到你做得多好.坐下来,这将是很长的.欢迎来到C.
char** monthGroup
Run Code Online (Sandbox Code Playgroud)
所有这些真正意味着"指向指针char".但是,C有许多原因可以指向某些内容.在你的情况下,"内部"指向是这样你实际上可以指向内存中的s 序列char(你通常将其视为"字符串",C正确地没有),而"外部"指向是这样的您可以指向那些char*s 的序列,并将该序列视为"数组"(即使它不是 ;您将动态分配它).
这就是问题所在:当你传入char**来自main它的内容时,它实际上并没有指向任何东西."那很好",你说; "该功能将使它指向我将分配的某些内存malloc()".
不.
C按值传递所有内容.在char**该months接收到的是一个副本中的char**在main局部变量的块.你覆盖指针(带有malloc调用的结果),写一些指向指向内存的指针(更多malloc结果),将一些数据复制到那些指向内存的块中......然后,在函数的末尾,参数monthGroup(它是一个局部变量months)不再存在,并且您丢失了所有数据,并且monthGroupmain中的变量在指向任何内容时仍然保持不变.当你试图使用它就像它指向什么东西一样,繁荣你已经死了.
那么我们如何解决这个问题呢?当然,对于另一个指向级别,C恰当地没有 "通过引用传递",所以我们必须伪造它.我们接受char***,并通过它&monthGroup.这仍然是一个复制值,但它直接指向main(在堆栈上)调用的局部变量存储.这让我们可以编写一个可见的值main.我们将第一个malloc结果分配给*monthGroup,并将指针写入该存储(*monthGroup[count])等.
除了我们真的不想这样做,因为它非常难看,令人困惑,很难做对.让我们做一些你应该做的非常明显的事情并且基本指令几乎不强调:使用函数的返回值来返回计算结果 - 这就是为什么它被称为返回值.
也就是说,我们设置了一个char**in months(不接受任何类型的参数),返回它,并用它来初始化值main.
我们完了吗?不.
您仍然有一些逻辑错误:
实际上,你确实想要做这样的事情,但这只是因为你事先并不知道你需要多少元素.问题是新的分配就是 - 一个新的分配 - 不包含先前设置的指针.
幸运的是,C有一个解决方案:realloc.这将分配新内存,复制旧内容(指向您分配的"字符串"的指针),并释放旧块.万岁!更好的是,如果我们为"旧记忆"给它一个NULL指针,realloc就会表现得像malloc.这让我们可以避免特殊的套管循环.
count错误地使用了该值.第一次通过循环,你将count增加到1,分配一些空间monthGroup[1]指向,然后尝试写入指向的空间monthGroup[0],这是从未设置过的.您想要为刚刚分配的"字符串"写入相同的空间.(BTW,sizeof(char)没用:它总是 1. 即使你的系统使用超过8位代表一个字符!这char是你系统上的基本存储单元.)除非没有,因为有一种更简单的方法:用于strdup获取指向缓冲区的已分配副本的指针.
char** months(FILE* monthfp) {
char buffer[50];
int count = 0;
char** monthGroup = NULL;
while (fgets(buffer, sizeof(buffer), monthfp) != NULL) {
// (re-)allocate the storage:
monthGroup = realloc(monthGroup, count * sizeof(char*));
// ask for a duplicate of the buffer contents, and put a pointer to the
// duplicate sequence into the last element of the storage:
monthGroup[count - 1] = strdup(buffer);
}
return monthGroup;
}
Run Code Online (Sandbox Code Playgroud)
调整main匹配留作(希望是微不足道的)练习.还请阅读文档realloc和strdup.
我们完了吗?没有.
你仍然应该检查NULL来自realloc和的返回strdup(因为它们都试图分配内存,因此可能在C中以这种方式失败),并且你仍然需要代码来free分配内存.
并且,正如其他人所指出的,你不应该假设将有12个月.如果你可以假设,你不会monthGroup在第一时间动态分配; 你只需要使用一个数组.所以你需要以某种方式传递结果"数组"的大小(向结尾添加一个显式的NULL指针是一种方式;另一种是做可怕的丑陋的事情,传入一个char***,并使用返回值来计算大小) .