所以我正在努力解决CS50中首字母问题的“不太舒服”版本,并且从非常详细的代码开始,我已经设法将其简化为:
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int c = 0;
int main(void)
{
string name = get_string();
int n = strlen(name);
char initials[10];
// first letter is always going to be the first initial
initials[0] = name[0];
// count through letters looking for spaces + add the first letter after a
// space to the initials array
for (int j = 0; j < n; j++)
{
if (name[j] == 32)
{
c += 1;
initials[c] += name[j+1];
}
}
// print out initials
for (int k = 0; k <= c; k++)
{
printf("%c", toupper(initials[k]));
}
printf("\n");
}
就像它经过的那样,但是我觉得我正在考虑一点cos我只是从空中选择[10]以获得最初的阵列大小,我知道这不是一个好习惯。为了使它更好'我'试图运行'for'循环迭代通过名称字符串并添加空格数。然后,我想使数组[空格+ 1]好像有2个空格,然后将有3个首字母。我正在尝试的代码是:
string name = get_string();
int n = strlen(name);
for (int i = 0; i < n; i++)
{
if (name[i] == 32)
{
spaces +=1;
}
}
我的想法是,然后我在下一行创建'char initials [spaces + 1]',但即使在我能做到这一点之前,只使用这个'for'循环编译我的代码,当我上传它时返回失败检查(虽然它编译没有问题)。即使我不使用任何'for'循环输出,仅仅是因为它会给我这个错误。
我哪里错了?
对此的任何帮助都将非常感激。
谢谢!
答案 0 :(得分:1)
首先,请记住,执行速度通常比内存使用更有价值。如果你先去寻找空格,然后分配内存,你必须遍历数组两次。这是以执行速度为代价的内存使用优化。因此,仅仅分配一个“足够大”的数组,让100个字符并保留您拥有的代码可能更有意义。
然后我想让数组[spaces + 1]好像有2个空格然后会有3个首字母
请记住,C字符串是空终止的,因此您还需要为空终止符spaces + 1 + 1
分配空间。
使用这个'for'循环编译我的代码,当我上传它以进行检查时返回失败(虽然它编译没有问题)。即使我不使用任何'for'循环输出,仅仅是因为它会给我这个错误。
什么错误?它是编译还是不编译,你的文本是矛盾的。
确保将spaces
初始化为零。
作为旁注,切勿在C代码中使用“幻数”。 if (name[i] == 32)
,32对任何无法通过内存引用ASCII表的人都是胡言乱语。此外,对于具有可能不具有相同索引号的其他符号表的系统,它是不可移植的。而是写:
if (name[i] == ' ')
答案 1 :(得分:0)
在我看来,迎合这种情况的好方法是库函数snprintf
使用的方法:它要求你传入要填充的字符串和该字符串的大小。 In确保不覆盖字符串并且字符串为零终止。
如果字符串足够大,该函数返回写入字符串的字符的长度。您现在可以执行以下两项操作之一:猜测合理的缓冲区大小,并接受偶尔缩短字符串的时间。或者调用长度为零的函数,使用返回值分配一个char缓冲区,然后用第二次调用填充它。
将此方法应用于首字母缩写问题:
int initials(char *ini, int max, const char *str)
{
int prev = ' '; // pretend there's a space before the string
int n = 0; // actual number of initials
while (*str) {
if (prev == ' ' && *str != ' ') {
if (n + 1 < max) ini[n] = *str;
n++;
}
prev = *str++;
}
if (n < max) {
ini[n] = '\0';
} else if (max > 0) {
ini[max] = '\0';
}
return n;
}
然后您可以使用固定大小的缓冲方法:
char *name = "Theodore Quick Brown Fox";
char ini[4];
initials(ini, sizeof(ini), name);
puts(ini); // prints "TQB", "F" is truncated
或两步动态尺寸方法:
char *name = "Theodore Quick Brown Fox";
int n;
n = initials(NULL, 0, name);
char ini[n + 1];
initials(ini, sizeof(ini), name);
puts(ini); // prints "TQBF"
(请注意,initals
的这种实现将忽略字符串末尾或开头的多个空格和空格。在这些情况下,您的前瞻功能将插入空格。)
答案 2 :(得分:0)
您知道您的initials
数组不能比名称本身更大;至多,它不能超过一半(每隔一个字符就是一个空格)。所以使用它作为你的尺寸。最简单的方法是使用可变长度数组:
size_t n = strlen( name ); // strlen returns a size_t type, not int
char initials[n/2+1]; // n/2+1 is not a *constant expression*, so this is
// a variable-length array.
memset( initials, 0, n + 1 ); // since initials is a VLA, we can't use an initializer
// in the declaration.
唯一的问题是VLA支持可能是不确定的 - 在C99中引入了VLA,但在C2011中是可选的。
或者,您可以使用动态分配的缓冲区:
#include <stdlib.h>
...
size_t n = strlen( name );
char *initials = calloc( n/2+1, sizeof *initials ); // calloc initializes memory to 0
/**
* code to find and display initials
*/
free( initials ); // release memory before you exit your program.
虽然,如果您只需要显示首字母,那么就没有理由存储它们 - 只需在找到它们时打印它们。
与其他人建议的一样,使用字符常量' '
而不是ASCII代码32
来与空格进行比较:
if ( name[j] == ' ' )
或使用isspace
库函数(对于空格,制表符,换行符等将返回true):
#include <ctype.h>
...
if ( isspace( name[j] ) )