I have a program that is trying to sort some names alphabetically. I run it and it does not have any errors, but the names are not sorted. I compare 2 names and see which one is supposed to be shifted in the array.
Here is the code:
void sort_names(char array[])
{
const int arraysize = 5;
// Step through each element of the array
for (int startindex = 0; startindex < arraysize; startindex++)
{
int smallestnum = startindex;
for (int currentindex = startindex + 1; currentindex < arraysize; currentindex++)
{
// If the current element is smaller than our previously found smallest
if ((student_list[currentindex].lname) < (student_list[smallestnum].lname))
// Store the index
smallestnum = currentindex;
}
// Swap our start element with our smallest element
swap(student_list[startindex], student_list[smallestnum]);
}
}
My struct looks like this:
struct student {
char fname[30];
char lname[30];
};
Do I have to convert these to strings somewhere because they are characters arrays? I am kind of lost and trying to figure out how to make it sort properly.
The Problem is that in this line:
if ((student_list[currentindex].lname) < (student_list[smallestnum].lname))
it doesn't compare string characters, but rather compares memory adresses.
If you still want to use char arrays, you have to use the strcmp function. However, I recommed that you use string instead.
The problem is this line:
if ((student_list[currentindex].lname) < (student_list[smallestnum].lname))
The line compares the pointers, it does not compare the contents.
It should be:
if ( strcmp( student_list[currentindex].lname, student_list[smallestnum].lname ) < 0 )
Another alternative is to use std::string instead, which has built-in comparisons. For example:
struct student {
std::string fname;
std::string lname;
};
Related
Output
The last names are sorted alphabetically, but they do not correspond to their first name. I used two arrays to hold the first/last names I extracted from a file.
I sorted last names using:
`
for(int i= 0; i < LISTSIZE; i++)
{
minidx = i; //declared as int before
strcpy(headers[0],lastname[i]);
for(int j = i; j < LISTSIZE; j++)
{
int match = strcmp(lastname[j],headers[0]);
if (match < 0)
{
minidx = j;
strcpy(headers[0], lastname[j]);
}
}
strcpy(headers[0], lastname[minidx]);
strcpy(lastname[minidx], lastname[i]);
strcpy(lastname[i], headers[0]);
}
`
I tried combining last and first names into one array but that ended up with nothing. I have looked on multiple forums and found nothing of note. I am relatively new to programming, so excuse my lack of knowledge.
You will want to hold the first and last names together in something like a structure when extracting from your file, and then sort those structures by the last name field. This keeps your associated data together from the beginning, so there's no need to attempt to recombine it later.
#include <string>
#define LISTSIZE 3
// Structure that stores a firstname and lastname for a person.
struct person {
std::string firstname;
std::string lastname;
};
bool lexical_less_than(std::string wordone, std::string wordtwo) {
//code to compare two strings and determine which one is 'before'
//the other in alphabetical order goes here
return true;
}
int main() {
//structure initialiser - firstname = bob, lastname = martin
struct person p1 = {"bob", "martin"};
struct person p2 = {"jim", "davey"};
struct person p3 = {"james", "kirk"};
//array to alphabetise
struct person people[LISTSIZE] = {p1, p2, p3};
//sketch of sorting code - this doesn't work!
//this is just to demo moving structures around and
//accessing fields.
for (int i = 0; i < LISTSIZE; i++) {
if (i != LISTSIZE - 1) {
//pass the lastnames of our people to the compare function
if (lexical_less_than(people[i].lastname, people[i+1].lastname)) {
//swap the structures over. Note that you can manipulate
//structures in the same way as any other type
struct person temp = people[i];
people[i] = people[i+1];
people[i+1] = temp;
}
}
}
}
Some reading on Structures - MSDN, Structures - CPlusPlus.
Consider also using standard library algorithms/containers such as std::string and std::vector rather than char arrays and strcpy. These will be safer and more idiomatic.
Based on this answer, if you have to use two separate arrays, use an index array to "sort" both of the arrays.
Here is an example of how to use an index array:
#include <iostream>
#include <string>
#include <algorithm>
#define LISTSIZE 4
int main()
{
// Sample first and last name arrays
std::string firstName[LISTSIZE] = {"Bob", "Alan", "Jack", "Jill"};
std::string lastName[LISTSIZE] = {"Smith", "Jones", "Brown", "Johnson"};
// This is the index array
int index[LISTSIZE] = {0,1,2,3};
// sort on last name
std::sort(index, index + LISTSIZE, [&](int n1, int n2)
{ return lastName[n1] < lastName[n2]; });
// Now print out the names, sorted on last name
for (int i = 0; i < LISTSIZE; ++i)
std::cout << firstName[index[i]] << " " << lastName[index[i]] << "\n";
}
Output:
Jack Brown
Jill Johnson
Alan Jones
Bob Smith
Note that we did not sort the arrays with the names themselves -- they have not been altered. The only thing done was to create the index array and sort the index array based on the ordering of the last name. At the end, we use the index value at position i to associate first and last names.
I know you used C-style strings, but the principle is the same.
I am writing code that finds the number of palindrome strings in a given array of strings. I think I have the right idea, but I am getting weird errors when I run it. What exactly am I doing wrong?
int countPalindromes(string s) {
int size = s.size();
int counter = 0;
string forwardSum = "";
string backwardSum = "";
for(int i = 0; i < size; i++){
for(int j = i; j < size; i++){
forwardSum.push_back(s[j]);
backwardSum.push_back(s[(n - 1)-j]);
if(forwardSum == backwardSum){
counter++;
}
}
}
return counter;
}
string forwardSum[] = {};
This is an array of zero size (which I don't believe is legal but we'll let that pass)
forwardSum[i] = forwardSum[i] + s[j];
This is an attempt to access the ith element of an array which has zero size.
That's bad.
I'm not really following your code (it's late at night), but I think you probably want forwardSum and backwardSum to be strings not arrays of strings. And you probably want to use push_back to add characters from s to those strings. I.e.
string forwardSum;
...
forwardSum.push_back(s[j]); // add s[j] to forwardSum
But if you really do want forwardSum to be an array, then the sensible thing to do would be to use a vector instead.
vector<string> forwardSum(size); // a vector of strings with the given size
Now that should at least not crash with the rest of your code.
The following code is part of my project in C++98, therefore i'm not allowed to use vectors and such. Now the main use for this function is to break down a single string line, to an array of strings using the given delimeter, and the size is basically the number of words that i need to return. the problem is that when i debug and check nums towards the end, it changed it's size to 4, and only returned the first word, filled by every char of it.As if, nums is now char* i have changed the code many times, but i don't where i went wrong, any advice?
string* Split(string ss,char delimeter,int size)
{
string *nums=new string[size];
int index_c, index_sw=0;
for (int i = 0; i < size; i++)
{
for(unsigned int j=0;j<ss.length();j++)
{
if (ss.at(j) == delimeter)
{
index_c = j;
nums[i] = ss.substr(index_sw, index_c);
index_sw += index_c;
i++;
}
}
break;
}
return nums;
}
Since you do not know the number of words in the string ss beforehand, you cannot specify size when calling the Split function. Not knowing size you will not be able to allocate memory to nums.
So you are better off using a vector of strings. As pointed out, vector is available in C++98.
Then your modified Split function will look like this:
vector<string> Split(string ss, char delimiter)
{
vector<string> vs;
int index_c, index_sw=0, j;
for(j=0;j<ss.length();j++)
{
if (ss.at(j) == delimiter)
{
index_c = j;
vs.push_back(ss.substr(index_sw, index_c - index_sw));
index_sw = index_c + 1;
}
}
vs.push_back(ss.substr(index_sw, j - index_sw));
return vs;
}
which then can be called like this:
vector<string> ret = Split("This is a stackoverflow answer", ' ');
See demo here.
I am trying to bubble sort the LastName property (under a struct StudentRecord, hence the names) of an array using bubble sort. But I am having trouble doing so.
I am receiving the error (I'm using MinGW to compile):
Invalid array assignment
Here is my code:
void option2 (StudentRecord student[], int n)
{
int pass = 1;
bool done = false;
StudentRecord temp;
while (!done && pass <= n-1)
{
done = true;
for (int i = n-1; i >= pass; i--)
{
if (student[i].lastName < student[i-1].lastName)
{
temp.lastName = student[i].lastName;
student[i].lastName = student[i-1].lastName;
student[i-1].lastName = temp.lastName;
done = false;
}
}
pass++;
}
}
It looks like lastName is an array of characters.
You can't assign entire arrays to each other; you need to use strcpy() (#include <cstring>) to copy one to the other. Additionally, using < with character arrays will cause the memory addresses of the first elements in each array to be compared, not the entire string of characters; use strcmp for this (which returns < 0 iff the first parameter is lexicographically < the second parameter).
Note you can (and probably should) use std::string instead (#include <string>), which will automatically provide copying, comparison, and dynamic growth for you transparently.
I have a simple table called mytable2 with only one column, name as varchar2(20).
I now have a list of names stored as vector of std::string to be inserted into the table.
I want to use executeArrayUpdate, so I must do the setDataBuffer first.
However, as I could see, people always use char[][20] to set databuffer.
This leaves me a big headache, since I have two issues here, first is to convert from vector to array, second is to convert the string to char.
1st, I tired to use vector of char[20], and this doesn't compile. Googled and they say that vector can't take char[], so I changed my vector of std::string to vector of char*.
2nd, I tried to turn the vector to arrray by using "void* p=&names[0]", as some people say this way we can use vectors just as array.
I used stmt->setDataBuffer(1,mystring,OCCI_SQLT_STR,20,NULL), and the program compiled and executed alright, but when I "select name from mytable2", it showed only some strange charaters.
Anyone has had a similiar issue before? what should I do?
My code is simple as below:
count=2;
vector<char*> mystring;
for(int i=0;i<count;i++)
{
char my[20];
strcpy_s(my,"Michael");
mystring.insert(mystring.end(),my);
}
stmt->setDataBuffer(1,&mystring[0],OCCI_SQLT_STR,20,NULL);
stmt->setBatchErrorMode (true);
stmt->executeArrayUpdate(count);
You'd need to dynamically create the char array you're putting into the vector for it to have a chance of working correctly.
I have not used OCCI, but if I had to use API that asked for char[][20], I would give it char[][20]
If you have your existing data in vector, why not just copy it across into the 2D char array? Eg.
// intialise vector with nonsense
unsigned int const VEC_SIZE = 2 ;
vector<string> v;
for (unsigned int i = 0; i < VEC_SIZE; ++i) {
stringstream s;
s << "Jon Paul " << i << endl;
v.push_back ( s.str() ) ;
}
// create the required 2D char array
unsigned int const STR_LEN = 20 ;
char c [VEC_SIZE][STR_LEN];
// copy the data from the vector of strings to the 2D char array
for (unsigned int i = 0; i < VEC_SIZE; ++i) {
string s = v[i].substr(0,STR_LEN);
char const * const cc = s.c_str();
unsigned int j = 0;
for (; j < STR_LEN && j < s.size(); ++j) {
c[i][j] = cc[j];
}
c[i][ j==STR_LEN ? 20 : j ] = 0; // write NULL character
}
I take it you've simplified your example to be a fixed size vector, so my response is going to be simplified to, with the thorny issue of dynamic allocation of 2D arrays left as an exercise for the reader...