i am writing a rail fence cipher algorithm in c for fun and to brush up on my C programming skills. i have it working well for smallish input phrases, but it gets garbled for some reason when the input phrase is large.
here is the code: (sorry, i couldnt reduce it to a SSCCE, i dont know which part of the algorithm is causing the problem)
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
/* function to append a char to a char array */
void append(char* s, char c)
{
int len = strlen(s);
s[len] = c;
s[len+1] = '\0';
}
int main(void)
{
int num_rails;
for (num_rails = 2; num_rails < 6; num_rails++)
{
char* message = "therailfencecipheristrickyespeciallywhentheinputisverylongabcdefghijklmnopqrstuvwxyzblerpblorp";
int word_len = strlen(message);
char* lines[num_rails];
char* rails[num_rails];
int len_rails[num_rails];
memset(len_rails, 0, num_rails*sizeof(int));
int i,j,k,mod;
int repeats;
int period = (2*num_rails) - 2;
printf("%d characters, %d rails:\n", word_len, num_rails);
printf("\nplaintext: %s\n", message);
/* encryption */
for (i = 0; i < num_rails; i++)
{
if ((lines[i] = malloc(sizeof(char))) == NULL)
{
printf("\nUnable to allocate memory.\n");
return EXIT_FAILURE;
}
}
for (repeats = 0; repeats < ((word_len/period)+1); repeats++)
{
if (repeats*period < word_len)
append(lines[0], message[repeats*period]);
for (j = 1; j < period/2; j++)
{
if ((j + (repeats*period)) < word_len)
append(lines[j], message[j + (repeats*period)]);
if ((((repeats+1)*period) - j) < word_len)
append(lines[j], message[((repeats+1)*period) - j]);
}
if (((period/2) + (repeats*period)) < word_len)
append(lines[j], message[(period/2)+(repeats*period)]);
}
char encrypted[word_len];
strcpy(encrypted,lines[0]);
for (i = 1; i < num_rails; i++)
strcat(encrypted, lines[i]);
printf("\nciphertext: %s\n", encrypted);
/* decryption */
for (i = 0; i < num_rails; i++)
{
if ((rails[i] = malloc(sizeof(int) * 40)) == NULL)
{
printf("\nUnable to allocate memory.\n");
return EXIT_FAILURE;
}
}
mod = word_len % period;
len_rails[0] = word_len / period;
len_rails[num_rails-1] = len_rails[0];
for (i = 1; i < num_rails - 1; i++)
len_rails[i] = len_rails[0] * 2;
for (i = 0; i < mod && i < num_rails; i++)
{
len_rails[i]++;
}
for (j = i-2; i < mod && j > -1; j--)
{
len_rails[j]++;
i++;
}
printf("\nrail lengths:");
for (i = 0; i < num_rails; i++)
printf(" %d", len_rails[i]);
putchar('\n');
k = 0;
for (i = 0; i < num_rails; i++)
{
for (j = 0; j < len_rails[i]; j++)
{
append(rails[i], encrypted[k++]);
}
}
char deciphered[word_len];
strcpy(deciphered, "");
for (i = 0; i < ((word_len/period)+1); i++)
{
if (rails[0][i])
append(deciphered, rails[0][i]);
for (j = 1; j < num_rails-1; j++)
{
if (rails[j][i*2])
append(deciphered, rails[j][i*2]);
}
if (rails[num_rails-1][i])
append(deciphered, rails[num_rails-1][i]);
for (j = num_rails-2; j > 0; j--)
{
if (rails[j][(i*2)+1])
append(deciphered, rails[j][(i*2)+1]);
}
}
printf("\ndeciphered: %s\n", deciphered);
printf("==========================================\n");
}
}
it should compile and run fine so you can test it.
it is supposed to print the plain text, then encipher it and print that, then decipher the enciphered text back to plain text and print that for 2, 3, 4, 5 rails but it should work for any number of rails.
the problem is that the output gets garbled if the input variable "message" gets over a certain size for different numbers of rails.
eg.
2 rails becomes garbled at 63 characters
3 rails becomes garbled at 64 characters
4 rails becomes garbled at 95 characters
5 rails becomes garbled at 126 characters
etc.
the closest i have been able to come to working out what is wrong is that whenever any value for len_rails[] exceeds 31 the output gets garbled for that amount of rails..
does anyone have any idea why this would be? is it to do with how i am allocating memory? its been a while since i did any C programming and my memory handling is a bit rusty.
any help would be greatly appreciated..
On this line:
if ((lines[i] = malloc(sizeof(char))) == NULL)
you are only allocating memory for a single char, but then try to use the buffer for storing much more than one char of data. Multiply sizeof(char) (which is, by the way, always 1) by the number of chars you are planning to store in the array.
Remember to free() the memory just before the end.
Related
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;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am trying to code the Waterman algorithm in C.
Now when the length of the sequence exceeds 35 the program just lags.
I have no idea where to start looking, tried but got nothing worked out.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// Max Function Prototype.
int maxfunction(int, int);
// Prototype of the random Sequences generator Function.
void gen_random(char *, const int);
int main(int argc, char *argv[]) {
// Looping variable and Sequences.
int i = 0, j = 0, k = 0;
char *X, *Y;
int length1, length2;
// Time Variables.
time_t beginning_time, end_time;
// Getting lengths of sequences
printf("Please provide the length of the first Sequence\n");
scanf("%d", &length1);
printf("Please provide the length of the second Sequence\n");
scanf("%d", &length2);
X = (char*)malloc(sizeof(char) * length1);
Y = (char*)malloc(sizeof(char) * length2);
int m = length1 + 1;
int n = length2 + 1;
int L[m][n];
int backtracking[m + n];
gen_random(X, length1);
gen_random(Y, length2);
printf("First Sequence\n");
for (i = 0; i < length1; i++) {
printf("%c\n", X[i]);
}
printf("\nSecond Sequence\n");
for (i = 0; i < length2; i++) {
printf("%c\n", Y[i]);
}
// Time calculation beginning.
beginning_time = clock();
// Main Part--Core of the algorithm.
for (i = 0; i <= m; i++) {
for (j = 0; j <= n; j++) {
if (i == 0 || j == 0) {
L[i][j] = 0;
} else
if (X[i-1] == Y[j-1]) {
L[i][j] = L[i-1][j-1] + 1;
backtracking[i] = L[i-1][j-1];
} else {
L[i][j] = maxfunction(L[i-1][j], L[i][j-1]);
backtracking[i] = maxfunction(L[i-1][j], L[i][j-1]);
}
}
}
// End time calculation.
end_time = clock();
for (i = 0; i < m; i++) {
printf(" ( ");
for (j = 0; j < n; j++) {
printf("%d ", L[i][j]);
}
printf(")\n");
}
// Printing out the result of backtracking.
printf("\n");
for (k = 0; k < m; k++) {
printf("%d\n", backtracking[k]);
}
printf("Consumed time: %lf", (double)(end_time - beginning_time));
return 0;
}
// Max Function.
int maxfunction(int a, int b) {
if (a > b) {
return a;
} else {
return b;
}
}
// Random Sequence Generator Function.
void gen_random(char *s, const int len) {
int i = 0;
static const char alphanum[] = "ACGT";
for (i = 0; i < len; ++i) {
s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
}
s[len] = 0;
}
Since you null terminate the sequence in gen_random with s[len] = 0;, you should allocate 1 more byte for each sequence:
X = malloc(sizeof(*X) * (length1 + 1));
Y = malloc(sizeof(*Y) * (length2 + 1));
But since you define variable length arrays for other variables, you might as well define these as:
char X[length1 + 1], Y[length2 + 1];
Yet something else is causing a crash on my laptop: your nested loops iterate from i = 0 to i <= m, and j = 0 to j <= n. That's one step too many, you index out of bounds into L.
Here is a corrected version:
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
The resulting code executes very quickly, its complexity is O(m*n) in both time and space, but m and n are reasonably small at 35. It runs in less than 50ms for 1000 x 1000.
Whether it implements Smith-Waterman's algorithm correctly is another question.
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
int main(void)
{
int i,j=0,k; //initialization
char equation[100]; //input is a string (I think?)
int data[3]; //want only 3 numbers to be harvested
printf("Enter an equation: ");
fgets(equation, 100, stdin); //not so sure about fgets()
for (i = 0; i < equation[100]+1; i++) { //main loop which combs through
//"equation" array and attempts
//to find int values and store
while (j <= 2) { //them in "data" array
if (isdigit(equation[i])) {
data[j] = equation[i]
j++;
}
}
if (j == 2) break;
}
for (k = 0; k <= 2; k++) { //this is just to print the results
printf("%d\n", data[k]);
}
return 0;
}
Hello! This is my program for my introductory class in C, I am trying to comb through an array and pluck out the numbers and assign them to another array, which I can then access and manipulate.
However, whenever I run this I get 0 0 0 as my three elements in my "data" array.
I am not sure whether I made an error with my logic or with the array syntax, as I am new to arrays.
Thanks in advance!!! :)
There are a few problems in your code:
for (i = 0; i < equation[100]+1; i++) { should be something like
size_t equ_len = strlen(equation);
for (i = 0; i < equ_len; i++) {
Whatever the input is, the value of equation[100] is uncertain, because char equation[100];, equation only has 100 element, and the last of them is equation[99].
equation[i] = data[j]; should be
data[j] = equation[i];
I suppose you want to store digit in equation to data.
break; should be deleted.
this break; statement will jump out of the while loop, the result is you will store the last digit in equation to data[0] (suppose you have switched data and equation, as pointed out in #2).
If you want the first three digits in equation, you should do something like
equ_len = strlen(equation);
j = 0;
for (i = 0; i < equ_len; i++) {
if (j <= 2 && isdigit(equation[i])) {
data[j] = equation[i];
j++;
}
if (j > 2) break;
}
printf("%d\n", data[k]); should be printf("%c\n", data[k]);
%d will give the ASCII code of data[k], for example, if the value of data[k] is character '1', %d will print 50 (the ASCII code of '1') instead of 1.
Here is my final code, based on the OP code:
#include <ctype.h>
#include <string.h>
#include <stdio.h>
int main(void)
{
int i,j,k;
char equation[100];
int data[3];
int equ_len;
printf("Enter an equation: ");
fgets(equation, 100, stdin);
equ_len = strlen(equation);
j = 0;
for (i = 0; i < equ_len; i++) {
if (j <= 2 && isdigit(equation[i])) {
data[j] = equation[i];
j++;
}
if (j > 2) break;
}
for (k = 0; k <= 2; k++) {
printf("%c\n", data[k]);
}
return 0;
}
Tested with:
$ ./a.out
Enter an equation: 1 + 2 + 3
1
2
3
I'm still learning C and I've been trying to figure out the best way to count occurrences of characters in an array.
I plan on separating it into functions and expanding on it a lot but so far the best working code I've come up with is a bigger version of this:
#define SIZEONE 7
#define SIZETWO 3
int main(void)
{
int arrOne[SIZEONE] = {97, 97, 98, 99, 99, 99, 99};
char arrTwo[SIZETWO] = {'a', 'b', 'c'};
int arrThree[SIZETWO] = {0};
int countOne = 0;
int countTwo = 0;
int countThree = 0;
for(countOne = 0; countOne < SIZEONE; countOne++)
{
for(countTwo = 0; countTwo < SIZETWO; countTwo++)
{
if(arrOne[countOne] == arrTwo[countTwo])
{
arrThree[countTwo] = arrThree[countTwo] + 1;
}
}
}
for(countThree = 0; countThree < SIZETWO; countThree++)
{
printf("%c ",arrTwo[countThree]);
}
countThree = 0;
printf("\n");
for(countThree = 0; countThree < SIZETWO; countThree++)
{
printf("%d ",arrThree[countThree]);
}
return 0;
}
From this I should get something that looks like:
a b c
2 1 4
I'm just wondering if there is a simpler way to do this that someone can point me towards or give me an example of before I start using this method.
You can try to insert this function as an example for all array sizes :
int findOccurences(const char *array, const int array_size, const char ch_to_find)
{
int found = 0;
for(int i = 0; i < array_size; ++i)
{
if(array[i] == ch_to_find) found++;
}
return found;
}
It's a better practice to name your variables with a significant name. This will be easier to read for you and for others that can read your code.
best way is to define a counting array of 256 (or 127 for ascii only) zero it and for each occurrence increment to counting array.
void count_chars(char* arr)
{
int counting[256],i;
memset(counting,0,sizeof(counting));
for(i=0; arr[i];++i){
++counting[(unsigned char)arr[i]];
}
for(i=0; i<256;++i){
if(counting[i]){
printf("%c - %d\n", (char)i, counting[i]);
}
}
}
If you use counting sort you get less code:
long count[1u << CHAR_BIT];
char *text = "The string we want to count characters in";
long i;
// Clear count array
memset(count, 0, sizeof(count));
// Count characters
for (i = strlen(text) - 1; i >= 0; i--) {
count[(unsigned char)text[i]]++;
}
// Print occurance:
for (i = 0; i < 1u << CHAR_BIT; i++) {
if (count[i] > 0) {
printf("%4c", i);
}
}
printf("\n");
for (i = 0; i < 1u << CHAR_BIT; i++) {
if (count[i] > 0) {
printf("%4ld", count[i]);
}
}
printf("\n");