背景
我试图创建一个带有用户名的程序(假设输入是干净的),并打印出名称的首字母。
目标:
代码:
#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 : %c\n",input[i]);
// eprintf("Counter is : %i\n",counter);
// eprintf("i is : %i\n",i);
// eprintf("n is : %i\n",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 :%c\n",c);
printf("Value of &c is :%s\n",&c);
for(int i = 0; i< count ; i++){
printf("Output: %c\n",data[i]);
}
return data;
}
问题:
输出不是我预期的,因为输出中出现了一个神秘的P。
当我输入名称Barack Obama时,而不是得到结果: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函数,更具体地说是&amp; c(c的地址)的值,虽然我不知道导致P出现的是什么,这意味着什么,为什么它出现以及如何摆脱它。
无论我何时输入,P的值都会显示出来。
对于为什么会发生以及我能做些什么来解决它的见解将不胜感激。
谢谢!
答案 0 :(得分:3)
有几个问题,按重要性递减顺序......
第一个问题 - c
中的appendArray
不是字符串 - 它不是由<0>终止的字符值的序列。{ {1}}是一个c
个对象,存储一个char
值。
当您尝试将char
打印为字符串时,如
c
printf("Value of &c is :%s\n",&c);
写出从printf
地址开始直到看到0值字节的字符值的序列。 无论出于何种原因,紧跟在c
之后的字节包含值80,它是字符c
的ASCII(或UTF-8)代码。下一个字节包含0(或者包含不可打印字符的字节序列,后跟0值字节)。
同样,使用'P'
作为&c
的参数是不合适的,因为strcat
不是字符串。相反,你应该做类似
c
其次,如果要将data[count-1] = c;
数组视为字符串,则必须确保将其大小设置为至少比首字母数量多1,并将0写入最终元素:
data
第三,
data[count-1] = 0; // after all initials have been stored to data
没有用处,行为是实现定义的,并且立即通过调用char *data = malloc(0);
覆盖malloc(0)
的结果:
realloc
所以,完全摆脱data = realloc(output,sizeof(char) * count);
电话;要么只是将malloc(0)
初始化为data
,要么使用NULL
调用进行初始化:
realloc
第四,避免使用&#34;魔术数字&#34; - 数值常量,其含义超出其直接的字面值。如果要与字符值进行比较,请使用 character 常量。 IOW,改变
char *data = realloc( output, sizeof(char) * count );
到
if(input[i] == 32 || input[i] == 9 ){
这样您就不必担心字符编码是ASCII,UTF-8,EBCDIC还是其他系统。 if ( input[i] == ' ' || input[i] == '\t' )
表示 space 无处不在,' '
表示标签无处不在。
...最后
我知道您参与此练习的部分动机是熟悉'\t'
和malloc
,但我想提醒您一些事情:
realloc
可能是一项昂贵的操作,可能将数据移至新位置,可能失败。你真的不想一次realloc
缓冲区一个字节。相反,它在块中realloc
更好。典型的策略是将当前缓冲区大小乘以某个因子> 1(通常加倍):
realloc
您应该始终检查char *tmp = realloc( data, current_size * 2 );
if ( tmp )
{
current_size *= 2;
data = tmp;
}
,malloc
或calloc
调用的结果,以确保在尝试访问该内存之前成功。
轻微的风格笔记:
尽可能避免使用全局变量。没有理由realloc
应该是全局的,特别是因为你将它作为参数传递给counter
。将其声明为appendArray
的本地,并将其作为参数(通过引用)传递给main
:
getInput