I'm working on a cybersecurity program where I need to split a string of plaintext into blocks of a certain size. The code I currently have does not work but is close. Certain letters are either skipped, or the blocks end up being larger than the block size. Additionally, characters appear that are not represented in the plaintext, but I am unsure of how this could even occur. Could anyone fix this code for me or illuminate where I am going wrong?
Example plaintext: abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
Example output:
In the following code, plaintext_len_no_pad is the string of plaintext I want to break into chunks of size size. The size in this case is 2.
// Split plaintext into blocks size n
int total_blocks = plaintext_len_no_pad / size;
printf("DEBUG Total blocks: %d\n", total_blocks);
char blocks[total_blocks][size + 1];
int k = 0;
for (int i = 0; i < total_blocks; i++)
{
for (int j = 0; j < size; j++)
{
blocks[i][j] = plaintext_no_pad[j + k];
}
blocks[i][k + 1] = '\0';
k += size;
}
for (int i = 0; i < total_blocks; i++)
{
printf("DEBUG Block %d: %s\n", i, blocks[i]);
}
I've tried adjusting where I put the string terminating character, and messed with different ways of splitting the string. This method I whipped up has a bug I cannot figure out. I have looked at related posts, but I have not found one that helped.
blocks[i][k + 1] = '\0';
is most definitely not right.
The first iteration of the outer loop it will be equivalent to blocks[i][1]. The second iteration it will be equivalent to blocks[i][size + 1] which is out of bounds. Then it get further out of bounds.
You should be using
blocks[i][size] = '\0';
instead.
Also be careful if plaintext_len_no_pad is not evenly divisible by size (i.e. when plaintext_len_no_pad % size != 0).
Related
I need some assistance in C language.
Assuming I have an array of 10 elements:
int arr[10] = {1,2,999,4,5,999,7,999,9,10};
I want to add the number 1000 at every position where 999 is found without deleting it of course. Or in that case positions where 1000 has to be added: arr[2], arr[5], arr[7]
So my result buffer would be after compiling (of course increased by the amount of positions where 999 has been added):
temp[100] = {1,2,1000,999,4,5,1000,999,7,1000,999,9,10};
Can you help me with that?
You can do this by using conditionals like given below.
//I assume that the arrays are already declared
int i,j;
for(i = 0, j = 0; i < n; i++ , j++){ //here n is the size of the array
if(arr[j] == 999){
temp[i] = 1000;
i++; n++;
temp[i] = 999;
}
else
temp[i] = arr[j];
}
Try this out. This code snippet may not seem so standard but this gives you your desired output...
I wrote a small program to combine two 2d arrays. Here is the code:
#define MAX 7
int main(void) {
int i, j;
char *array1[] = {"Welt,", "bist", "du"};
char *array2[] = {"noch", "zu", "retten?"};
char final[MAX][MAX];
for(i = 0; i < 3; i++) {
// initialize ith names element with first name
strcpy(final[i], array1[i]);
}
for(j = 0; j < 3; j++) {
// concatenate the last name to the firstname+space string
strcat(final[i], array2[j]);
}
for (i = 0; i != 6; i++) {
printf("%s", final[i]);
}
return EXIT_SUCCESS;
}
I get really strange output like:
Welt,bistbistdunochzuretten?uretten?en?
while what I want is this:
Welt,bistdunochzuretten
As you can see it is not completely wrong. There should not be a space between the words.
How can I fix my code?
The problems were that in the second for you were doing strcat(final[3], array2[j]);, because i was 3 at that point and in the final for you were trying to print from final[0] to final[5], when you only had defined final[0] to final[3] (where on final[0] to final[2] you had the names, and in final[3] you had all the last names concatenated which also exceeded the limit of characters), and without printing them in a new line it was hard to tell which string was what.
Try this.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 7
int main(void) {
int i,j;
char *array1[] = {"Welt","bist","du"};
char *array2[] = {"noch","zu","retten?"};
char final[MAX][MAX];
for(i=0;i<3;i++)
strcpy(final[i], array1[i]); //To initialize ith names element with first name
for(j=0;j<3;j++)
strcat(final[j],array2[j]); //Concatanate the last name to the firstname+ space string
for (i = 0; i < 3; i++)
printf("%s\n", final[i]);
return EXIT_SUCCESS;
}
There are several problems with your code:
The constant MAX is not large enough for your data. The string "retten?" contains seven characters plus one terminating byte. As such, MAX must be at least 8, otherwise you get undefined behavior.
Your second loop contains uses the wrong index into final[i]. See point 3. for corrected versions.
The use of strcat() is wrong, you should be using strcpy() just like in the first loop. Together with point 2., your second loop should either look like this:
for(j = 0; j < 3; i++, j++) { //add increment for i
strcpy(final[i], array2[j]);
}
or like this:
for(j = 0; j < 3; j++) {
strcpy(final[3 + j], array2[j]); //derive the index from j
}
Regarding Point 1, I always advise against using any compile time constants like MAX. My experience is that these are just bugs that are waiting to strike. Someday, someone will have a use case that exceeds the limit, and your program goes boom. I always allocate buffers to fit the strings that I need to store, leaving the available RAM as the only limit to my code. To this end, functions like strdup() and asprintf() are extremely handy because they already do the allocation for me.
Regarding Point 2, you should try to declare all your loop variables right inside the initialization statement. Like so:
for(int i = 0; i < 3; i++) {
// initialize ith names element with first name
strcpy(final[i], array1[i]);
}
That way you don't run the danger of inadvertently using the loop variable after the loop / forgetting the initialization, etc. because your compiler will complain about the unknown variable.
I wrote the following code to check whether a string is a palindrome using stacks. I'm not getting the correct output whenever there are two same continuous characters in the string. For example, the code does say exe is a palindrome. But it says ee is not a palindrome.
int is_palindrome(char str[]) {
int j, top = -1;
char stk_item, s[30];
for (j = 0; j < strlen(str); j++)
s[top++] = str[j];
for (j = 0; j < strlen(str); j++) {
stk_item = s[--top];
if (str[j] != stk_item) return 0; // is not a palindrome
}
return 1; // is a palindrome
}
What may be the issue?
You confused the pre-increment and post-increment operators.
In C, x++ means "increment the value of x after this statement" and ++x means "first increment the value of x and then execute the statement."
The following code should work:
int is_palindrome(char str[]) {
int j, top = -1;
char stk_item, s[30];
for (j = 0; j < strlen(str); j++)
s[++top] = str[j];
for (j = 0; j < strlen(str); j++) {
stk_item = s[top--];
if (str[j] != stk_item) return 0;
}
return 1;
}
First of all, stacks work on Last-In First-Out technique. The last thing you insert into a stack is the first thing which gets out of it.
Basically speaking, there are two things you could do onto a stack, which are insert an object into the stack (typically called push) and remove an object from the stack (typically called pop).
In push technique, you assign the lowest available empty index to the object given. And thus it ought to be s[++top] = str[j]. Because you first increase the index and then fill it with an object.
In pop technique, you just reduce the highest filled index by 1. And thus it ought to be stk_item = s[top--]. Because you first say that the removed object is top and then reduce the index.
I have to write a program that does global alignment between two sequences using affine gap penalty function. The dynamic algorithm (modified Needleman Wunsch) calculates similarity (maximum score that express how similar sequences are) of two given sequences, s and t. And it takes into account gaps, blocks of consecutive spaces in a sequence, which are more likely to occur then isolated spaces, by building three 2d arrays. The arrays could be not so formally described as:
array C: keeps maximum score for blocks that end with a character of sequence s aligned with a character of sequence t;array BS: keeps maximum score for blocks that end with a character of sequence t aligned with a space in sequence s
array BT: keeps maximum score for blocks that end with a character of sequence s aligned with a space in sequence t;
The algorithm has the following recurrence relation:
C[i,j] = v(s[i],t[j]) + max{C[i-1][j-1], BS[i-1][j-1], BT[i-1][j-1]}
BS[i,j] = max{C[i][j-1]-(h+g), BS[i][j-1]-g, BT[i][j-1]-(h+g)}
BT[i,j] = max{C[i-1][j]-(h+g), BS[i-1][j]-(h+g), BT[i-1][j]-g}
** v(s[i],t[i]) = value of match(when both character are identical) or mismatch(when characters are not identical)
Similarity is the highest value among the last value of each array. The problem is when I run the program it has a strange behaviour:
For a given pair of sequences, my program gives different values for the same pair of sequences if I change which one is t or s. So, could you please help me to find out why the program has such behaviour? Do you have any idea of what I'm doing wrong? And about the code, here it goes:
int main (void){
int mat, mis, h, g,
sim, i, j, m, n;
/* mat = match, mis = mismatch, h = open gap penalty, g = extend gap penalty */
string s, t;
s = malloc(1500);
t = malloc(1500);
scanf("%d %d %d %d", &mat, &mis, &h, &g);
scanf("%s", s);
scanf("%s", t);
m = strlen(s);
n = strlen(t);
int C[m][n], BS[m][n], BT[m][n];
C[0][0] = 0;
for(j = 1; j<= n; j++)
C[0][j] = -32000;
for(i = 1; i<= m; i++)
C[i][0] = -32000;
for(j = 1; j <= n; j++)
BS[0][j] = -(h + g*j);
for(i = 0; i <= m; i++)
BS[i][0] = -32000;
for(j = 0; j <= n; j++)
BT[0][j] = -32000;
for(i = 1; i <= m; i++)
BT[i][0] = -(h + g*i);
for(i = 1; i <= m; i++){
for(j = 1; j <= n; j++){
C[i][j] = align(s[i-1],t[j-1],mat,mis) + max(C[i-1][j-1],BS[i-1][j-1],BT[i-1][j-1]);
BS[i][j] = max((C[i][j-1]-(h+g)),(BS[i][j-1]-g),(BT[i][j-1])-(h+g));
BT[i][j] = max((C[i-1][j]-(h+g)),(BS[i-1][j]-(h+g)),(BT[i-1][j]-g));
}
}
printf("\n");
printf("c[m][n]: %d bs[m][n]:%d bt[m][n]: %d\n", C[m][n], BS[m][n], BT[m][n]);
sim = max(C[m][n], BS[m][n], BT[m][n]);
printf("sim: %d\n", sim);
return 0;
}
Ok, I finally find out the problem after trying many printfs, since I don't know how to use debuggers.The first clue I had was the segmentation fault that gcc was telling me when I tryed to read the sequences (with a relatively big length) from files. It's true that segmentation fault can have several causes, but almost all the times I saw this error in my programs, it occured because I was trying to access a position that actually didn't exist in the array.
Then the many printfs showed some values in the initialization step, which were different from what the first row and first column of each array should have. I associated the segmentation fault with the strange values from initialization step, and decided to check the declaration step of the arrays as well as all loop conditions. There it was! I simply forgot a very basic feature of any array: if the array has size n, you can access from zero to n-1. To solve my very newbie error, I added one position for row and column in each array (since the position (0,0) is not associated with any pair of aligned characters) so that each array has size [m][n], where m is the (length + 1) of sequence s, and n is the (length+1) of sequence t. Furthermore, I altered all loop conditions to access till [m-1][n-1] position. Now the program works fine.
I am having trouble with a homework question that I've been working at for quite some time.
I don't know exactly why the question is asking and need some clarification on that and also a push in the right direction.
Here is the question:
(2) Solve this problem using one single subscripted array of counters. The program uses an array of characters defined using the C initialization feature. The program counts the number of each of the alphabetic characters a to z (only lower case characters are counted) and prints a report (in a neat table) of the number of occurrences of each lower case character found. Only print the counts for the letters that occur at least once. That is do not print a count if it is zero. DO NOT use a switch statement in your solution. NOTE: if x is of type char, x-‘a’ is the difference between the ASCII codes for the character in x and the character ‘a’. For example if x holds the character ‘c’ then x-‘a’ has the value 2, while if x holds the character ‘d’, then x-‘a’ has the value 3. Provide test results using the following string:
“This is an example of text for exercise (2).”
And here is my source code so far:
#include<stdio.h>
int main() {
char c[] = "This is an example of text for exercise (2).";
char d[26];
int i;
int j = 0;
int k;
j = 0;
//char s = 97;
for(i = 0; i < sizeof(c); i++) {
for(s = 'a'; s < 'z'; s++){
if( c[i] == s){
k++;
printf("%c,%d\n", s, k);
k = 0;
}
}
}
return 0;
}
As you can see, my current solution is a little anemic.
Thanks for the help, and I know everyone on the net doesn't necessarily like helping with other people's homework. ;P
char c[] = "This is an example of text for exercise (2).";
int d[26] = {0}, i, value;
for(i=0; i < sizeof(c) - 1; i++){ //-1 to exclude terminating NULL
value = c[i]-'a';
if(value < 26 && value >= 0) d[value]++;
}
for(i=0; i < 26; i++){
if(d[i]) printf("Alphabet-%c Count-%d\n", 'a'+i, d[i]);
}
Corrected. Thanks caf and Leffler.
The intention of the question is for you to figure out how to efficiently convert a character between 'a' and 'z' into an index between 0 and 25. You are apparently allowed to assume ASCII for this (although the C standard does not guarantee any particular character set), which has the useful property that values of the characters 'a' through 'z' are sequential.
Once you've done that, you can increment the corresponding slot in your array d (note that you will need to initialise that array to all-zeroes to begin with, which can be done simply with char d[26] = { 0 };. At the end, you'd scan through the array d and print the counts out that are greater than zero, along with the corresponding character (which will involve the reverse transformation - from an index 0 through 25 into a character 'a' through 'z').
Fortunately for you, you do not seem to be required to produce a solution that would work on an EBCDIC machine (mainframe).
Your inner loop needs to be replaced by a conditional:
if (c[i] is lower-case alphabetic)
increment the appropriate count in the d-array
After finishing the string, you then need a loop to scan through the d-array, printing out the letter corresponding to the entry and the count associated with it.
Your d-array uses 'char' for the counts; that is OK for the exercise but you would probably need to use a bigger integer type for a general purpose solution. You should also ensure that it is initialized to all zeros; it is difficult to get meaningful information out of random garbage (and the language does not guarantee that anything other than garbage will be on the stack where the d-array is stored).
char c[] = "This is an example of text for exercise (2).";
char d[26];
int i;
int j;
for(i = 0; i < 26; i++)
{
d[i] = 0; // Set the frequency of the letter to zero before we start counting.
for(j = 0; j < strlen(c); j++)
{
if(c[j] == i + 'a')
d[i]++;
}
if(d[i] > 0) // If the frequency of the letter is greater than 0, show it.
printf("%c - %d\n", (i + 'a'), d[i]);
}
.
for(s = 'a'; s < 'z'; s++){
j=0;
for(i = 0; i < sizeof(c); i++) {
if( c[i] == s )
j++;
}
if (j > 0)
printf("%c,%d\n", s, j);
}