C ++奇怪的字符打印到屏幕上

时间:2015-02-08 22:17:05

标签: c++

谢谢sp2danny的回答!

HEADER FILE:

#ifndef EMPLOYEERECORD_H
#define EMPLOYEERECORD_H

#include <iostream>
#include <string>
using namespace std;

class EmployeeRecord
{
    char m_sLastName[31];  // employee last name
    char m_sFirstName[31]; // employee first name

    EmployeeRecord();     // default constructor
    EmployeeRecord(int ID, char *fName, char *lName, int dept, double sal);
};

#endif

SOURCE FILE:

#include "EmployeeRecord.h"

//constructor 1 (default)
EmployeeRecord::EmployeeRecord()
{
    m_iEmployeeID = 0;
    m_sLastName == "";
    m_sFirstName == "";
    m_iDeptID = 0;
    m_dSalary = 0.0;
}

// this constructor shall set the member variables to the values passed into the function
EmployeeRecord::EmployeeRecord(int ID, char *fName, char *lName, int dept, double sal)
{
    unsigned int i = 0;
    m_iEmployeeID = ID;
    for (i = 0; i < 31; i++)
    {
        m_sFirstName[i] = *(fName + i);
        m_sLastName[i] = *(lName + i);
    }
    m_iDeptID = dept;
    m_dSalary = sal;
}

// destructor - cleans up and deallocates any memory that pointers within this class may have referenced to
EmployeeRecord::~EmployeeRecord(){};


// this function shall print to the screen all data found in the employee's record
void EmployeeRecord::printRecord()
{
    cout << "Employee ID:     " << m_iEmployeeID << endl;
    cout << "First Name:      " << m_sFirstName << endl;
    cout << "Last Name:       " << m_sLastName << endl;
    cout << "Department ID:   " << m_iDeptID << endl;
    cout << "Salary:        $ " << m_dSalary << endl;
}

我如何打电话:

/*******************************************************************
*   main function for project Prog1
*******************************************************************/

#include <stdio.h>
#include <time.h>
#include <cstdlib>
#include <stdlib.h>
#include <windows.h>

#include <string>
#include <iostream>
using namespace std;

#include "EmployeeRecord.h"

int main(void)
{

    int answer, employee_id, dept_id;
    unsigned int i;
    char  firstname[31], lastname[31];
    double *salary, _salary;

    salary = &_salary;


    EmployeeRecord Employee1 = EmployeeRecord();
    firstname[0] = 'J';
    firstname[1] = 'h';
    firstname[2] = 'o';
    firstname[3] = 'n';
    firstname[4] = 'n';
    firstname[5] = 'y';
    lastname[0] = 'D';
    lastname[1] = 'o';
    lastname[2] = 'e';
    lastname[3] = 'b';
    lastname[4] = 'e';
    lastname[5] = 'r';
    EmployeeRecord Employee2 = EmployeeRecord(0, firstname, lastname, 0, 0.0);
    Employee2.printRecord();
    system("pause");

所以说我已经将m_sFirstName设置为&#34; Johnny&#34;和m_sLastName等于&#34; Doeber&#34;其中m_sFirstName [0] =&#39; J&#39;,m_sLastName =&#39; D&#39;等... 每次调用printRecord函数时,都会得到以下结果:

Fist Name: Johnny########################### (2 more spaces than were allocated)
Last Name: Doeber#########################Johnny###########################

其中#是空字符(在真实程序中看起来很奇怪)

因此,不仅m_sFirstName不能正确地将前3个字符打印到屏幕上,而且m_sFirstName的整个混乱版本正被添加到m_sLastName字符数组的末尾...

我是如何在世界上对自己做的?

3 个答案:

答案 0 :(得分:2)

比较与分配

这行代码:

m_sLastName == "";

什么都不做。它将指向空字符串的指针与字符数组进行比较。并计算它们是否指向同一块内存(不是相同的内容)。然后我们扔掉那个结果。

如果要使用所有空字符初始化m_sLastName,则应执行以下操作:

memset(m_sLastName, '\0', sizeof(m_sLastName));

如果不这样做,m_sLastName将初始化为未指定的值。也就是随机垃圾。

相反,如果您希望这些字符串为空字符串,那么您可以这样做:

m_sLastName[0] = '\0';

我们如何复制字符串?

您当前将代码值复制到对象几乎的代码有效。您不会终止字符串,并假设传入的字符串长度为31个字符。在你的main()中,这是真的。但这是一件非常糟糕的事情。

让我们解决一下:

strncpy(m_sLastName, lName, 31);
m_sLastName[30] = '\0'; // If lName was too long, then strncpy won't null terminate the string.

我们也可以使用snprintf(),这有点慢,但更安全。

snprintf(m_sLastName, sizeof(m_sLastName), "%s", lName);

您在main()

中创建的字符串 主要的

firstnamelastname已终止。他们真的应该。所以你需要添加:

firstname[6] = '\0';
lastname[6] = '\0';

实现所有这些的代码是什么样的:

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <string>
using namespace std;

class EmployeeRecord {
    private:
        char m_sLastName[31];
        char m_sFirstName[31];

    public:
        EmployeeRecord();
        EmployeeRecord(int ID, const char *fName, const char *lName, int dept, double sal);

    public:
        void printRecord();
};

EmployeeRecord::EmployeeRecord() {
    memset(m_sFirstName, '\0', sizeof(m_sFirstName));
    memset(m_sLastName, '\0', sizeof(m_sLastName));
}

EmployeeRecord::EmployeeRecord(int ID, const char *fName, const char *lName, int dept, double sal) {
    snprintf(m_sFirstName, sizeof(m_sLastName), "%s", fName);
    snprintf(m_sLastName, sizeof(m_sLastName), "%s", lName);
}

void EmployeeRecord::printRecord() {
    cout << "First Name:      " << m_sFirstName << endl;
    cout << "Last Name:       " << m_sLastName << endl;
}

int main() {
    EmployeeRecord Employee1 = EmployeeRecord();
    Employee1.printRecord();
    printf("\n");

    char firstname[31] = "Jhonny";
    char lastname[31] = "Doeber";
    EmployeeRecord Employee2 = EmployeeRecord(0, firstname, lastname, 0, 0.0);
    Employee2.printRecord();
    printf("\n");

    EmployeeRecord Employee3 = EmployeeRecord(0, "John", "Smith", 0, 0.0);
    Employee3.printRecord();
    printf("\n");
}

运行该代码会是什么样的?

First Name:      
Last Name:       

First Name:      Jhonny
Last Name:       Doeber

First Name:      John
Last Name:       Smith

Employee3.firstname实际上是什么?

所以,这就是我对Employee3的第一个名字的了解。有31个字符可供空间使用。我知道前5个包含{'J', 'o', 'h', 'n', '\0'}

我不知道剩下的内容。它可能有一些不是所有空字符的垃圾。问题是,我们不在乎。字符串的有效内容以第一个空字符结束。

答案 1 :(得分:1)

std::stringm_sFirstName使用m_sLastName,行为将更接近您的期望。

答案 2 :(得分:-1)

清除构造函数中的名称字段应为

m_sLastName[0] = 0
m_sFirstName[0] = 0;

其他构造函数中的名称字段设置应为

strncpy( m_sFirstName, fName, 31 );
strncpy( m_sLastName,  lName, 31 );

主要的本地人应该用

设置
strncpy(firstname, "Johnny", 31 );
strncpy(lasname,   "Doeber", 31 );

并非需要那些当地人

<string.h>

需要strncpy

另请注意,您的教授应该为此作业获得F,从C开始是最差教授C ++的方式