我正在开发一个程序,其目标是从文件中读取字符串并仅打印大写字母。我的代码如下:
#include <stdio.h>
#include <string.h> //enables the use of string functions
#define BUFFER_SIZE 25 //limits string to 25 characters
#define INPUT_FILE "l6p2.txt"
//Function prototypes
char extractCaps(char *str);
int main()
{
//Create an array that can hold 25 characters
char string[BUFFER_SIZE] = { 0 };
//Open the text file
FILE *fp = NULL;
fp = fopen(INPUT_FILE, "r"); //read only
//Scan string from the file
fscanf(fp, "%s", string);
//Call the function and pass the string from the file as the parameter
extractCaps(string);
printf("%s", string);
return 0;
}
//Recursive function that will extract capital letters from a string
char extractCaps(char *str)
{
static int i=0;
if(i < strlen(str))
{
//Base case (if the string is empty)
if (str[i] == '\0') // \0 is a character that is automatically added at the end of a string
{
return;
}
else if((str[i] >= 65 && str[i] <= 90)) //if the letter at this index is capital (ASCII codes for A and Z)
{
return str[i];
i++;
}
else //if not a capital letter
{
//Recursive call... move to the next letter and repeat the above steps
i++;
return extractCaps(str);
}
}
printf("\n");
}
l6p2.txt
文件包含字符串"hHeElLlLoO"
。因此,我希望输出为"HELLO"
,但我的代码仍在输出整个字符串"hHeElLlLoO"
。当我在printf
函数中有extractCaps
语句时,我原来的代码工作正常,但我被告知要更改它以便在main
中进行打印。对于我的生活,我无法理解为什么这段代码表现不正确。这个逻辑对我来说很有意义,但是我再也不知道对编程的蹲坐了。
作为旁注,我听说将静态变量与递归相结合是一个坏主意,所以我尝试使用i
作为extractCaps
的参数,但仍然得到相同(不正确)的输出。
我哪里错了?
编辑:要求extractCaps
是递归函数。
答案 0 :(得分:2)
虽然你已经有了答案,但是有一些事情要考虑未来。首先,当您打开一个文件进行阅读始终验证开放实际上是否成功:
/* Open the text file AND VALIDATE */
FILE *fp = NULL;
if (!(fp = fopen ("filename.txt", "r"))) {
fprintf (stderr, "error: file open failed '%s'.\n", "filename.txt");
return 1;
}
如果只是将文件名作为参数传递给程序,则可以使代码更加灵活,而不是在代码中对"filename.txt"
进行硬编码。这是int main (int argc, char **argv)
main
参数的目的。它只需要额外的努力:
int main (int argc, char **argv)
{
...
/* validate sufficient input on command line (filename) given */
if (argc < 2) {
fprintf (stderr, "error: insufficient input. usage: %s filename",
argv[0]);
return 1;
}
/* Open the text file AND VALIDATE */
FILE *fp = NULL;
if (!(fp = fopen (argv[1], "r"))) {
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
...
虽然您可以使用fscanf
读取字符串,但尝试使用Xscanf
函数族进行输入时会涉及许多陷阱。 (他们有自己的位置,但对于一般阅读,有更好的选择)
在阅读文件时,您通常要考虑使用C标准库提供的面向行的输入函数之一,如fgets
或getline
。一般方法是一次读取一行到缓冲区,然后解析缓冲区的内容以获取所需的信息。一次读取一行并不比一次读取一个字符串困难,但它更不容易出错,例如:
/* read each line in file into buf
* BUFFER_SIZE set to 256 (or as needed)
*/
while (fgets (buf, BUFFER_SIZE, fp))
extractCaps (string, buf, &stridx);
在这种情况下,您需要以某种方式将所有大写字母收集到第二个缓冲区中,以便在文件读取完成后保存它们以进行打印。当然,使用单行文件几乎没有必要,但由于这些只是提示,让我们考虑一下你的文件是否超过一行,例如:
hHeElL
lLoO
然后呢?在这种情况下,您将读取一行,然后将该行传递给extractCaps。然后,extractCaps将以递归方式扫描该行,或者只是使用指针逐步遍历每个字符,测试每个字符以确定它是否为大写,然后将字符保存在字符串中,并将字符串索引递增1(所以它会知道在哪里保存下一个)。通过使用单独的缓冲区来保存大写字母,您可以处理具有任意行数的输入文件。
每当您填充固定大小的任何类型缓冲区时,您需要检查缓冲区是否已满,并且如果是,则采取适当的操作。 (写入超出缓冲区的末尾是遇到麻烦的可靠方法。)
最后,您需要一种方法来跟踪在调用extractCaps之间在缓冲区中写下一个Capital的位置的索引。有几种方法。您可以让函数返回索引号并以这种方式跟踪它 - 或者 - 您可以将指针作为参数传递给extractCaps,以便在main
中的extractCaps中更新值。将所有这些部分放在备用extractCaps
函数中,它可能看起来像:
/* simple function to extract capital letters from 'buf' and save in 'str'
updating the index 'idx' to reflect the number of chars in string */
void extractCaps (char *str, char *buf, size_t *idx)
{
if (!buf || !str || !idx) { /* validate parameters */
fprintf (stderr, "extractCaps() error: invalid parameter.\n");
return;
}
char *p = buf; /* pointer to buf */
while (*p) { /* for each char in buf */
if ('A' <= *p && *p <= 'Z') {
if (*idx == BUFFER_SIZE - 1) { /* check idx against BUFFER_SIZE */
fprintf (stderr, "extractCaps() error: BUFFER_SIZE reached.\n");
return;
}
str[(*idx)++] = *p; /* copy CAP to str, increment idx */
}
p++;
}
}
采取下一步并将所有部分放在一起,这是解决问题的另一种方法。这只是未来需要考虑的事项,用于比较目的,以及以面向行的方式读取文件的示例:
#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 256 /* limits line to 256 characters */
/* Function prototypes */
void extractCaps (char *str, char *buf, size_t *idx);
int main (int argc, char **argv)
{
/* Create an array that can hold 25 characters */
char buf[BUFFER_SIZE] = { 0 };
char string[BUFFER_SIZE] = { 0 };
size_t stridx = 0;
/* validate sufficient input on command line (filename) given */
if (argc < 2) {
fprintf (stderr, "error: insufficient input. usage: %s filename",
argv[0]);
return 1;
}
/* Open the text file AND VALIDATE */
FILE *fp = NULL;
if (!(fp = fopen (argv[1], "r"))) {
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* read each line in file into buf */
while (fgets (buf, BUFFER_SIZE, fp))
extractCaps (string, buf, &stridx);
/* print the results in string */
printf("\nAll caps in file : %s\n\n", string);
return 0;
}
/* simple function to extract capital letters from 'buf' and save in 'str'
updating the index 'idx' to reflect the number of chars in string */
void extractCaps (char *str, char *buf, size_t *idx)
{
if (!buf || !str || !idx) { /* validate parameters */
fprintf (stderr, "extractCaps() error: invalid parameter.\n");
return;
}
char *p = buf; /* pointer to buf */
while (*p) { /* for each char in buf */
if ('A' <= *p && *p <= 'Z') {
if (*idx == BUFFER_SIZE - 1) { /* check idx against BUFFER_SIZE */
fprintf (stderr, "extractCaps() error: BUFFER_SIZE reached.\n");
return;
}
str[(*idx)++] = *p; /* copy CAP to str, increment idx */
}
p++;
}
}
输入文件
$ cat dat/hellocaps.txt
hHeElLlLoO
使用/输出强>
$ ./bin/extract_caps dat/hellocaps.txt
All caps in file : HELLO
答案 1 :(得分:1)
以下是解决方案,基本上您只需要检查fgetc
中的字符是否在大写字母A到Z字母的ASCII值范围65到90范围内。
#include<stdio.h>
#pragma warning(disable : 4996)
int main()
{
FILE *pfile;
int data;
pfile = fopen("test.txt", "r");
printf("Opening file...\n");
if (pfile == NULL)
{
printf("Error!\n");
}
while ((data = fgetc(pfile)) != EOF)
{
if (data>=65 && data<=90)//ascii values 65 to 90 represent
{ //Upper Case Letters A to Z.
printf("%c\n", data);
}
}
fclose(pfile);
return 0;
}
以下是Ascii Table ASCII Table的链接。
答案 2 :(得分:1)
您的固定代码
#include <stdio.h>
#include <string.h> //enables the use of string functions
#define BUFFER_SIZE 25 //limits string to 25 characters
#define INPUT_FILE "l6p2.txt"
//Function prototypes
void extractCaps(char *str, char* ostr, int iPos, int iCurrPos);
int main()
{
//Create an array that can hold 25 characters
char string[BUFFER_SIZE] = { 0 };
char ostring[BUFFER_SIZE] = { 0 };
//Open the text file
FILE *fp = NULL;
fp = fopen(INPUT_FILE, "r"); //read only
//Scan string from the file
fscanf(fp, "%s", string);
//Call the function and pass the string from the file as the parameter
extractCaps(string, ostring, 0, 0);
printf("%s",ostring);
return 0;
}
//Recursive function that will extract capital letters from a string
void extractCaps(char *str, char* ostr, int iPos, int iCurrPos)
{
if (iPos < strlen(str))
{
if((str[iPos] >= 65 && str[iPos] <= 90)) //if the letter at this index is capital (ASCII codes for A and Z)
{
ostr[iCurrPos] = str[iPos];
extractCaps(str, ostr, iPos + 1, iCurrPos + 1);
}
else
extractCaps(str, ostr, iPos + 1, iCurrPos);
}
}
我强烈建议你避免在这样的函数中使用静态变量,因为如果第二次使用这个函数,你将收到超出边界错误的索引,这在C中很难找到。