How to make strings stick together while radix sorting? - c

I have to make a program that sort strings (with exact length 7 chars) by using radix sort. I already made a function that sort each column separately. My problem is how to make the whole string move, not just one char. It's really problematic for me to see how should it work in C.
I made one array "char strings[3][8]" and "char output[3][8]" to get sorted 3 strings with exact 7 chars in each one. For example sorting these strings:
strcpy(strings[0], "kupbars");
strcpy(strings[1], "daparba");
strcpy(strings[2], "jykaxaw");
In output I get:
dakaaaa
juparbs
kypbxrw
Each column is sorted correctly but chars don't stick together. I tried many ways for 3 hours but nothing works.
My code looks like this:
void countingSort(char a[][8], char b[][8]) {
int c[123];
for (int pos = 6; pos >= 0; pos--) {
for (int i = 0; i < 123; i++)
c[i] = 0;
for (int i = 0; i < 3; i++)
c[(int)a[i][pos]]++;
for (int i = 1; i < 123; i++)
c[i] += c[i - 1];
for (int i = 2; i >= 0; i--) {
b[--c[(int)a[i][pos]]][pos] = a[i][pos];
}
}
}
(There are constants limiting string length etc. because it's easy to change it to variable - I just focused on getting this program work properly.)

Try changing the loop to move an entire string:
for (int i = 2; i >= 0; i--) {
int k = --c[(int)a[i][pos]];
for(int j = 0; j < 8; j++) {
b[k][j] = a[i][j];
}
}

You could do a circular list but it's a little overhead. I propose you to use memmove().
#include <string.h>
void array_move_forward(char array[3][8]) {
for (int i = 0; i < 3; i++) {
char tmp = array[i][6];
memmove(array[i] + 1, array[i], 6);
array[i][0] = tmp;
}
}
void array_move_rewind(char array[3][8]) {
for (int i = 0; i < 3; i++) {
char tmp = array[i][0];
memmove(array[i], array[i] + 1, 6);
array[i][6] = tmp;
}
}
A other solution would be to manipulate your string yourself and using a index, that indicate the first letter of your string.
{
char str[7];
int i = 0;
...
int j = i;
for (int k = 0; k < 7; k++) {
char tmp = str[j++ % 7];
}
}
With that you could rotate your string just with i++ or i--.
struct my_string_radix {
char str[7];
int begin;
}

Related

What causes the difference between memcpy and strcpy in copying openssl BIGNUM

This problem bothered me for an hour when I was programming, but I still didn't know the error of the original method after solving it.
void generate_r_vector(char (*r_vector)[17],char *random_r) {
BIGNUM* vector[127];
char r_v[128][17];
char flag[17];
memset(flag, 0, sizeof(flag));
int bits = 128;
int top = 0;
int bottom = 0;
for (int i = 0; i < 127; i++) {
vector[i] = BN_new();
BN_rand(vector[i], bits, top, bottom);
memset(r_v[i], 0, sizeof(r_v[i]));
BN_bn2bin(vector[i], r_v[i]);
}
memset(r_v[127], 0, sizeof(r_v[127]));
for (int i = 0; i < 127; i++) {
for (int j = 0; j < 16; j++) {
flag[j] = flag[j] ^ r_v[i][j];
}
}
for (int i = 0; i < 16; i++) {
r_v[127][i] = flag[i] ^ random_r[i];
}
for (int i = 0; i < 128; i++) {
memcpy(r_vector[i], r_v[i], 17);
}
}
Using memcpy to copy these arrays, when XOR in the main function, you can get the original string random_r.
But using the strcpy function to copy these arrays in the main function XOR, can not get the original random_r.
What I learned about OpenSSL:here, a 128 bit large number is converted into binary, and then every 4 bits are converted into a decimal, which is stored in the char array.
Memcpy copies by byte, while strcpy can only copy strings.
I can't understand why the XOR results of the two copy methods are different when they are both stored in char arrays.
My English level is not good, I hope you programmers can understand my expression. I sincerely hope you can answer my question. thank you
=======================2021/2/21 updata=====================================
I provide a program that can run directly, hoping to alleviate the problems caused by my unclear expression.
int main() {
char* random_r="1234567891234567";//长度16 算上'\0'17
char r_vector[128][17];
BIGNUM* vector[127];
char r_v[128][17];
char flag[17];//判断是否一致
memset(flag, 0, sizeof(flag));
int bits = 128;
int top = 0;
int bottom = 0;
for (int i = 0; i < 127; i++) {
vector[i] = BN_new();
BN_rand(vector[i], bits, top, bottom);
memset(r_v[i], 0, sizeof(r_v[i]));
BN_bn2bin(vector[i], r_v[i]);
}
memset(r_v[127], 0, sizeof(r_v[127]));
for (int i = 0; i < 127; i++) {
for (int j = 0; j < 16; j++) {
flag[j] = flag[j] ^ r_v[i][j];
}
}
for (int i = 0; i < 16; i++) {
r_v[127][i] = flag[i] ^ random_r[i];
}
//至此生成了128个向量,这些向量的异或之和正好是random_r的值,ans可以验证这个结论
char ans[17];
memset(ans, 0, sizeof(ans));
for (int i = 0; i < 128; i++) {
for (int j = 0; j < 16; j++) {
ans[j] = ans[j] ^ r_v[i][j];
}
}
printf("the target XOR result is:%s\n", ans);//
//下面使用memcpy的形式拷贝并求异或值
for (int i = 0; i < 128; i++) {
memcpy(r_vector[i], r_v[i], 17);//逐字节拷贝解决问题strcpy会出现问题,原因未知
}
memset(ans, 0, sizeof(ans));
for (int i = 0; i < 128; i++) {
for (int j = 0; j < 16; j++) {
ans[j] = ans[j] ^ r_vector[i][j];
}
}
printf("using memcpy copying and the result is:%s\n", ans);//这是正确的结果
memset(r_vector, 0, sizeof(r_vector));
for (int i = 0; i < 128; i++) {
strcpy(r_vector[i], r_v[i]);//strcpy会出现问题,原因未知
}
memset(ans, 0, sizeof(ans));
for (int i = 0; i < 128; i++) {
for (int j = 0; j < 16; j++) {
ans[j] = ans[j] ^ r_vector[i][j];
}
}
printf("using strcpy copying and the result is:%s\n", ans);
int err_count = 0;
for (int i = 0; i < 128; i++) {
if (strcmp(r_vector[i], r_v[i]) != 0) err_count++;
}
printf("after using strcpy() each vector using strcmp() with orignal r_v,the different vector nums:%d\n", err_count);
system("pause");
return 0;
}
Running results in vs2019
the target XOR result is:1234567891234567
using memcpy copying and the result is:1234567891234567
using strcpy copying and the result is:12eH⊙碡?H-c纫
after using strcpy() each vector using strcmp() with orignal r_v,the different vector nums:0
What causes the difference between memcpy and strcpy in copying openssl BIGNUM
The comment "BIGNUM values are not C strings, so strcpy() won't work." may be not enough to enlighten you.
BIGNUM values can contain a byte with all bits set to 0, called the null character, and since that is used to terminate a character string, strcpy() stops there and doesn't copy the rest of the BIGNUM value.
Even when strcpy and memcpy are both used for char arrays, they don't do exactly the same thing. memcpy copies a fixed number of bytes, which you give as the third argument. strcpy doesn't just copy from one char array or pointer to another, it figures out how much to copy in a completely different way, namely by checking for a 0 value in the chars to copy.
Even though r_vector points to char arrays, they don't have to be strings: If they are not 0-terminated or have 0 values at other positions things will behave differently than for a string.

How to compare jagged array to another array in C?

I've been trying to use a jagged array for a project of mine, meanwhile this is just a test furthermore I'll use it in my project. The question is the following How could I compare each element from each array, so in the code below I have three arrays, after them, I have one more which will be used to compare to the first ones,here what I have so far.
#include <stdio.h>
#include <stdlib.h>
int main(){
int row0[4] = {0,1,3,0};
int row1[4] = {5,6,9,10};
int row2[4] = {9,0,1,10};
int aux[4] = {9,6,9,10};
int *result[3] = {row0,row1,row2};
int size[3] = {4,4,4}, k =0;
for (int i = 0; i < 3; i++) {
int *ptr = result[i];
for (int j = 0; j < size[k]; j++) {
if(ptr[j] == aux[j])
{
printf("%d\n",ptr[j]);
}
ptr++;
}
printf("\n");
k++;
result[i]++;
}
return 0;
}
The result of it is 5, but I'd like to loop over all the values from the array that starts with 5, to find out if the all the other values are equal, in other words I want to know which array is equal to the "aux" array.
You have the (inner) loop:
int *ptr = result[i];
for (int j = 0; j < size[k]; j++)
{
if(ptr[j] == aux[j])
{
printf("%d\n",ptr[j]);
}
ptr++;
}
Since you increment both j and ptr, you're doing far too much incrementing. It's probably best to remove the ptr++; line.

How can I combine two arrays and output stored values as it`s written in description. May be there are some ways to do that?

Task description -> Whole task description is here
I have done part with sorting and got stuck.
How can I combine these arrays in one of already sorted pairs?
printf("\nHeight of boys in descending order\n");
for (i = (LENGTH1 - 1); i >= 0; i--)
{
printf("%d ", heightBoys[i]);
}
for (i = 0; i < LENGTH2; i++)
{
for (j = 0; j < (LENGTH2 - j - 1); j++)
{
if (heightGirls[j] > heightGirls[j+1])
{
temp = heightGirls[j];
heightGirls[j] = heightGirls[j+1];
heightGirls[j+1] = temp;
}
}
}
printf("\nHeight of girls in descending order\n");
for (j = (LENGTH2 - 1); j >= 0; j--)
{
printf("%d ", heightGirls[j]);
}
You have a sort [for the girls], but it is broken. Change:
for (j = 0; j < (LENGTH2 - j - 1); j++)
Into:
for (j = 0; j < (LENGTH2 - i - 1); j++)
To avoid [needless] replication of code, put the sorting code into a separate function.
Sort both arrays.
Take the minimum of the lengths of the two arrays (e.g. minlen).
I'm not sure what you mean [exactly] by "pairing", but the simplest is to print the pairing
Then, just loop on:
for (i = 0; i < minlen; ++i)
printf("Girl:%d Boy:%d\n",heightGirls[i],heightBoys[i]);
If you needed something more complex, you might need an array of structs like:
struct pair {
int boyheight;
int girlheight;
};
This array would need to be at least minlen in length. You could fill it in by adapting the final print loop.
But, if you're just printing, here is some sample code:
#include <stdio.h>
void
print_single(const int *height,int len,const char *sex)
{
printf("\nHeight of %s in descending order\n",sex);
for (int i = (len - 1); i >= 0; i--)
printf(" %d", height[i]);
printf("\n");
}
void
sort_height(int *height,int len)
{
for (int i = 0; i < len; i++) {
for (int j = 0; j < (len - i - 1); j++) {
if (height[j] > height[j + 1]) {
int temp = height[j];
height[j] = height[j + 1];
height[j + 1] = temp;
}
}
}
}
int
main(void)
{
int heightBoys[] = { 5, 8, 7, 9, 6 };
int heightGirls[] = { 3, 1, 2 };
int LENGTH1 = sizeof(heightBoys) / sizeof(heightBoys[0]);
int LENGTH2 = sizeof(heightGirls) / sizeof(heightGirls[0]);
sort_height(heightBoys,LENGTH1);
print_single(heightBoys,LENGTH1,"boys");
sort_height(heightGirls,LENGTH2);
print_single(heightGirls,LENGTH2,"girls");
int minlen = LENGTH1;
if (minlen > LENGTH2)
minlen = LENGTH2;
printf("\n");
printf("Pairing:\n");
for (int i = 0; i < minlen; ++i)
printf("Girl:%d Boy:%d\n",heightGirls[i],heightBoys[i]);
return 0;
}
UPDATE:
Let's say that we input heights and number of them by ourselves. If we have extra heights of boys or girls, how can we output these extra heights apart from the rest?
Two additional for loops appended to the bottom should do the trick. In order for this to work, the iteration variable of the final for loop in the previous example must be defined outside the loop. In other words, notice the definition and usage of ipair below.
If you are creating an array the type of struct that I suggested, these loops can fill it in. The array size would then need to be max(LENGTH1,LENGTH2).
And, in unpaired loops (e.g. for boy 8, the girl value in the struct could be set to 0 or -1 to indicate that the boy is unpaired)
#include <stdio.h>
void
print_single(const int *height,int len,const char *sex)
{
printf("\nHeight of %s in descending order\n",sex);
for (int i = (len - 1); i >= 0; i--)
printf(" %d", height[i]);
printf("\n");
}
void
sort_height(int *height,int len)
{
for (int i = 0; i < len; i++) {
for (int j = 0; j < (len - i - 1); j++) {
if (height[j] > height[j + 1]) {
int temp = height[j];
height[j] = height[j + 1];
height[j + 1] = temp;
}
}
}
}
int
main(void)
{
int heightBoys[] = { 5, 8, 7, 9, 6 };
int heightGirls[] = { 3, 1, 2 };
int LENGTH1 = sizeof(heightBoys) / sizeof(heightBoys[0]);
int LENGTH2 = sizeof(heightGirls) / sizeof(heightGirls[0]);
sort_height(heightBoys,LENGTH1);
print_single(heightBoys,LENGTH1,"boys");
sort_height(heightGirls,LENGTH2);
print_single(heightGirls,LENGTH2,"girls");
int minlen = LENGTH1;
if (minlen > LENGTH2)
minlen = LENGTH2;
int ipair = 0;
printf("\n");
printf("Pairing:\n");
for (; ipair < minlen; ++ipair)
printf("Girl:%d Boy:%d\n",heightGirls[ipair],heightBoys[ipair]);
if (ipair < LENGTH1) {
printf("\n");
printf("Unpaired Boys:\n");
for (int i = ipair; i < LENGTH1; ++i)
printf("Boy:%d\n",heightBoys[i]);
}
if (ipair < LENGTH2) {
printf("\n");
printf("Unpaired Girls:\n");
for (int i = ipair; i < LENGTH2; ++i)
printf("Girl:%d\n",heightGirls[i]);
}
return 0;
}

Beginner in C - Array of strings lost content after initialization in cyklus

I am trying to make array of strings each representing one card of a poker deck from 2 strings (ranks, colors). If I try print card immidietly after assignment it's ok but if I try it after all assignments nothing happend.
My "code":
int main(void)
{
char rank[] = "23456789TJQKA";
char color[] = "cdhs";
char deck[52][3];
int k = 0;
for (int i = 0; i < 13; i++) {
for(int j = 0; j < 4; j++) {
deck[k][0] = rank[i];
deck[k][1] = color[j];
deck[k][2] = 0;
k++;
printf("%s\n",deck[k-1]); // this print works
}
}
printf("%s\n",deck[0]); //this does nothing (even if I change index)
//-------------------------- here I am trying make all possible pairs but deck is now empty :(
k = 0;
char allPairs[1327][5];
for (int i = 0; i < 51; i++) {
for (int j = 0; j < 52; j++) { //**edit** - thanks ;)
allPairs[k][0] = deck[i][0];
allPairs[k][1] = deck[i][1];
allPairs[k][2] = deck[j][0];
allPairs[k][3] = deck[j][1];
allPairs[k][4] = 0;
k++;
}
}
}
All seems to work now thanks guys!
What you need to do is replace i++ with j++ in the following statement
for (int j = 0; j < 3; i++)
and also comment out the following line as it is printing 2c again:
printf("%s\n",deck[0]); //this does nothing (even if I change index)

Array values changing without reason

This is my code for Project Euler: Problem 11
int main(int argc, char** argv) {
char stevila [1600] = "08022297381500400075040507785212507791084949994017811857608717409843694804566200814931735579142993714067538830034913366552709523046011426924685601325671370236912231167151676389419236542240402866331380244732609903450244753353783684203517125032988128642367102638406759547066183864706726206802621220956394396308409166499421245558056673992697177878968314883489637221362309750076442045351400613397343133957817532822753167159403800462161409535692163905429635314755588824001754243629855786560048357189070544443744602158515417581980816805944769287392138652177704895540045208839735991607975732162626793327986688366887576220720346336746551232639353690442167338253911249472180846293240627636206936417230238834629969826759857404361620733529783190017431497148868116235705540170547183515469169233486143520189196748";
int stevilaGrid [20][20];
int stevilaRacunanje[4][4];
int stevecPoStevilih = 0;
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 20; j++) {
stevilaGrid[i][j] = (stevila[stevecPoStevilih] - 48)*10 + stevila[stevecPoStevilih + 1] - 48;
stevecPoStevilih += 2;
}
}
int rezultat [10];
int najvecji = 0;
int trenutni;
int temp = 0;
for (int i = 0; i < 17; i++) {
for (int j = 0; j < 17; j++) {
//problems start here
for (int k = 0; k < 5; k++) {
for (int l = 0; l < 5; l++) {
temp = stevilaGrid[i + k][j + l];
stevilaRacunanje[k][l] = temp;
}
}
for (int k = 0; k < 5; k++) {
rezultat[k] = stevilaRacunanje[k][0] * stevilaRacunanje[k][1] * stevilaRacunanje[k][2] * stevilaRacunanje[k][3];
rezultat[k+4] = stevilaRacunanje[0][k] * stevilaRacunanje[1][k] * stevilaRacunanje[2][k] * stevilaRacunanje[3][k];
}
rezultat[8] = stevilaRacunanje[0][0] * stevilaRacunanje[1][1] * stevilaRacunanje[2][2] * stevilaRacunanje[3][3];
rezultat[9] = stevilaRacunanje[0][3] * stevilaRacunanje[1][2] * stevilaRacunanje[2][1] * stevilaRacunanje[3][0];
for (int k = 0; k < 10; k++) {
trenutni = rezultat[k];
if(trenutni > najvecji){
najvecji = trenutni;
}
}
}
}
printf("Najvecji zmnozek: %d", najvecji);
return (EXIT_SUCCESS);
}
First I convert the string of numbers into a 2D int array.
Then I try to divide the grid into smaller 4x4 squares with which I can work more easily. That is where the problems start (as marked in the code).
At the very beginning (*i=0,j=0;k=4,j=0*) something strange starts to happen. The values in *stevilaGrid[][]* start to change randomly and seemingly without a reason.
Can somebody please explain this to me. I have tested this behavior on Windows with Cygwin 64bit and Ubuntu with GCC 64bit.
[i + k][j + l];
When i==16 and k==4 or j==16 and j==4 you'll be hitting element [20]
Your array only goes 0...19

Resources