c - 神秘的P之谜



背景:

我正在尝试创建一个程序,该程序采用用户名(假设输入是干净的),并打印出名称的首字母。

目的:

  • 尝试使用 CS50 进行 C 编程
  • 让自己熟悉 malloc & realloc

法典:

#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
string prompt(void);
char *getInitials(string input);
char *appendArray(char *output,char c,int count);
//Tracks # of initials
int counter = 0;
int main(void){
string input = prompt();
char *output = getInitials(input);
for(int i = 0; i < counter ; i++){
printf("%c",toupper(output[i]));
}

}
string prompt(void){
string input;
do{
printf("Please enter your name: ");
input = get_string();
}while(input == NULL);
return input;
}
char *getInitials(string input){
bool initials = true;
char *output;
output = malloc(sizeof(char) * counter);
for(int i = 0, n = strlen(input); i < n ; i++){
//32 -> ASCII code for spacebar
//9  -> ASCII code for tab
if(input[i] == 32 || input[i] == 9 ){
//Next char after spaces/tab will be initial
initials = true;

}else{//Not space/tab
if(initials == true){
counter++;
output = appendArray(output,input[i],counter);
initials = false;

}        
}
// eprintf("Input[i] is : %cn",input[i]);
// eprintf("Counter is : %in",counter);
// eprintf("i is : %in",i);
// eprintf("n is : %in",n);

}
return output;
}
char *appendArray(char *output,char c,int count){
// allocate an array of some initial (fairly small) size;
// read into this array, keeping track of how many elements you've read;
// once the array is full, reallocate it, doubling the size and preserving (i.e. copying) the contents;
// repeat until done.

//pointer to memory
char *data = malloc(0);
//Increase array size by 1
data = realloc(output,sizeof(char) * count);
//append the latest initial
strcat(data,&c);
printf("Value of c is :%cn",c);
printf("Value of &c is :%sn",&c);
for(int i = 0; i< count ; i++){
printf("Output: %cn",data[i]);
}
return data;
}

问题:

输出不是我预期的,因为输出中出现了一个神秘的 P。

例如,当我输入巴拉克·奥巴马这个名字时,我得到的结果不是 result:BO,而是得到结果 BP,无论我选择输入什么名字,都会发生同样的情况,最后一个首字母总是 P。

输出:

Please enter your name: Barack Obama
Value of c is :B
Value of &c is :BP
Output: B
Value of c is :O
Value of &c is :OP
Output: B
Output: P
BP

我做了什么:

我已经将问题追溯到appendArray函数,更具体地说是&c(c的地址)的值,尽管我不知道是什么导致P出现,它是什么意思,为什么出现以及如何摆脱它。

无论我何时输入,P 的值都会显示。

关于它为什么会发生以及我能做些什么来解决它的见解将不胜感激。

谢谢!

几个问题,按重要性降序排列...

第一个问题 -appendArray中的c不是字符串- 它不是以 0 结尾的字符值序列c是单个char对象,存储单个char值。

当您尝试将c打印为字符串时,如

printf("Value of &c is :%sn",&c);

printf写出从c地址开始的字符值序列,直到看到 0 值字节。无论出于何种原因,紧跟在c后面的字节包含值 80,这是字符'P'的 ASCII(或 UTF-8)代码。 下一个字节包含 0(或者有一个字节序列包含不可打印的字符,后跟一个 0 值字节)。

同样,使用&c作为strcat参数是不合适的,因为c不是字符串。 相反,你应该做一些类似的事情

data[count-1] = c;

其次,如果要将data数组视为字符串,则必须确保其大小至少比首字母数多 1,并将 0 写入最终元素:

data[count-1] = 0; // after all initials have been stored to data

第三

char *data = malloc(0);

没有任何用途,该行为是实现定义的,并且您立即通过调用realloc来覆盖malloc(0)的结果:

data = realloc(output,sizeof(char) * count);

所以,完全摆脱malloc(0)调用;要么只是将data初始化为NULL,要么用realloc调用初始化它:

char *data = realloc( output, sizeof(char) * count );

第四,避免使用"幻数"——其意义超出其直接文字值的数字常量。 如果要与字符值进行比较,请使用字符常量。 欠条,改变

if(input[i] == 32 || input[i] == 9 ){

if ( input[i] == ' ' || input[i] == 't' )

这样,您就不必担心字符编码是ASCII,UTF-8,EBCDIC还是其他系统。' '意味着无处不在的空间't'意味着无处不在的选项卡

最后。。。

我知道你做这个练习的部分动机是熟悉mallocrealloc,但我想提醒你一些事情:

realloc操作可能成本高昂,它可能会将数据移动到新位置,并且可能会失败。 您真的不想一次realloc一个字节的缓冲区。 相反,最好分块realloc。 典型的策略是将当前缓冲区大小乘以 1>的某个系数(通常加倍):

char *tmp = realloc( data, current_size * 2 );
if ( tmp )
{
current_size *= 2;
data = tmp;
}

在尝试访问该内存之前,应始终检查malloccallocrealloc调用的结果,以确保其成功。

小文体笔记:

尽可能避免使用全局变量。 没有理由counter应该是全局的,特别是因为您将其作为参数传递给appendArray。 将其声明为本地main并将其作为参数(通过引用)传递给getInput

int main( void )
{
int counter = 0;
...
char *output = getInitials( input, &counter );
for(int i = 0; i < counter ; i++)
{
printf("%c",toupper(output[i]));
} 
...
}
/**
* The "string" typedef is an abomination that *will* lead you astray,
* and I want to have words with whoever created the CS50 header.
*
* They're trying to abstract away the concept of a "string" in C, but 
* they've done it in such a way that the abstraction is "leaky" - 
* in order to use and access the input object correctly, you *need to know*
* the representation behind the typedef, which in this case is `char *`.
*
* Secondly, not every `char *` object points to the beginning of a 
* *string*.    
*
* Hiding pointer types behind typedefs is almost always bad juju.  
*/
char *getInitials( const char *input, int *counter ) 
{
...
(*counter)++;                                   // parens are necessary here
output = appendArray(output,input[i],*counter); // need leading * here
...
}

相关内容

  • 没有找到相关文章

最新更新