根据您的评论,我假设C中有一些基本概念
你还没有完全理解。
C字符串
C字符串是字节序列。此序列
必须
以值0结束。
序列中的每个值表示一个基于
ASCII
编码,例如
性格
'a'
是97,
'b'
是98等字符
'\0'
有
值0,该字符决定字符串的结尾。
这就是为什么您经常听到C字符串以“\0”结尾的原因。
在C中,使用字符数组(
char string[]
,
char string[SOME VALUE]
)至
保存字符串。对于一串长度
n
,您需要一个维度数组
n+1
因为
您还需要一个空间用于终止
'\0'
性格
在处理字符串时,必须始终考虑正确的类型,
您使用的是数组还是指针。指针
到char并不一定意味着您正在处理一个C字符串!
我为什么要告诉你这些?因为:
char inputChoice = 0;
printf("Do you wish to save the Input? (Y/N)\n");
scanf("%s", &inputChoice);
我没什么变化,在尝试了一段时间后,我变得非常缺乏动力。
我改变了
%s
至
%c
在
scanf(" %c, &inputChoice)
还有那个
似乎阻止了程序崩溃。
这表明他们还不了解
%s
和
%c类
.
这个
%c类
转换说明符字符指示
scanf
它必须匹配单个字符,并且它需要一个指向
char
.
曼斯坎夫
c
匹配长度由最大字段指定的字符序列
宽度(默认值为1);
下一个指针必须是
指向char的指针,并且必须有足够的空间容纳所有字符
(未添加终止空字节)。
通常跳过
前导空格被抑制。要首先跳过空白,请在格式中使用显式空格。
忘了长度吧,现在不重要了。
重要部分用粗体表示。对于格式
scanf("%c"
,函数
需要指向的指针
烧焦
它不会写终止
'\0'
字符,它将不是C字符串。如果你想读一个字母和一个
仅限信函:
char c;
scanf("%c", &c);
// also possible, but only the first char
// will have a defined value
char c[10];
scanf("%c", c);
第一个很容易理解。第二个更有趣:这里
您有一个数组
烧焦
尺寸为10(即它能容纳10
烧焦
s) 。
scanf公司
将匹配一封信并将其写在
c[0]
. 但结果不会是
C字符串,不能传递给
puts
也不适用于预期
C字符串(如
strcpy
).
这个
%s
转换说明符字符指示
scanf公司
它必须匹配一系列非空白字符
曼斯坎夫
s
匹配一系列非空白字符;
下一个指针必须是
指向字符数组的初始元素的指针,该元素的长度足以
保持输入序列和终止空字节(
'\0'
),已添加
自动地
这里的结果将是保存一个C字符串。你也必须有足够的
保存字符串的空间:
char string[10];
scanf("%s", string);
如果字符串匹配9个或更少的字符,一切都会很好,因为
对于长度为9的字符串,需要10个空格(不要忘记终止
'\0'
). 如果字符串匹配的字符数超过9个,您将没有足够的字符
缓冲区中的空间和缓冲区溢出(访问超出大小)发生。
这是一种未定义的行为,任何事情都可能发生:您的程序可能
崩溃,您的程序可能不会崩溃,但会覆盖另一个变量,因此
控制你程序的流程,甚至可能在某处杀死一只小猫,是吗
你真的想杀小猫?
那么,你明白为什么你的代码错了吗?
char inputChoice = 0;
scanf("%s", &inputChoice);
inputChoice
是一个
烧焦
变量,它只能保存
1.
价值
&inputChoice
为您提供
输入选择
变量,但
char之后是越界的,如果您读/写它,您将有一个
溢出,所以你杀了一只小猫。即使只输入1个字符,也会
至少写2个字节,因为它只有一个字符的空间,小猫就会死。
那么,让我们来谈谈您的代码。
从用户的角度来看:为什么我要输入几行文字,可能是很多行文字
然后回答“不,我不想保留台词”。这没有意义
我
在我看来,您应该首先询问用户是否要保存
首先输入,然后
然后
询问输入。如果用户不想保存
任何内容,那么要求用户在
全部的但这只是我的观点。
如果你真的想坚持你的计划,那么你必须保存每一行
当用户结束输入数据时,您会询问并保存文件。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFERLEN 1024
void printFile () {
int i;
char openFile[BUFFERLEN];
FILE *file;
printf("What file do you wish to write in?\n");
scanf("%s", openFile);
getchar();
file = fopen(openFile, "w");
if (file == NULL) {
printf("Could not open file.\n");
return;
}
// we save here all lines to be saved
char **lines = NULL;
int num_of_lines = 0;
char buffer[BUFFERLEN];
printf("Enter an empty line of -1 to end input\n");
// for simplicity, we assume that no line will be
// larger than BUFFERLEN - 1 chars
while(fgets(buffer, sizeof buffer, stdin))
{
// we should check if the last character is \n,
// if not, buffer was not large enough for the line
// or the stream closed. For simplicity, I will ignore
// these cases
int len = strlen(buffer);
if(buffer[len - 1] == '\n')
buffer[len - 1] = '\0';
if(strcmp(buffer, "") == 0 || strcmp(buffer, "-1") == 0)
break; // either an empty line or user entered "-1"
char *line = strdup(buffer);
if(line == NULL)
break; // if no more memory
// process all lines that already have been entered
char **tmp = realloc(lines, (num_of_lines+1) * sizeof *tmp);
if(tmp == NULL)
{
free(line);
break; // same reason as for strdup failing
}
lines = tmp;
lines[num_of_lines++] = line; // save the line and increase num_of_lines
}
char inputChoice = 0;
printf("Do you wish to save the Input? (Y/N)\n");
scanf("%c", &inputChoice);
getchar();
if (inputChoice == 'Y' || inputChoice == 'y') {
for(i = 0; i < num_of_lines; ++i)
fprintf(file, "%s\n", lines[i]); // writing every line
printf("Your file has been saved\n");
printf("Please press any key to continue");
getchar();
}
// closing FILE buffer
fclose(file);
// free memory
if(num_of_lines)
{
for(i = 0; i < num_of_lines; ++i)
free(lines[i]);
free(lines);
}
}
int main(void)
{
printFile();
return 0;
}
规范备注
我使用了与您相同的代码作为我的基本代码,以便您可以发现
差异更快。
-
我使用宏
BUFFERLEN
用于声明缓冲区的长度。那是
我的风格。
-
看看
fgets
生产线:
fgets(buffer, sizeof buffer, stdin)
我在这里使用
sizeof buffer
而不是1024或
缓冲区
. 再说一次,那是我的
但是我认为这样做更好,因为即使你改变尺寸
通过更改宏或使用其他显式大小,
缓冲区大小
将始终返回正确的大小。请注意,这仅在以下情况下有效
buffer
是一个数组。
-
功能
strdup
返回指针指向新字符串的指针
复制参数。它用于创建字符串的新副本。什么时候
使用此功能时,不要忘记必须使用
free()
.
strdup标准
不是标准库的一部分,它符合
至SVr4、4.3BSD、POSIX。1-2001. 如果您使用Windows(我不使用Windows,
我不熟悉Windows生态系统),此功能可能不
目前在这种情况下,您可以自己编写:
char *strdup(const char *s)
{
char *str = malloc(strlen(s) + 1);
if(str == NULL)
return NULL;
strcpy(str, s);
return str;
}