神秘的神秘P

时间:2017-05-23 13:48:23

标签: c malloc realloc cs50

背景

我试图创建一个带有用户名的程序(假设输入是干净的),并打印出名称的首字母。

目标:

  • 尝试使用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 : %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的值都会显示出来。

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

谢谢!

1 个答案:

答案 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; } malloccalloc调用的结果,以确保在尝试访问该内存之前成功。

轻微的风格笔记:

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

getInput