I want to store elements of an array containing strings to make it accessible via a shared memory segment. I am currently using strcpy(), but it is obviously only storing the last string in the array. How would I make it store all 4 strings in the array? Currently I can only choose which line I would like to send (e.g. the first line with the two loops below:
Here is my loop in the server program:
for(int j = 0; j < 1;j++){
strcpy(mem,words);
}
and the client program:
for(int i = 0; i < 1; i++){
printf("%s\n",mem);
}
here is the full server program:
int main() {
const key_t key = 12345678;
FILE *ptr_fp;
char words[600][600];
char *mem;
int i = 0;
ptr_fp = fopen("words.txt","r");
int shmid = shmget(key, sizeof(float)*8, 0644 | IPC_CREAT);
if (shmid < 0) {
perror("shmget");
exit(1);
}
if (ptr_fp != NULL){
while(fgets(words[i],600,ptr_fp )&& i <600){
i++;
}
}
mem = (char *)shmat(shmid,NULL,0);
if(mem == (char *)-1){
perror("shmat error\n");
exit(1);
} else {
for(int j = 0; j < 1;j++){
strcpy(mem,words);
}
printf("Memory is attached\n");
}
return 0;
}
This looks like a copy-paste mistake.
In this while loop, i gets updated.
while(fgets(words[i],600,ptr_fp )&& i <600) {
i++;
}
In the for loop, j should be compared to i in the controlling expression, instead it is compared with 1
for(int j = 0; j < 1; j++) {
strcpy(mem,words);
}
I think the above should be changed to:
for(int j = 0, k = 0; j < i; j++) {
strcpy((mem + k),words[j]);
k = k+ strlen(words[j]);
}
Related
So I have a project where I needed to implement the game of life and then parallelise it in c. However, when I try using pthreads.h to parallelise it the program runs slower when introducing more threads and the %CPU is lower than 100% (when using top in the ubuntu terminal, I have an Ubuntu Windows subsystem). Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
/* Parallel code with PTHREADS v1 */
//Global variables
int N; // Size of the world
int nthreads; // Number of threads
pthread_mutex_t lock;
typedef struct info_thread
{
int threadID; // thread ID
int low; // lower limit of interval
int high; // higher limit of interval
int **world; // pointer to the world matrix
int **neighbors; // pointer to the neighbors matrix
//int **neighbors_2; // pointer to the neighbors_2 matrix
//int **one_step; // pointer to the one_step matrix
}t_info;
void * thread_func(void *arg);
void print_world(int **world);
void count_neighbors(int **world, int **neighbors);
void next_step(int **world, int **one_step, int **neighbors);
void update(int **world, int **one_step);
int compare(int **world, int **one_step, int **two_steps, int **old, int status);
int main(int argc, const char *argv[])
{
if (argc != 5)
{
printf("Give the following input arguments:\n");
printf("N: Size of the NxN world (integer)\n");
printf("Initial state: random (0), chessboard (1)\n");
printf("Output: Number of steps until final state (0) \n");
printf(" Number of steps until final state, initial and final states (1) \n");
printf(" Number of steps until final state and all states states (2) \n");
printf("Threads: Number of threads (integer)\n");
exit(0);
}
N = atoi(argv[1]);
const int pattern = atoi(argv[2]);
const int output = atoi(argv[3]);
nthreads = atoi(argv[4]);
// Create necessary matrices
const int n = N+1;
int **buffer = (int **)malloc(6 * n * sizeof(int *));
for(int i = 0; i < (6*n); i++)
{
buffer[i] = (int *)malloc(n*sizeof(int));
}
int **world = &buffer[0];
int **neighbors = &buffer[n];
int **neighbors_2 = &buffer[2*n];
int **one_step = &buffer[3*n];
int **two_steps = &buffer[4*n];
int **old = &buffer[5*n];
// Setting a random initial pattern
if(pattern == 0){
srand(time(0));
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
int r = rand() % 10;
if (r > 5)
world[i][j] = 1;
else
world[i][j] = 0;
}
}
}
// Setting a chessboard initial state
else if(pattern == 1){
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
if(i%2 == 0){
if(j%2 == 0)
world[i][j] = 0;
else
world[i][j] = 1;
}
else{
if(j%2 == 0)
world[i][j] = 1;
else
world[i][j] = 0;
}
}
}
}
if(output==1 || output==2){
printf("Initial state:\n");
print_world(world);
}
int status = 1;
int t = 1;
update(old, world);
// Create threads and input info
pthread_t thread[nthreads];
t_info threadinfo[nthreads];
const int interval = N/nthreads;
while(status == 1)
{
for (int k=0; k<nthreads; k++)
{
threadinfo[k].threadID = k;
threadinfo[k].low = k*interval;
threadinfo[k].high = (k+1)*interval-1;
threadinfo[k].world = world;
threadinfo[k].neighbors = neighbors;
}
threadinfo[nthreads-1].high = N;
// Predict one step forward
pthread_mutex_init(&lock, NULL);
for (int k=0; k<nthreads; k++)
pthread_create(&thread[k], NULL, thread_func, (void *)&threadinfo[k]);
for (int k=0; k<nthreads; k++)
pthread_join(thread[k],NULL);
pthread_mutex_destroy(&lock);
next_step(world, one_step, neighbors);
// Predict two steps forward
for (int k=0; k<nthreads; k++)
{
threadinfo[k].world = one_step;
threadinfo[k].neighbors = neighbors_2;
}
for (int k=0; k<nthreads; k++)
pthread_create(&thread[k], NULL, thread_func, (void *)&threadinfo[k]);
for (int k=0; k<nthreads; k++)
pthread_join(thread[k],NULL);
//count_neighbors(one_step,neighbors_2);
next_step(one_step, two_steps, neighbors_2);
// Compare all predicted steps
status = compare(world, one_step, two_steps, old, status);
// Update world with two steps
update(world, two_steps);
for(int i = 0; i < N; i++)
{
for(int j = 0; j < N; j+=2)
{
neighbors[i][j] = 0;
neighbors[i][j+1] = 0;
neighbors_2[i][j] = 0;
neighbors_2[i][j+1] = 0;
}
}
if((output == 2) && (status == 1)){
printf("Step %d:\n", t);
print_world(one_step);
printf("Step %d:\n", t+1);
print_world(two_steps);
}
// Save previous step
update(old, world);
//t+=1;
t+=2;
}
//printf("It took %d steps to reach the final state\n", t-2);
printf("It took %d steps to reach the final state\n", (t-3));
if(output==1 || output ==2){
printf("Final state:\n");
print_world(world);
}
for (int i = 0; i < (6*n); i++)
{
free(buffer[i]);
}
free(buffer);
}
void * thread_func(void *arg)
{
pthread_mutex_lock(&lock);
t_info *threadinfo = arg;
int threadID = threadinfo->threadID;
int low = threadinfo->low;
int high = threadinfo->high;
//int **world = threadinfo->world;
//int **neighbors = threadinfo->neighbors;
int i; //rows
int j; //col
for (i = low; i <= high; i++){
for (j = 0; j <= N-1; j++){
if (i > 0){
if (j > 0){
if (threadinfo->world[i-1][j-1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (j < N-1){
if (threadinfo->world[i-1][j+1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (threadinfo->world[i-1][j] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (i < N-1){
if (j > 0){
if (threadinfo->world[i+1][j-1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (j < N-1){
if (threadinfo->world[i+1][j+1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (threadinfo->world[i+1][j] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (j > 0){
if (threadinfo->world[i][j-1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if(j < N-1){
if (threadinfo->world[i][j+1] == 1)
threadinfo->neighbors[i][j] +=1;
}
}
}
pthread_mutex_unlock(&lock);
pthread_exit(NULL);
}
void print_world(int **world)
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j+=2)
{
printf("%d ", world[i][j]);
printf("%d ", world[i][j+1]);
}
printf("\n");
}
printf("\n");
}
void count_neighbors(int **world, int **neighbors)
{
int i; //rows
int j; //col
for (i = 0; i <= N-1; i++){
for (j = 0; j <= N-1; j++){
if (i > 0){
if (j > 0){
if (world[i-1][j-1] == 1)
neighbors[i][j] +=1;
}
if (j < N-1){
if (world[i-1][j+1] == 1)
neighbors[i][j] +=1;
}
if (world[i-1][j] == 1)
neighbors[i][j] +=1;
}
if (i < N-1){
if (j > 0){
if (world[i+1][j-1] == 1)
neighbors[i][j] +=1;
}
if (j < N-1){
if (world[i+1][j+1] == 1)
neighbors[i][j] +=1;
}
if (world[i+1][j] == 1)
neighbors[i][j] +=1;
}
if (j > 0){
if (world[i][j-1] == 1)
neighbors[i][j] +=1;
}
if(j < N-1){
if (world[i][j+1] == 1)
neighbors[i][j] +=1;
}
}
}
}
void next_step(int **world, int **one_step, int **neighbors)
{
int i, j;
for (i = 0; i < N; i++){
for (j = 0; j < N; j++){
if (world[i][j] == 1)
{
if (neighbors[i][j] == 2 || neighbors[i][j] == 3)
one_step[i][j] = 1;
else
one_step[i][j] = 0;
}
else if (world[i][j] == 0)
{
if (neighbors[i][j] == 3)
one_step[i][j] = 1;
else
one_step[i][j] = 0;
}
}
}
}
void update(int **world, int **one_step)
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j+=2)
{
world[i][j] = one_step[i][j];
world[i][j+1] = one_step[i][j+1];
}
}
}
int compare(int **world, int **one_step, int **two_steps, int **old, int status)
{
int counter1=0, counter2=0, counter3=0;
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
if(world[i][j] == one_step[i][j])
counter1++;
if(world[i][j] == 0)
counter2++;
if(old[i][j] == two_steps[i][j])
counter3++;
}
}
if (counter1 == (N*N))
status = 0;
else if(counter2 == (N*N))
status = 0;
else if(counter3 == (N*N))
status = 0;
return status;
}
When I compile the code and run it using 2, 4 and 8 threads I get the following:
gcc -o gol gol.c -lpthread
time ./gol 500 1 0 2
It took 1670 steps to reach the final state
real 0m10.064s
user 0m8.971s
sys 0m0.246s
time ./gol 500 1 0 4
It took 1670 steps to reach the final state
real 0m15.694s
user 0m9.976s
sys 0m0.437s
time ./gol 500 1 0 8
It took 1670 steps to reach the final state
real 0m14.600s
user 0m10.400s
sys 0m0.855s
Also the %CPU using top is ~65% when using 2 threads, ~78% when using 4 threads and ~100% when using 8 threads. What am I doing wrong?
You've got 2 problems:
a) Creating threads and waiting for them to terminate adds overhead. Doing it inside a "while(status == 1)" loop means that you're paying for that extra overhead repeatedly. It'd be better to create the threads once (outside the loop) then re-use the existing threads, using something (e.g. condition variable) to make the threads wait for the next iteration of the loop.
b) Mutexes exist to prevent (unwanted) parallelism, and also have overhead. If the threads acquire a mutex, then do their work, then release a mutex; then you're deliberately preventing all parallelism between these threads. For your code, parallelism between the main thread and the newly created threads is also prevented (main thread sits waiting in a pthread_join()).
Essentially; you've added lots of overhead (creating and destroying threads, acquiring and releasing mutexes) and prevented all parallelism to ensure that there's no benefits to outweigh the extra overhead; leading to code that is worse than not using threads at all.
To fix this you need to find ways to ensure that threads can do useful work in parallel. The easiest way to do that would probably be to use 2 global arrays to represent the state of the world, where one of these arrays is "previous world state" and the other is "next world state", and where you swap (pointers to) the arrays between steps. In this case, during a step, "previous world state" is only being read (and many threads can read in parallel without a problem) and each thread can update different parts of "next world state" in parallel. Note that because the threads would write to each cell in "next world state" you won't need to clear "next world state" between steps either.
WARNING: To ensure that updating one element of the array won't cause "lack of atomicity" problems with other/adjacent elements in the array; you will need to either use an atomic type (sig_atomic_t, C11 I think) with a 2D array, or use "1D array of pointers to 1D arrays" (where each row can only be modified by one thread) and the element/s are volatile. Note that if the world state is an 8 * 8 grid you can probably represent a whole row with a single uint8_t (meaning that it could become "1D array of pointers to volatile uint8_t).
Basically (if you include the re-use of threads) it can be done without using any mutexes for anything other than worker threads waiting for the main thread to start the next step, and the main thread waiting for worker threads to complete the current step.
Also; instead of waiting for worker threads, the main thread can also participate in doing useful work. For example, if the world state is an 8 * 8 grid, then "main thread + 7 worker threads" can do a row each (in parallel) to ensure that all 8 rows are done. However, when threads have the same priority it's rarely sane to have more threads than CPUs; so it can be a good idea to check how many CPUs the computer has and limit the number of threads (e.g. if there are 4 CPUs, then you might have "main thread + 3 more threads do 2 rows each").
I had a task and the program is working, for the most part, however, it crashes if I put SPLIT value between 4 and 7 (crashes at different values, if I change SIZE, but for sake of simplicity, let's keep it at 10).
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#define SIZE 10
#define SPLIT 4
#define LOW 0
#define HIGH 10
void generateArray(int data[],int size,int low, int high){
srand(time(NULL));
for(int i=0;i<size;++i){
data[i]=rand()%(high-low+1)+low;
}
}
int splitData(int arraySize, int startArray[], int splitPoint, int **firstNewArray, int **secondNewArray){
if(arraySize < 1){
return -1;
}
if(splitPoint < 1 || (splitPoint >= arraySize)){
return -1;
}
if(*firstNewArray != NULL || *secondNewArray != NULL){
return -1;
}
*firstNewArray = malloc(splitPoint * sizeof(int));
*secondNewArray = malloc((arraySize - splitPoint) * sizeof(int));
for(int i = 0; i < arraySize; ++i){
if(i < splitPoint){
(*firstNewArray)[i] = startArray[i];
printf("%d\n",startArray[i]);
}else{
(*secondNewArray)[i] = startArray[i];
printf("%d\n",startArray[i]);
}
}
return 0;
}
int main(){
int arraySize = SIZE ;
int *startArray = malloc(arraySize * sizeof(int));
generateArray(startArray,arraySize,LOW,HIGH);
int splitPoint = SPLIT;
int *firstNewArray = NULL;
int *secondNewArray = NULL;
int result;
result = splitData(arraySize, startArray, splitPoint, &firstNewArray, &secondNewArray);
if(result == 0){
for(int i = 0; i < arraySize; ++i){
if(i < splitPoint){
printf("First array number %d is %d\n",i+1,firstNewArray[i]);
}else{
printf("Second array number %d is %d\n",i,secondNewArray[i]);
}
}
free(firstNewArray);
free(secondNewArray);
}
free(startArray);
return 0;
}
What could be the cause of this behavior and how could I fix it? The task is to split startArray by the value SPLIT into 2 new dynamic arrays, that would be created in a function splitData and both of them could be used outside the function.
You have two issues with your code
first when you display the results:
for(int i = 0; i < arraySize; ++i){
if(i < splitPoint){
printf("First array number %d is %d\n",i+1,firstNewArray[i]);
}else{
printf("Second array number %d is %d\n",i,secondNewArray[i]);
}
}
This will not work specialy if array size is too higth or too low, example splitPoint is 9, this means secondNewArray Size is 1 but in this loop you are accessing secondNewArray[9] where it should be 0, you need to change the loop into something like this
for(int i = 0; i < splitPoint; ++i){
printf("First array number %d is %d\n",i+1,firstNewArray[i]);
}
for(int i = 0; i < SIZE - splitPoint; ++i){
printf("Second array number %d is %d\n",i+splitPoint+1 ,secondNewArray[i]);
}
You have the same isssue in your split function:
for(int i = 0; i < arraySize; ++i){
if(i < splitPoint){
(*firstNewArray)[i] = startArray[i];
printf("%d\n",startArray[i]);
}else{
(*secondNewArray)[i] = startArray[i];
printf("%d\n",startArray[i]);
}
}
In this case also you are accessing regions outside the size of your array, let say split is 9 you will be accessing secondNewArray[9] = startArray[9] where it should be secondNewArray[0] = startArray[9], to fix this you need to do the same thing here where you use different index for each array, the code should look like this:
int j = 0;
int k = 0;
for(int i = 0; i < arraySize; ++i){
if(i < splitPoint) {
(*firstNewArray)[j] = startArray[i];
printf("%d\n",startArray[i]);
j++;
}
else {
(*secondNewArray)[k] = startArray[i];
printf("%d\n",startArray[i]);
k++;
}
}
Take a hard look at the marked line below
for(int i = 0; i < arraySize; ++i){
if(i < splitPoint){
(*firstNewArray)[i] = startArray[i];
printf("%d\n",startArray[i]);
}else{
(*secondNewArray)[i] = startArray[i]; // LOOK HERE
printf("%d\n",startArray[i]);
}
Assuming an array size of 10 and a split point of 4, then *secondNewArray is indexed from 0 to 5; however, you’re trying to assign elements 4 through 9, which is outside the bounds of the array, leading to undefined behavior. You need to adjust the value of i in order to map properly:
(*secondNewArray)[i - splitPoint] = startArray[i];
I'm having problems by freeing the elements on my struct.
long code warning
typedef struct bingo
{
char board[5][5];
int* luckNum;
int* boardNum;
} bingo;
void update(bingo *pBingo,int num); //Function that gets a struct, number and checks if he is in the board, if it does he change it to "X"
int main(void)
{
srand(time(NULL));
int i, j, m, k, temp[75], *parr;
bingo player;
//For rellocating them later
if (!(player.luckNum = (int*) malloc(sizeof(int))))
{
printf("ERROR");
}
if (!(player.boardNum = (int*) malloc(sizeof(int))))
{
printf("ERROR");
}
//giving temp values of 1-75
for ( i = 0; i < 75; i++)
{
temp[i] = i + 1;
}
//Giving the player board random values of 1-75 without repeating the same number twice
for ( i = 0; i < 5; i++) //Passing on the rows
{
for (j = 0; j < 5; j++) //Passing on the columns
{
//
do
{
k = rand() % 75; //from 0-74
}
while (temp[k] == NULL); //while temp[k] is marked
player.board[i][j] = temp[k];
temp[k] = NULL; //NULL as a "flag" that marks the cell as taken (for not taking the same number twice)
player.luckNum=(int*) malloc(sizeof(int)*(i*j+j));
player.luckNum[i*j + j] = player.board[i][j];
}
}
//sets luckNum
for ( i = 0; i < 25; i++)
{
printf("%d ", player.luckNum[i]);
update(&player, player.luckNum[i]);
}
printf("\n");
for ( i = 0; i < 25; i++)
{
printf("%d",player.luckNum);
}
free(player.boardNum);
free(player.luckNum);
getchar();
return 0;
}
void update(bingo *pBingo, int num)
{
int i, j, k;
static int counter = 0,luckCounter = 25;
for (i = 0; i < 5; i++)
{
for (j = 0; j < 5; j++)
{
if (num == (int) (pBingo->board[i][j]))
{
pBingo->board[i][j] = 'X';
counter++;
pBingo->boardNum = (int*) realloc(pBingo->boardNum, sizeof(int)*counter);
pBingo->boardNum[counter] = num;
for (k = 0; k < luckCounter; k++)
{
if (pBingo->luckNum[k] == num)
{
num = pBingo->luckNum[k];
pBingo->luckNum[k] = pBingo->luckNum[luckCounter-1];
pBingo->luckNum[luckCounter-1] = num;
pBingo->luckNum = (int*) realloc(pBingo->luckNum, sizeof(int)*luckCounter);
luckCounter--;
}
}
}
}
}
}
Can anyone recognize what interrupts the free() function from freeing the memory?. I'm new to C and working on this code about good days so sorry for my ignorance about free() function, can anyone help me?
Ilan,
Don't be afraid to post your code with the necessary includes. First of all, are you heeding to the warnings of your compiler?
A few problem areas:
while (temp[k] == NULL)
You can research the difference between 0, NULL and '\0' but reserve the use of NULL for pointers. Also:
for ( i = 0; i < 25; i++)
{
printf("%d",player.luckNum);
}
Printf is expecting an integer and you're giving it a pointer. Finally, to address what I think is your problem, when you write "..interrupts the free() function from freeing the memory?" Do you mean your program simply not returning? If so then get rid of the final getchar(). You're still going to have at least one leak in this program. This address of this malloc:
if (!(player.luckNum = (int*) malloc(sizeof(int))))
will be lost as you assigned luck.Num a new address here without freeing the first:
player.luckNum=(int*) malloc(sizeof(int)*(i*j+j));
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
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.