I'm working on a program that takes a list of words entered by the user, ignores the cases (upper and lower) and then sorts them using the function qsort. I'm having an issue with qsort in that I don't know what to pass as the 3rd item qsort(array, sizeOfArray, ??, funcCompare). Can somebody point me in the right direction?
using namespace std;
int compare(const void* , const void*);
const int SIZE = 100;
void main()
{
int i = 0;
int s = 0;
size_t size = 0;
string words;
string list[SIZE];
for (i = 0; i < SIZE; i++)
{
cout << "Please enter a word. Press ^Z to quit: " << endl;
cin >> words;
transform(words.begin(), words.end(), words.begin(), ::tolower);
if (words.length() > size)
{
size = words.length();
}
list[i] = words;
if (cin.eof())
{
s = i;
break;
}
}
qsort(list, s, ?? , compare);
for (int j = 0; j < i; j++)
{
cout << list[j] << endl;
}
}
int compare(const void* p1, const void *p2)
{
char char1, char2;
char1 = *(char *)p1; // cast from pointer to void
char2 = *(char *)p2; // to pointer to int
if(char1 < char2)
return -1;
else
if (char1 == char2)
return 0;
else
return 1;
}
The spot in question in qsort has the '??' Any help you can give is appreciated!
This is an assignment
Technically you need to pass sizeof(string)
But std::string is not trivial type and thus you are not allowed to use qsort to sort array of strings.
25.5 C library algorithms
4 The function signature:
qsort(void *, size_t, size_t, int (*)(const void *, const void ));
is replaced by the two declarations:
extern "C" void qsort(void base, size_t nmemb, size_t size, int (compar)(const void, const void*));
extern "C++" void qsort(void* base, size_t nmemb, size_t size, int (compar)(const void, const void*));
both of which have the same behavior as the original declaration. The behavior is undefined unless the
objects in the array pointed to by base are of trivial type.
If you are using C++ and std::string you should use also std::vector instead of plain array and std::sort instead of qsort.
You need to pass the size of each element in the array, in bytes.
This is accomplished by: sizeof(string)
qsort(list, s, sizeof(string), compare);
EDIT: Take a look at alexrider's post for more information on this
I wrote a qsort string comparision function a while back for BRL-CAD, here is the compare function used(keep in mind written in C, could be optimized).
* Sort function called by quick sort to sort data according
* to its second field in the string
*/
int
sort(const void* a, const void* b)
{
char *ia = *(char**)a;
char *ib = *(char**)b;
char Str[MAX_RESULT_LEN];
char Str2[MAX_RESULT_LEN];
//get string into array
GetStr(ia, Str);
GetStr(ib, Str2);
int n1 = atoi(Str);
int n2 = atoi(Str2);
return (n2 - n1);
}
Related
My code is generating duplicates (3) to be precise and I don't know why, could anyone help out?
I've tried searching for a problem, but to my eyes it seems the same as other premutation codes on the internet.
I was thinking it could've been a miss-use of the loop but I don't see why it's giving me 9 answers instead of 6.
#include <iostream>
using namespace std;
void swap(char *a, int x, int y);
void print(char *a, int n);
void permute(char *a, int n, int index);
int grabSize(char a[]);
int main() {
char array[] = {'a', 'b', 'c'}; // PLACE COMPONENTS HERE
int n = grabSize(array);
//
cout << "[" << endl;
cout << " ";
permute(array, n, 0);
cout << endl << "]";
}
int grabSize(char a[]) {
int i = 0;
while (a[i] != '\0') {
i++;
}
return i;
}
void swap(char *a, int x, int y) {
char aux;
aux = a[x];
a[x] = a[y];
a[y] = aux;
}
void permute(char *a, int n, int index) {
if (index == n-1) {
print(a, n);
return;
}
for (int i = 0; i < n; i++) {
swap(a, i, index);
permute(a, n, index+1);
swap(a, i, index);
}
}
void print(char *a, int n) {
cout << " [ ";
for (int i = 0; i < n; i++) {
cout << a[i];
}
cout << " ] ";
}
You are getting 9 combinations of string because, in permute(), the for loop variable i initialised with 0:
for (int i = 0; i < n; i++) {
^^^
Note that you are calling permute() function recursively to generate the permutations of string and, in every recursive call, the index is incremented by 1 while passing to permute() function but the for loop , in permute() function, starts with 0 and iterate till < n. Hence you are getting n*n combinations of string in output. Instead, the for loop variable i should be initialised with index:
for (int i = index; i < n; i++) {
^^^^^
Other problems in your code:
This
char array[] = {'a', 'b', 'c'};
is array of 3 characters. Note that there is no terminating null character in array array. Passing it to grabSize() function and checking for '\0' character in it will lead to UB as grabSize() function will end up accessing array array beyond its size while looking for null terminating character. To get the size of array, you can simply do sizeof(array)/sizeof(array[0]) in main() function and do away with grabSize() function.
If you are inclined to use grabSize() function then either add null terminating character manually
char array[] = {'a', 'b', 'c', '\0'};
or initialise array array with string, like this
char array[] = "abc";
and then pass it to grabSize() function.
Suggestion:
In C++, the use of plain C style array is discouraged. C++ has Containers Library, go through it. The sequence container array and vector will be of your interest.
I'm a new Computer Science student, and I have a homework question that is as follows:
Write a Function that passes in a C-String and using a pointer determine the number of chars in the string.
Here is my code:
#include <iostream>
#include <string.h>
using namespace std;
const int SIZE = 40;
int function(const char* , int, int);
int main()
{
char thing[SIZE];
int chars = 0;
cout << "enter string. max " << SIZE - 1 << " characters" << endl;
cin.getline(thing, SIZE);
int y = function(thing, chars, SIZE);
cout << y;
}
int function(const char *ptr, int a, int b){
a = 0;
for (int i = 0; i < b; i++){
while (*ptr != '\0'){
a++;
}
}
return a;
}
First of all welcome to stackoverflow ye0123! I think you are trying to rewrite the strlen() function here. Try giving the following link a look Find the size of a string pointed by a pointer.
The short answer is that you can use the strlen() function to find the length of your string. The code for your function will look something like this:
int function(const char *ptr)
{
size_t length = strlen(ptr);
return length;
}
You should also only need this function and main.
Edit: Maybe I misunderstood your question and you are supposed to reinvent strlen() after all. In that case, you can do it like so:
unsigned int my_strlen(const char *p)
{
unsigned int count = 0;
while(*p != '\0')
{
count++;
p++;
}
return count;
}
Here I am comparing *p from '\0' as '\0' is the null termination character.
This was taken from https://overiq.com/c-programming-101/the-strlen-function-in-c/
I'm having trouble trying to come up with the pointer version of this function:
void strncpy(char t[], const char s[], const unsigned int n)
{
unsigned int i = 0;
for(i = 0; i < n and s[i]; i++)
t[i]=s[i];
t[i] = '\0'
}
This function is supposed to copy the first "n" characters of one array to another array and then terminate with a null character. I'm sure this is simple but I'm still learning pointers :P
This is what I have right now:
void strncpy(char * t, const char * s, const unsigned int * n)
{
unsigned int i = 0;
for(i = 0; i < *n and *s; i++)
*t = *s;
*t = '\0';
}
Im calling it in main via:
char array_one[5] = "quiz";
char array_two[5] = "test";
unsigned int x = 2;
strncpy(array_one,array_two,x);
You've failed to increment the pointers, so you're always overwriting the same address. There's also no need to pass n via a pointer:
#include <cstddef>
void my_strncpy(char *t, const char *s, std::size_t n) {
while (n && *s) {
*t++ = *s++;
--n;
}
*t = '\0';
}
NB: note use of size_t to duplicate the standard parameter signature
of the standard strncpy function, although the standard version also returns the original value of t rather than void.
#include <iostream>
// changing the function signature to take an int instead of
// pointer to int - cleaner
void my_strncpy(char * t, const char * s, const unsigned int n)
{
unsigned int i = 0;
for(i = 0; i < n; i++)
{
*t++ = *s++; // copy and increment
}
*t = '\0'; // fixing - added terminating char
}
int main(void)
{
char a[] = "string1";
char b[] = "string2";
my_strncpy(a,b,7); // replace 7 with appropriate size
std::cout << a << std::endl;
}
You need to copy over each character from one string to another and then increment the pointers - you were missing that in your implementation.
I also assume that you will not overshoot the array you are copying from.
Hello im trying to write this program which replace each negative number with -1 and positive with 1
but an error :
[Error] cannot convert 'int ()[3]' to 'int ()[100]' for argument '1' to 'void replace(int (*)[100], int, int)'
what does that mean ??
#include<iostream>
using namespace std;
void replace(int Arr[][100],int rsize, int csize)
{
for(int r=0;r<rsize;r++)
{
for (int c=0;c<csize;c++)
{
if (Arr[r][c]>0) Arr[r][c]=1;
else if (Arr[r][c]<0) Arr[r][c]=-1;
else Arr[r][c]=0;
}
}
}
int main()
{
int a[4][3]={
{2,0,-5},
{-8,-9,0},
{0,5,-6},
{1,2,3}};
replace(a,4,3);
for(int i=0;i<4;i++)
for (int j=0;j<3;j++)
cout<<a[i][j]<<" ";}cout<<endl;
system ("pause");
return 0;
}
You declared function void replace(int Arr[][100],int rsize, int csize) - it expects 2D array, with 'inner' dimension being 100.
Then you pass to it int a[4][3] which has 'inner' dimension 3. Compiler can't convert it. Those dimensions are used to calculate memory position shift when using Arr[x][y] (it is equivalent to *(Arr + x * 100 + y). That's why compiler can't assign array with 3 to array with 100.
If you want your replace to work with any dimension change it to:
void replace(int* Arr,int rsize, int csize). Then use *(Arr + r*csize + c) to access fields instead of Arr[r][c]
Even better solution: you tagged this question as C++ - use C++ library :) - std::vector<std::vector<int> > or std::array (C++11)
Well you declare a function which takes int[][100], then you pass it an int[4][3]. C++ doesn't work like this. In fact, you can't actually pass arrays by value at all; they decay to pointers implicitly.
If you want your function to take arbitrarily sized arrays, you could just make it take pointers to pointers instead:
void replace(int** Arr,int rsize, int csize)
Then you should throw your code away and use std::vector instead:
void replace(std::vector<std::vector<int>> &Arr)
If you want some compile-time constraints on the size of the array, you could do something like:
template <std::size_t X, std::size_t Y>
void replace (std::array<std::array<int,Y>,X>& Arr)
{
static_assert (Y <= 100, "Inner array is too large");
}
The issue is that you're declaring your argument (Arr[][100]) as having 100 elements. But it's not 100 elements, it's three in your code. I'm assuming what you really want is to be able to pass different sized arrays, and specify the array dimensions in the other arguments. If that's the case, you can just declare the array as an int *. So something like the following will work:
#include "stdafx.h"
#include<iostream>
using namespace std;
void replace(int *Arr, int rsize, int csize);
void print(int *Arr, int rsize, int csize);
int _tmain(int argc, _TCHAR* argv[])
{
int a[4][3] = {
{ 2, 0, -5 },
{ -8, -9, 0 },
{ 0, 5, -6 },
{ 1, 2, 3 } };
print((int *)a, 4, 3);
replace((int *)a, 4, 3);
for (int i = 0; i<4; i++)
{
for (int j = 0; j<3; j++)
{
cout << a[i][j] << " ";
}cout << endl;
}
system("pause");
return 0;
}
void replace(int *Arr, int rsize, int csize)
{
for (int r = 0; r<rsize; r++)
{
for (int c = 0; c<csize; c++)
{
int index = (r * (rsize - 1)) + c;
if (Arr[index] > 0)
{
Arr[index] = 1;
}
else if (Arr[index] < 0)
{
Arr[index] = -1;
}
else
{
Arr[index] = 0;
}
}
}
}
void print(int *Arr, int rsize, int csize)
{
char str[256];
for (int r = 0; r<rsize; r++)
{
sprintf(str, "");
for (int c = 0; c<csize; c++)
{
int index = (r * (rsize - 1)) + c;
if (strlen(str) > 0)
{
sprintf(str, "%s, ", str);
}
sprintf(str, "%s%d", str, Arr[index]);
}
cout << str;
cout << endl;
}
}
Don't follow my example of using the unsafe string functions.
The reason this works is that a two-dimensional int array is just a bunch of one dimensional arrays stacked together. So an int[4][3] is just 12 ints in memory. That's functionally identical to an int[12]. If you declare the input to the function as an int *, then it's a pointer to a block of memory that contains ints, doesn't matter how many. So you can avoid the type cast errors you were getting.
There's lots of risk with doing this if you don't make sure your parameters are correct. For example, if you call the same replace function with the same input array, but claim it has 5 rows, then you'll start reading uninitialized memory. (Possibly uninitialized...more accurately, you'll at least be reading memory that is not what you think it is.) Of course, you can do the same thing without the pointer, that's the whole fun part of C++.
I know I shouldn't use C-style arrays but I was trying to look for a way to do this anyway. I'm trying to alphabetize the const char* array but std::sort didn't do it right. What am I doing wrong?
#include <iostream>
#include <algorithm>
int main() {
const char * str[5] = {"alpha", "gamma", "beta", "delta", "chi"};
int size = sizeof(str)/sizeof(*str);
std::sort(str, str + size);
for (int i = 0; i < size; i++) std::cout << str[i] << ", ";
}
It doesn't change the array at all. What am I not doing right?
The default std::sort comparison function is simply comparing pointers (memory addresses) with the < operator. It's not actually lexicographically comparing the C-strings. You need to create a custom comparison function which compares the strings lexicographically by e.g. calling std::strcmp
bool compare(const char* s1, const char* s2)
{
return std::strcmp(s1, s2) < 0;
}
int main()
{
const char * str[5] = {"alpha", "gamma", "beta", "delta", "chi"};
int size = sizeof(str)/sizeof(*str);
std::sort(str, str + size, compare);
for (int i = 0; i < size; i++) std::cout << str[i] << ", ";
}
The problem is simple: You're using the default comparison, which will just compare the pointer values. Usually these will have ascending addresses, so you won't see any change.
You'll have to write your own comparison function:
int comp(const char *c1, const char *c2) {
return strcmp(c1, c2) < 0;
}
std::sort(str, str + size, &comp);
Maybe because the default comparator for const char * is comparing pointer values (and the string constants happen to be allocated in the array order already)?
Use std::string.