简体   繁体   中英

C++ weird output with printf

Below is my functions, its suppose to list some countries I tried using << fixed but doesn't seems to help

This is my output:

�ѿra
�ѿd Arab Emirates
�ѿnistan
�ѿua and Barbuda
�ѿlla
�ѿia
�ѿia
�ѿrlands Antilles
�ѿa
�ѿctica
�ѿtina
�ѿcan Samoa

My text file is okay, i wonder is there wrong in my casting of data.

This is my CountryData.cpp file

#include <iostream>
#include <string.h>
#include "CountryData.h"

using namespace std;
// ====================================================================

void readData ()
{
    FILE * pFile;
    NoOfRecordsRead = 0;
    char buffer [Line_Char_Buffer_Size];

    pFile = fopen (INPUT_FILE_NAME , "r");

    if (pFile == NULL) 
        perror ("Error opening file 'Countries.txt' !");
    else
    {
        while ( !feof (pFile) )
        {
            char* aLine = get_line (buffer, Line_Char_Buffer_Size, pFile);

            if (aLine != NULL)
            {
//              printf ("%d] aLine => %s\n", NoOfRecordsRead, aLine);
                globalCountryDataArray [NoOfRecordsRead++] = createCountryRecord (aLine);
            }
        }

     fclose (pFile);

    }
}

// ====================================================================

char* get_line (char *s, size_t n, FILE *f)
{
    char *p = fgets (s, n, f);

    if (p != NULL) 
    {
        size_t last = strlen (s) - 1;
        if (s[last] == '\n') 
            s[last] = '\0';
    }
    return p;
}

// ====================================================================

CountryRecordType createCountryRecord (char* aLine)
{
    CountryRecordType ctryRec;
    char* pch = strtok (aLine, LINE_DATA_DELIMITER);

    // 1) Retrieve TLD
    strcpy (ctryRec.TLD, pch);
    pch = strtok (NULL, LINE_DATA_DELIMITER);

    // 2) Retrieve Country
    strcpy (ctryRec.Country, pch);
    pch = strtok (NULL, LINE_DATA_DELIMITER);

    // 3) Retrieve FIPS104
    strcpy (ctryRec.FIPS104, pch);
    pch = strtok (NULL, LINE_DATA_DELIMITER);

    // 4) Retrieve ISO2
    strcpy (ctryRec.ISO2, pch);
    pch = strtok (NULL, LINE_DATA_DELIMITER);

    // 5) Retrieve ISO3
    strcpy (ctryRec.ISO3, pch);
    pch = strtok (NULL, LINE_DATA_DELIMITER);

    // 6) Retrieve ISONo
    ctryRec.ISONo = atof (pch);
    pch = strtok (NULL, LINE_DATA_DELIMITER);

    // 7) Retrieve Capital
    strcpy (ctryRec.Capital, pch);
    pch = strtok (NULL, LINE_DATA_DELIMITER);

    // 8) Retrieve Region
    strcpy (ctryRec.Region, pch);
    pch = strtok (NULL, LINE_DATA_DELIMITER);

    // 9) Retrieve Currency
    strcpy (ctryRec.Currency, pch);
    pch = strtok (NULL, LINE_DATA_DELIMITER);

    // 10) Retrieve CurrencyCode
    strcpy (ctryRec.CurrencyCode, pch);
    pch = strtok (NULL, LINE_DATA_DELIMITER);

    // 11) Retrieve Population
    ctryRec.Population = atof (pch);

    return (ctryRec);

}

// ====================================================================

char* displayRecordContent (CountryRecordType ctryRec)
{
    char * output = ctryRec.Country;
    return output;

}

// ====================================================================

void showAllRecords ()
{
    int i=0;
    string stroutput;
    char * result;
    for (i=0; i<NoOfRecordsRead; i++)
    {

        result = displayRecordContent (globalCountryDataArray [i]);
        stroutput += result;
        stroutput += "\n";
    }

cout << fixed << stroutput << endl;

}

// ====================================================================

int findCountryRecord (const char* countryName)
{
    int idx     = -1;
    int found   = 0;

    while (!found && (++idx < Max_Record_Size))
        if (strcmp (globalCountryDataArray [idx].Country, countryName) == 0)
            found = 1;

    if (found)
        return (idx);
    else
        return (-1);
}

// ====================================================================

char* getCapital (const char* countryName)
{
    int idx = findCountryRecord (countryName);

    if (idx < 0)
    {
        printf ("Country '%s' not found!\n", countryName);
        return (NULL);  
    }
    else
        return (globalCountryDataArray [idx].Capital);
}

// ====================================================================

char* getCurrencyCode (const char* countryName)
{
    int idx = findCountryRecord (countryName);

    if (idx < 0)
    {
        printf ("Country '%s' not found!\n", countryName);
        return (NULL);  
    }
    else
        return (globalCountryDataArray [idx].CurrencyCode);
}


// ====================================================================

main ()
{
    readData ();
    showAllRecords ();


}

This is my CountryData.h file

#ifndef COUNTRY_DATA_H
#define COUNTRY_DATA_H

// ====================================================================

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

using namespace std;
// ====================================================================

#define TLD_LEN             2
#define COUNTRY_LEN         100
#define FIPS104_LEN         2
#define ISO2_LEN            2
#define ISO3_LEN            3
#define CAPITAL_LEN         100
#define REGION_LEN          100
#define CURRENCY_LEN        50
#define CURRENCY_CODE_LEN   3

#define No_Of_Rec_Fields        11
#define Max_Record_Size         250
#define Line_Char_Buffer_Size   400

