我对fscanf的理解:
从文件中抓取一行并根据格式将其存储到字符串中。
话虽如此,有三种(看似不同的)方式传递"字符串"周围(字符数组)。
一些假设:
1. fp是一个有效的FILE指针
2.文件中有1行,内容为" Something"
char* temp = malloc(sizeof(char) * 1); // points to some small part in mem.
int resp = fscanf(fp,"%s", temp);
printf("Trying to print: %s\n",temp); // prints "Something" (that's what's in the file)
char temp[100]; // this buffer MUST be big enough, or we get segmentation fault
int resp = fscanf(fp,"%s", temp);
printf("Trying to print: %s\n",temp); // prints "Something" (that's what's in the file)
char* temp; // null pointer
int resp = fscanf(fp,"%s", temp);
printf("Trying to print: %s\n",temp); // Crashes, segmentation fault
因此出现了一些问题!
char temp[1];
)崩溃?编辑:
我很清楚你需要传递一个足够大的缓冲区来包含来自该行的数据,我想知道为什么它仍在工作并且在其他情况下不会崩溃。
答案 0 :(得分:2)
我对fscanf的理解:
从文件中获取一行并基于 格式,将其存储到字符串。
不,这包含一些严重而重要的错误观念。 fscanf()
按照指定的格式从文件中读取,以便为其第三个和后续参数指向的部分或全部对象赋值。它不一定读取整行,但另一方面,它可能读取不止一行。
在您的特定用法中,
int resp = fscanf(fp,"%s", temp);
,它试图跳过任何前导空格,包括但不限于空行和空行,然后将字符读入指向字符数组,直到第一个空格字符或文件末尾。在任何情况下它都不会消耗它填充数组内容的行的行终止符,但如果在至少一个非空白字符后面的行上有其他空格,它甚至都不会那么远(尽管不是您描述的特定样本输入中的案例。)
话虽如此,有三种(看似不同的)方式传递"字符串"周围(字符数组)。
字符串不是C中的实际数据类型。字符数组是,但这样的数组不是"字符串"在C意义上,除非它们包含至少一个空字符。此外,在这种情况下,大多数情况下C字符串函数仅对这些数组的部分进行操作,直到并包括第一个空值,因此最好将这些部分表示为"字符串"。
有多种方法可以获得可以被视为字符串的字符序列的存储空间,但只有一种方法可以传递它们:通过指向第一个字符的指针。无论是通过声明字符数组,字符串文字还是通过为其分配内存来获取存储,都只能通过指针访问 。即使通过将索引运算符[]
应用于数组变量的名称来声明char数组和访问元素,实际上仍然使用指针来访问内容。
- 为什么malloc为1的指针可以包含更长的文本?
醇>
指针除了自身之外不包含任何内容。它指向的空间包含其他任何内容,例如文本。如果只分配一个字节,则分配的空间只能包含一个字节。如果通过尝试写入指针所指向的较长字符序列来超出该一个字节,则调用未定义行为。特别是,C不保证会产生错误,或者程序将无法按预期运行,但是所有方式的 都可以无限制地发生。
- 由于指针内容似乎不重要,为什么空指针崩溃,我希望分配的指针崩溃为 好吧,因为它指的是一小段记忆。
醇>
尝试取消引用无效指针(包括但不限于空指针)也会产生未定义的行为。崩溃完全在可能的行为范围内。在这种情况下,C不保证崩溃,但是某些实现可靠地提供了这种情况。
- 为什么指针有效,但数组(char temp [1];)崩溃?
醇>
你没有演示你的单字符数组替代,但是再次,超越对象的边界 - 在这种情况下是一个数组 - 产生未定义的行为。它是 undefined 所以没有理由认为行为与超出已分配对象的边界相同,或者甚至其中任何一个行为都是一致的。
答案 1 :(得分:1)
话虽如此,有三种(看似不同的)方式传递"字符串"周围(字符数组)。
传递C - "字符串"至scanf()
&朋友只有一种方式:传递足够有效记忆的地址。
如果你没有代码会调用infamouse Undefined Behavior,这意味着任何事情都可能发生,从崩溃到看似正常运行。
答案 2 :(得分:0)
为什么malloc为1的指针可以包含更长的文本?
理论上讲,它不能不导致未定义的行为。但实际上,当你分配一个字节时,分配器会给你一小块它支持的最小大小的内存,这通常足够8..10个字符而不会导致崩溃。附加内存用作防止崩溃的“填充”(但它仍然是未定义的行为)。
另一方面,由于指针内容似乎不重要,为什么空指针崩溃,我希望分配的指针也会崩溃,因为它指向一小段内存。
空指针即使对于空字符串也是不够的,因为您需要空终止符。因此,它是一个有保证的UB,它在大多数平台上表现为崩溃。
为什么指针有效,但数组(
char temp[1]
)崩溃?
因为数组的分配没有任何额外的“填充”内存。请注意,无法保证崩溃,因为数组后面可能没有未使用的内存字节,您的字符串可能会损坏而不会产生任何后果。
答案 3 :(得分:0)
因为空指针没有分配内存。
当你请求一小段内存时,它是从名为" heap"的内存块中分配的。堆总是以块或页为单位进行分配和释放,总是比几个字节大一些,通常是几KB。
因此,当您使用new
或通过定义数组(小)分配内存时,您将在堆中获得一块内存。实际可用空间较大,可以(经常)超过您请求的数量,因此写入(和读取)比请求的数据更安全。但理论上,它是一个UB而应使程序崩溃。
创建空指针时,它指向0,无效地址,无法读取或写入。因此,它保证程序会崩溃,通常是由于分段错误。
小型阵列可能比new
和malloc
更频繁地崩溃,因为它们并不总是从堆中分配,并且可能会在之后没有任何额外空间,所以写超过限制更危险。但是,它们经常在未使用的(未分配的)内存区域之前,因此有时您的程序可能不会崩溃,而是会损坏数据。