I wrote a function that sorts an array of strings by their length
void lenSort(char sen[][NAME_LENGTH], int len)
{
int i = 0, j = 0, k = 0;
char tmp[NAME_LENGTH] = {0};
for(i = 0; i < len - 1; i++)
{
for(j = 0; j < len - i - 1; j++)
{
if(strlen(sen[j]) > strlen(sen[j+1]))
{
strncpy(tmp, sen[j], strlen(sen[j]));
for(k = 0; k < strlen(sen[j]); k++)
{
sen[j][k] = 0;
}
strncpy(sen[j], sen[j+1], strlen(sen[j+1]));
strncpy(sen[j+1], tmp, strlen(tmp));
}
}
}
}
The array I pass is: {"12345", "123", "123456", "12", "1234", "1234", "1234567", "123", "1", "12345"}
For some reason when I copy sen[j+1] into sen[j] I get excess characters, I thought that that's becuase sen[j] is longer, but I reset it before copying and it still happens and I don't have any clue why..
If you want to sort strings based on their length only then inner below for loop is not required though it may serving some other purpose
for(k = 0; k < strlen(sen[j]); k++)
{
sen[j][k] = 0;
}
here is the my solution. use strcpy() instead of strncpy() because strings copied using strncpy() are not null terminated. from the man page of strncpy
Warning: If there is no null byte among the first n bytes
of src, the string placed in dest will not be null-terminated.
void lenSort(char sen[][NAME_LENGTH], int len)
{
int i = 0, j = 0, k = 0;
char tmp[NAME_LENGTH] = {0};
for(i = 0; i < len - 1; i++)
{
for(j = 0; j < len - i - 1; j++)
{
if(strlen(sen[j]) > strlen(sen[j+1]))
{
strcpy(tmp, sen[j]);
strcpy(sen[j], sen[j+1]);
strcpy(sen[j+1], tmp);
}
}
}
}
Related
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.
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;
}
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;
}
I'm currently reading in a list of words from a file and trying to sort them line by line.
I can read each line in and print the words out just fine, but I can't seem to sort each line individually. The first line is sorted, but the second is not. Can anyone see where I'm going wrong? Thanks!
int fd;
int n_char = 0;
int charCount = 0, wordCount = 0, lineCount = 0;
int wordsPerLine[100];
char buffer;
char words[6][9];
fd = open(inputfile, O_RDONLY);
if (fd == -1) {
exit(1);
}
wordsPerLine[0] = 0;
/* use the read system call to obtain 10 characters from fd */
while( (n_char = read(fd, &buffer, sizeof(char))) != 0) {
if (buffer == '\n' || buffer == ' ') {
words[wordCount][charCount] = '\0';
charCount = 0;
wordCount++;
wordsPerLine[lineCount] += 1;
if (buffer == '\n') {
lineCount++;
wordsPerLine[lineCount] = 0;
}
} else {
words[wordCount][charCount++] = buffer;
}
}
printf("Num Words: %d --- Num Lines: %d\n", wordCount, lineCount);
char tmp[9];
int m, n;
int i, x, totalCount = 0;
for (i = 0; i < lineCount; i++) {
for (x = 0; x < wordsPerLine[i]; x++) {
/* iterate through each word 'm' in line 'i' */
for(m = 0; m < wordsPerLine[i]; m++) {
for(n = 0; n < wordsPerLine[i]; n++) {
if(strcmp(words[n-1], words[n])>0) {
strcpy(tmp, words[n-1]);
strcpy(words[n-1], words[n]);
strcpy(words[n], tmp);
}
}
} /* end sorting */
}
}
printf("Sorted:\n");
totalCount = 0;
for(i = 0; i < lineCount; i++) {
printf("Line %d (%d words)\n", i + 1, wordsPerLine[i]);
for(x = 0; x < wordsPerLine[i]; x++) {
printf("%s\n", words[totalCount++]);
}
}
My sample input file is:
great day out
foo bar food
Let's go by small parts...
To see if the problem is in the reading, comment the reading part and try to add:
char words[][9] = {"great", "day", "out", "foo", "bar", "food"};
and set the counters to the value they would with this input also...
Your loop is accessing some data out of the bounds... I would recommend you to try your sorting code with an array of numbers first and see if it is sorting them correctly...
#include<stdio.h>
#define N 6
int main()
{
char words[][9] = {"great", "day", "out", "foo", "bar", "food"};
int numbers[] = {20, 10, 50, 5, 30, -50};
int i, j, temp;
for(i = 0; i < N - 1; i++)
for(j = 0; j < N - 1; j++)
if(numbers[j] > numbers[j + 1])
{
temp = numbers[j];
numbers[j] = numbers[j + 1];
numbers[j + 1] = temp;
}
for(i = 0; i < N; i++)
{
printf("%d\n", numbers[i]);
//printf("%s\n", words[i]);
}
}
Note also that this is the least efficient implementation of bubble sort (but is the same you provided), you can improve it by adding a variable to check in the inner loop some change happened for instance(which would mean that it is already sorted and you can stop sorting)...
Also, after each iteration on the outter loop one element is going to be placed in its final place (try to find out which one), which means that you won't need to consider this element in the next iteration, so after each iteration in the outer loop the number of elements compared in the inner loop can be reduced by 1...
you can find more info about bubble sort here
/* iterate through each line */
for (i = 0; i < lineCount; i++) {
/* iterate through each word 'm' in line 'i' */
for(m = 0; m < wordsPerLine[i]; m++) {
for(n = m+1; n < wordsPerLine[i]; n++) {
if(strcmp(words[n + totalCount], words[m + totalCount]) < 0) {
strcpy(tmp, words[m + totalCount]);
strcpy(words[m + totalCount], words[n + totalCount]);
strcpy(words[n + totalCount], tmp);
}
}
} /* end sorting */
totalCount += wordsPerLine[i];
}
I just needed to keep a running count of each word per line, so i know what line to start comparing with
It crashes with a debug error and says stack around variable 'code' was corrupted. This is code for a hamming code lab I am doing. The input file is just a bunch of 1's and 0's on the same line. Why is it crashing?
void processFile(FILE* read, char* InMessage) {
int i = 0, count = 0;
for (i = 0; !feof(read); i++) {
InMessage[i] = fgetc(read);
count++;
}
InMessage[count] = '\0';
}
void hammingCode(char* InMessage) {
int len = strlen(InMessage), i = 0, j = 0;
char code[12], temp[1000];
temp[0] = '\0';
for (i = 0, j = 0; i < len; i++, j++) {
code[j] = InMessage[i];
if (j == 10) {
j = 0;
decode(code);
code[11] = '\0';
strcat_s(temp, sizeof(char)*1000, code);
}
}
strcpy_s(InMessage, sizeof(char)*1000, temp);
}
void decode(char* codeWord) {
int i = 0, j = 0, parity[4] = {0}, diffParity[4] = {0}, twoPower = 0, readNSkip = 0, bitSum = 0;
for (i = 0; i < 4; i++) {
twoPower = (int)pow((double)2, i);
for (j = twoPower; j <= 12; j++) {
if (readNSkip <= twoPower) {
if (j != twoPower) {
parity[i] += codeWord[j-2] - 48;
}
readNSkip++;
}
else {
if (readNSkip == twoPower*2)
readNSkip = 0;
readNSkip++;
}
}
if (parity[i] % 2 == 0)
parity[i] = 0;
else
parity[i] = 1;
if ((codeWord[twoPower-1] - 48) != parity[i])
diffParity[i] = 1;
}
for (i = 0; i < 4; i++) {
twoPower = (int)pow((double)2, i);
bitSum += diffParity[i]*twoPower;
}
codeWord[bitSum] = !codeWord[bitSum];
}
There's two problems I see here:
It looks to me like you are calculating the size of the InMessage buffer incorrectly in your hammingCode function:
int len = strlen(InMessage), i = 0, j = 0;
The strlen function determines the length of the string by finding the position of the first null terminator. If InMessage is not cleared, then this could give you some strange lengths as it will contain a random sequence of bytes. Conversely, if you have cleared the buffer then len will be 0.
To overcome this problem, it is better for the caller to provide the size of the buffer:
int hammingCode (char *InMessage, size_t messageSize)
And use messageSize in place of len.
It's advisable to use this same strategy for your other two functions as well as currently there is a chance of overflowing the provided buffers.
Following on from the previous problem, it may be that the decode function is writing outside the bounds of the buffer. Providing the length of the buffer to decode and adding the appropriate checks to ensure the function does not write outside the given bounds would be a good idea.