#define LINE_DATA_DELIMITER     ","
#define INPUT_FILE_NAME         "Countries.txt"

// ====================================================================

//const char*   LINE_DATA_DELIMITER     = ",";
//const char*   INPUT_FILE_NAME         = "Countries.txt";


typedef struct CountryRecord
{
    char TLD            [TLD_LEN+1];            // Top Level Domain code
    char Country        [COUNTRY_LEN+1];    
    char FIPS104        [FIPS104_LEN+1];        // Ctry code according to FIPS104 standard
    char ISO2           [ISO2_LEN+1];           // Ctry code according to ISO2    standard
    char ISO3           [ISO3_LEN+1];           // Ctry code according to ISO3    standard
    double ISONo;

    char Capital        [CAPITAL_LEN+1];    
    char Region         [REGION_LEN+1];         // E.g. Asia, Europe, etc.
    char Currency       [CURRENCY_LEN+1];       // Full name of currency
    char CurrencyCode   [CURRENCY_CODE_LEN+1];  // Currency abbreviation
    double Population;

}   CountryRecordType;

int NoOfRecordsRead;
CountryRecordType globalCountryDataArray [Max_Record_Size];

// ====================================================================

void readData ();
char* get_line (char *s, size_t n, FILE *f);
CountryRecordType createCountryRecord (char* aLine);
char* displayRecordContent (CountryRecordType ctryRec);
void showAllRecords ();

int findCountryRecord (const char* countryName);
char* getCapital (const char* countryName);
char* getCurrencyCode (const char* countryName);

// ====================================================================

#endif // COUNTRY_DATA_H

This is part of my countries.txt file

AD,Andorra,AN,AD,AND,20.00,Andorra la Vella,Europe,Euro,EUR,67627.00
AE,United Arab Emirates,AE,AE,ARE,784.00,Abu Dhabi,Middle East,UAE Dirham,AED,2407460.00
AF,Afghanistan,AF,AF,AFG,4.00,Kabul,Asia,Afghani,AFA,26813057.00
AG,Antigua and Barbuda,AC,AG,ATG,28.00,Saint John's,Central America and the Caribbean,East Caribbean Dollar,XCD,66970.00
AI,Anguilla,AV,AI,AIA,660.00,The Valley,Central America and the Caribbean,East Caribbean Dollar,XCD,12132.00
AL,Albania,AL,AL,ALB,8.00,Tirana,Europe,Lek,ALL,3510484.00
AM,Armenia,AM,AM,ARM,51.00,Yerevan,Commonwealth of Independent States,Armenian Dram,AMD,3336100.00
AN,Netherlands Antilles,NT,AN,ANT,530.00,Willemstad,Central America and the Caribbean,Netherlands Antillean guilder,ANG,212226.00
AO,Angola,AO,AO,AGO,24.00,Luanda,Africa,Kwanza,AOA,10366031.00
AQ,Antarctica,AY,AQ,ATA,10.00,--,Antarctic Region, , ,0.00
AR,Argentina,AR,AR,ARG,32.00,Buenos Aires,South America,Argentine Peso,ARS,37384816.00
AS,American Samoa,AQ,AS,ASM,16.00,Pago Pago,Oceania,US Dollar,USD,67084.00
AT,Austria,AU,AT,AUT,40.00,Vienna,Europe,Euro,EUR,8150835.00
AU,Australia,AS,AU,AUS,36.00,Canberra,Oceania,Australian dollar,AUD,19357594.00

Since you are passing CountryRecordType by value to displayRecordContent , the pointer you are returning is invalid, and using it results in undefined behavior. This is because you are returning a pointer to the contents held by the copy that was made during the function call, which gets destructed when the function returns.

Modify your displayRecordContent function to use pass by reference instead.

const char* displayRecordContent (const CountryRecordType &ctryRec)
{
    const char * output = ctryRec.Country;
    return output;

}

I'd rewrite the code pretty much from the ground up, attempting to actually use C++ instead of C with a few bits of C++ mixed in.

#include <vector>
#include <string>
#include <iostream>
#include <iterator>
#include <fstream>

struct CountryRecord { 
    std::string TLD;
    std::string Country;
    std::string FIPS104;
    std::string ISO2;
    std::string ISO3;
    double ISONo;
    std::string Capital;
    std::string Region;
    std::string Currency;
    std::string CurrencyCode;
    double Population;
};

template <class T>
std::istream &get_field(std::istream &is, T &field) {
    is >> field;
    is.ignore(1);
    return is;
}

template<>
std::istream &get_field<std::string>(std::istream &is, std::string &field) {
    return std::getline(is, field, ',');
}

std::istream &operator>>(std::istream &is, CountryRecord &r) { 
    get_field(is, r.TLD);
    get_field(is, r.Country);
    get_field(is, r.FIPS104);
    get_field(is, r.ISO2);
    get_field(is, r.ISO3);
    get_field(is, r.ISONo);
    get_field(is, r.Capital);
    get_field(is, r.Region);
    get_field(is, r.Currency);
    get_field(is, r.CurrencyCode);
    return get_field(is, r.Population);
}

std::ostream &operator<<(std::ostream &os, CountryRecord const &r) { 
    return os << r.Country;
}

int main() { 
    std::ifstream in("countries.txt");
    std::vector<CountryRecord> countries(
        (std::istream_iterator<CountryRecord>(in)),
        std::istream_iterator<CountryRecord>());

    std::copy(countries.begin(), countries.end(), 
              std::ostream_iterator<CountryRecord>(std::cout, "\n"));

    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM