Reversing input every two characters - c

I've been trying to make a program that takes an address and reverses it for every two characters. An example input would be "0xefba5896" and ideally it's output would be "\x96\x58\xba\xef". The trouble I'm getting is that the first few bytes work, but the last one doesn't print. My code is below:
int i;
char *add = argv[1];
char rev[8];
char xa[2];
strncpy(rev, &add[2], strlen(add));
for (i = strlen(rev) - 2; i > -2; i-=2) {
if (i == 0) {
strncpy(xa, &rev[0], 2);
} else {
strncpy(xa, &rev[i], 2);
xa[2] = '\0';
}
printf("\\x%s", xa);
}
If I input "0xefba5896" my output is:
\x96\x58\xba\x
If the answer is obvious to someone, please forgive me. I've been learning C for only about a week.
Any help would be immensely appreciated!

It makes no sense to pass strlen(add) as the limiting factor to strncpy, if add is longer than 10,
you will still overflow rev!
You have to pass the size of the destination, not the size of the source. So the correct call is
strncpy(rev, add+2, sizeof rev);
rev[sizeof(rev) - 1] = 0;
Also note that strncpy does not necessarily write the '\0'-terminating byte
if the destination is not long enough, so you should always set the
'\0'-terminating byte yourself.
Also note that xa[2] = '\0'; overflows xa, because the size of xa is 2, so
the maximal index is 1. If you want to store 2 characters in xa, then
xa needs to be of at least dimension 3. Same goes for rev. So You have to declare xa as this:
char rev[9];
char xa[3];
So when you use strncpy, you should use it like this:
char dest[8];
strncpy(dest, src, sizeof dest);
dest[sizeof(dest) - 1] = 0;
So you can rewrite your program like this:
int main(int argc, char **argv)
{
if(argc != 2)
{
fprintf(stderr, "usage: %s address\n", argv[0]);
return 1;
}
size_t len;
char *add = argv[1];
char rev[9];
char xa[3];
strncpy(rev, add + 2, sizeof rev);
rev[sizeof(rev) - 1] = 0;
len = strlen(rev);
if(len & 1)
{
fprintf(stderr, "Invalid length of address, needs an even number of characters\n");
return 1;
}
for(size_t i = len - 2; i >= 0; i -= 2)
{
strncpy(xa, rev + i, sizeof xa);
xa[sizeof(xa) - 1] = 0;
printf("\\x%s", xa);
fflush(stdout);
}
putchar('\n');
return 0;
}

Related

How to rearrange array using spaces?

I'm struggling with rearranging my array. I have used from single to multiple loops trying to put spaces (white characters) between two pairs of characters, but I was constantly rewriting the original input. So there is always an input of even length, for example ABCDEFGH. And my task would be to extend the size of the array by putting spaces after every 2 chars (except the last one).
So the output would be:
AB CD EF GH
So the size of output (if I'm correct) will be (2*input_len)-1
Thanks.
EDIT:
This is my code so far
// output = "ABCDEFGHIJKL
char c1;
char c2;
char c3;
int o_len = strlen(output);
for(int i = 2; i < o_len + olen/2; i = i + 3){
if(i == 2){
c1 = output[i];
c2 = output[i+1];
c3 = output[i+2];
output[i] = ' ';
output[i+1] = c1;
output[i+2] = c2;
}
else{
c1 = output[i];
c2 = output[i+1];
output[i] = ' ';
output[i+1] = c3;
output[i+2] = c1;
c3 = c2;
}
}
So the first 3 pairs are printed correctly, then it is all a mess.
Presuming you need to store the space separate result, probably the easiest way to go about inserting the spaces is simply to use a pair of pointers (one to your input string and one to your output string) and then just loop continually writing a pair to your output string, increment both pointers by 2, check whether you are out of characters in your input string (if so break; and nul-terminate your output string), otherwise write a space to your output string and repeat.
You can do it fairly simply using memcpy (or you can just copy 2-chars to the current pointer and pointer + 1, your choice, but since you already include string.h for strlen() -- make it easy on yourself) You can do something similar to:
#include <stdio.h>
#include <string.h>
#define ARRSZ 128 /* constant for no. of chars in output string */
int main (int argc, char **argv) {
char *instr = argc > 1 ? argv[1] : "ABCDEFGH", /* in string */
outstr[ARRSZ] = "", /* out string */
*ip = instr, *op = outstr; /* pointers to each */
size_t len = strlen (instr); /* len of instr */
if (len < 4) { /* validate at least 2-pairs worth of input provided */
fputs ("error: less than two-pairs to separate.\n", stderr);
return 1;
}
if (len & 1) { /* validate even number of characters */
fputs ("error: odd number of characters in instr.\n", stderr);
return 1;
}
if (ARRSZ < len + len / 2) { /* validate sufficient storage in outstr */
fputs ("error: insufficient storage in outstr.\n", stderr);
return 1;
}
for (;;) { /* loop continually */
memcpy (op, ip, 2); /* copy pair to op */
ip += 2; /* increment ip by 2 for next pair */
op += 2; /* increment op by 2 for next pair */
if (!*ip) /* check if last pair written */
break;
*op++ = ' '; /* write space between pairs in op */
}
*op = 0; /* nul-terminate outstr */
printf ("instr : %s\noutstr : %s\n", instr, outstr);
}
Example Use/Output
$ ./bin/strspaceseppairs
instr : ABCDEFGH
outstr : AB CD EF GH
$ ./bin/strspaceseppairs ABCDEFGHIJLMNOPQ
instr : ABCDEFGHIJLMNOPQ
outstr : AB CD EF GH IJ LM NO PQ
Odd number of chars:
$ ./bin/strspaceseppairs ABCDEFGHIJLMNOP
error: odd number of characters in instr.
Or short string:
$ ./bin/strspaceseppairs AB
error: less than two-pairs to separate.
Look things over and let me know if you have further questions.
Edit To Simply Output Single-Pair or Empty-String
Based upon the comment by #chqrlie it may make more sense rather than issuing a diagnostic for a short string, just to output it unchanged. Up to you. You can modify the first conditional and move it after the odd character check in that case, e.g.
if (len & 1) { /* validate even number of characters */
fputs ("error: odd number of characters in instr.\n", stderr);
return 1;
}
if (len < 4) { /* validate at least 2-pairs worth of input provided */
puts(instr); /* (otherwise output unchanged and exit) */
return 0;
}
You can decide how you want to handle any aspect of your program and make the changes accordingly.
I think you are looking for a piece of code like the one below:
This function returns the output splitted array, as you requested to save it.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
char* split_by_space(char* str, size_t length, size_t step) {
size_t i = 0, j = 0, spaces = (length / step);
char* splitted = malloc(length + spaces + 1);
for (i = 0, j = 0; i < length; ++i, ++j) {
if (i % step == 0 && i != 0) {
splitted[j] = ' ';
++j;
}
splitted[j] = str[i];
}
splitted[j] = '\0';
return splitted;
}
int main(void) {
// Use size_t instead of int.
size_t step = 2; // Also works with odd numbers.
char str[] = "ABCDEFGH";
char* new_str;
// Works with odd and even steps.
new_str = split_by_space(str, strlen(str), step);
printf("New splitted string is [%s]", new_str);
// Don't forget to clean the memory that the function allocated.
free(new_str);
return 0;
}
When run with a step value of 2, the above code, outputs:
New splitted string is [AB CD EF GH]
Inserting characters inside the array is cumbersome and cannot be done unless you know the array is large enough to accommodate the new string.
You probably want to allocate a new array and create the modified string there.
The length of the new string is not (2 * input_len) - 1, you insert a space every 2 characters, except the last 2: if the string has 2 or fewer characters, its length is unmodified, otherwise it increases by (input_len - 2) / 2. And in case the length is off, you should round this value to the next integer, which is done in integer arithmetics this way: (input_len - 2 + 1) / 2.
Here is an example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *reformat_with_spaces(const char *str) {
size_t len = strlen(str);
size_t newlen = len > 2 ? len + (len - 2 + 1) / 2 : len;
char *out = malloc(newlen + 1);
if (out) {
for (size_t i = 0, j = 0; i < len; i++) {
if (i > 0 && i % 2 == 0) {
out[j++] = ' ';
}
out[j++] = str[i];
}
out[j] = '\0';
}
return out;
}
int main(void) {
char buf[256];
char *p;
while (fgets(buf, sizeof buf, stdin)) {
buf[strcspn(buf, "\n")] = '\0'; // strip the newline if any
p = reformat_with_spaces(buf);
if (p == NULL) {
fprintf(stderr, "out of memory\n");
return 1;
}
puts(p);
free(p);
}
return 0;
}
Try this,
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void rearrange(char *str)
{
int len=strlen(str),n=0,i;
char *word=malloc((len+(int)(len/2)));
if(word==NULL)
{
printf("Memory Error");
exit(1);
}
for(i=0;i<len;i++)
{
if( i % 2 == 0 && i != 0)
{
word[n]=' ';
n++;
word[n]=str[i];
n++;
}
else
{
word[n]=str[i];
n++;
}
}
word[n]='\0';
strcpy(str,word);
free(word);
return;
}
int main()
{
char word[40];
printf("Enter word:");
scanf("%s",word);
rearrange(word);
printf("\n%s",word);
return 0;
}
See Below:
The rearrange function saves the letters in str into word. if the current position is divisible by 2 i.e i%2 it saves one space and letter into str, otherwise it saves letter only.

Random Bytes In C Output

I just wrote my first program in C and it is a cesarean shift implementation. It works as expected with short inputs, but sometimes produces seemingly random bytes at the and of the output and I cannot figure out why.
I have tried looking at the program in GDB, but just don't have enough experience yet to figure out exactly what is going wrong. I would love to know how one would go about figuring this out with a debugger like GDB.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void rot(char*, int);
char alphabet[27] = "abcdefghijklmnopqrstuvwxyz";
int main (int argc, char* argv[]) {
if (argc != 3) {
printf("Usage: %s [lowercase-text] [rotation-number]\n", argv[0]);
return 1;
} else {
rot(argv[1], atoi(argv[2]));
}
}
void rot (char* t, int r) {
char result[100];
for (int i = 0; i < strlen(t); i++) {
char* location = strchr(alphabet, t[i]);
result[i] = location ? alphabet[(location - alphabet + r) % strlen(alphabet)] : t[i];
}
printf("%s\n", result);
}
Here is the unexpected output. The actual rotation works fine but there are some unexpected bytes at the end.
michael#linux:~/Desktop$ ./rotation
Usage: ./rotation [lowercase-text] [rotation-number]
michael#linux:~/Desktop$ ./rotation rotations_are_cool 13
ebgngvbaf_ner_pbby��� (<- Why are these here ???)
Here was my attempt with GDB. I have not been able to identify the extra data tagging at the end. (full output # https://pastebin.com/uhWnj17e)
(gdb) break *rot+260
Breakpoint 1 at 0x936: file ../rot.c, line 25.
(gdb) r rotations_are_cool 13
Starting program: /home/michael/Desktop/rotation rotations_are_cool 13
Breakpoint 1, 0x0000555555554936 in rot (
t=0x7fffffffe2d2 "rotations_are_cool", r=13) at ../rot.c:25
25 printf("%s\n", result);
(gdb) x/s $rbp-0x80
0x7fffffffdde0: "ebgngvbaf_ner_pbby\377\367\377\177"
This strange occurrence only happens around 50% of the time and happens more often with longer strings. Please help explain and eliminate this. Any other tips that would improve my code are also appreciated. Thanks a dozen!
The end of a string is recognized by the character '\0'.
So you could do it like this
char result[100];
int i;
for (i = 0; i < strlen(t); i++) {
char* location = strchr(alphabet, t[i]);
result[i] = location ? alphabet[(location - alphabet + r) % strlen(alphabet)] : t[i];
}
result[i] = '\0';
You also don't check, that result is large enough for the string, so you could allocate the needed memory dynamically
size_t len = strlen(t)
char *result = malloc(len + 1); /* +1 for terminating '\0' character */
if(result == NULL) {
/* Error allocating memory */
}
int i;
for (i = 0; i < len; i++) {
char* location = strchr(alphabet, t[i]);
result[i] = location ? alphabet[(location - alphabet + r) % strlen(alphabet)] : t[i];
}
result[i] = '\0';
printf("%s\n", result);
free(result);

Passing substring in C

I've spent last night debugging this little piece of code. I have two data text files, both contain 18000 chars. Id like to split these 18000 into two sub-strings each of 100 chars, that makes 180 iterations.
The tricky thing is, in the first 180 iterations the size of both sub-strings is fine. After 18 iterations, the sizes of the sub-strings are 0.
Both files were opened properly. I can print them and so on. I tried to allocate the sub-strings in all the possible ways I could think of but could find no solution so far.
int main(int argc, char const *argv[]) {
//Ive loaded two files into two strings buff1 and buff2 both size of 18000 chars
//It works fine with small data example, I dunno why but eventually I have work with much more bigger data set
//Id like to divide them into 100 char long pieces and do some stuff with that
char *substrA; //substring for buff1
char *substrB; //substring for buff2
substrA = malloc((wlen+1)*sizeof(char)); //word length wlen=100
substrA = malloc((wlen+1)*sizeof(char));
for (int i= 0; i <numOfSubProblems; ++i){ //numOfSubProblems = 18000/100
strncpy(substrA, buff1+i*wlen, wlen);
strncpy(substrB, buff2+i*wlen, wlen);
substrA[wlen] = '\0';
substrA[wlen] = '\0';
int lenA = strlen(substrA);
int lenB = strlen(substrB);
printf("STRA a STR B: %d %d \n",lenA,lenB);
DoSomething(substrA,substrB,i); //some parser and other functionality
}
return 0;
}
strncpy does not null-terminate the destination string. So you have to do
strncpy(subA, buff1+i*wlen, wlen);
subA[wlen] = '\0';
strncpy(subB, buff2+i*wlen, wlen);
subB[wlen] = '\0';
Otherwise you cannot use strlen, and you access the buffers behind their end when doing so.
Use snprintf.
You may not be dealing with formatting strings, but at least it is a sane API. Also make sure to round up when determining the number of subproblems:
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#define PROBSIZE 18002
int main (int argc, char **argv) {
char input[PROBSIZE];
for (size_t i = 0; i < PROBSIZE; ++i) {
input[i] = 'A' + (i % 10);
}
const size_t wlen = 10;
char *subA = malloc (wlen + 1);
if (!subA) {
return EXIT_FAILURE;
}
for (int i = 0; i < (PROBSIZE + wlen - 1) / wlen; ++i) {
/* If there's no error, guarantees `wlen` characters copied */
int err = snprintf(subA, wlen + 1, "%s", input + i * wlen);
if (err < 0) {
fprintf(stderr, "snprintf encountered an error\n");
return EXIT_FAILURE;
}
/* In absence of errors, we expect that the return value is
* always >= wlen + 1, except the last iteration.
*/
assert(err >= wlen + 1 || i == ((PROBSIZE + wlen - 1) / wlen) - 1);
printf("%s\n", subA);
}
return EXIT_SUCCESS;
}

C Loop through a small array and add to a large array [closed]

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 6 years ago.
Improve this question
my first time here, im a very novice student in programming and I have a problem I cant find any solution for.
I’m writing a code to do vigenere cipher but I have problems with it:
First: Key is to be entered, let’s say that the key is; “aaa”
Second: Text to be encrypted, let’s say that the text is:”alligator”
The cipher should be:
alligator
+
aaa|aaa|aaa (key to rerun each extra letter in the text vs key)
a
+
a
ciphered first letter;
b
all the text:
bmmjhbups
My problem is how to loop through alligator with the shorter abc? In all my attempts the abc becomes zero when looping pass it instead of starting from the beginning when the loop for the text is passed the length of the abc.
I have also tried with strcpy and concatenate so that the abc becomes the same strlength at alligator but i meet problems in the strcpy and cat metodes due to strange symbols in the begging of the string.
Do any have a easy solution regarding how a loop can work through a bigger loop ?
Although I probably shouldn't post this (as no code sample was provided), here's a piece of code that does what you want. However, a couple of ideas:
According to Vigenere wiki, each letter has a number associated with it:
a .. 0
b .. 1
...
z .. 25
and when adding 2 letters their values are added and then the % 26 (modulo) is applied to the result. E.g. 'a' + 'a' = (0 + 0) % 26 = 0 which is also a (which is different than b that you are expecting), that's why I had to add the CUSTOM_OFFSET shifting every result from the table (forward) by 1.
The cipher works either with upper or lower case letters, not with both (or any other characters). Probably some text and key validation routines could be added. Anyway in this case, lowercase are used.
Code:
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define BASE_CHR 'a' //Change it to 'A' if working with uppercases (can't have both)
#define ALPHABET_LEN ('z' - 'a' + 1)
#define CUSTOM_OFFSET 1 //According to specs should be 0, but it wouldn't match the current requirements
int main() {
char *text = "alligator", *key = "aaa", *new_text = NULL;
size_t text_len = strlen(text), key_len = strlen(key), i = 0;
if ((new_text = (char*)calloc(text_len + 1, sizeof(char))) == NULL) {
printf("Malloc error\n");
return 1;
}
for (i = 0; i < text_len; i++)
new_text[i] = ((text[i] - BASE_CHR + key[i % key_len] - BASE_CHR + CUSTOM_OFFSET) % ALPHABET_LEN) + BASE_CHR;
printf("Text: %s, Key: %s, Crypted: %s\n", text, key, new_text);
free(new_text);
new_text = NULL;
return 0;
}
Output:
Text: alligator, Key: aaa, Crypted: bmmjhbups
Please have a look at this program. I think it does what you want.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define NUMLETTERS 26
#define BUFSIZE 4096
char *get_input(void);
int main(int argc, char *argv[])
{
char sign = 1;
char const plainmsg[] = "Plain text: ";
// Convert argument into array of shifts
char const *const restrict key = "bbb";
size_t const keylen = strlen(key);
char shifts[keylen];
char const *restrict plaintext = NULL;
for (size_t i = 0; i < keylen; i++) {
if (!(isalpha(key[i]))) {
fprintf(stderr, "Invalid key\n");
return 2;
}
char const charcase = (char) (isupper(key[i])) ? 'A' : 'a';
// If decrypting, shifts will be negative.
// This line would turn "bacon" into {1, 0, 2, 14, 13}
shifts[i] = (key[i] - charcase) * sign;
}
do {
fflush(stdout);
// Print "Plain text: " if encrypting and "Cipher text: " if
// decrypting
printf("%s", plainmsg);
plaintext = get_input();
if (plaintext == NULL) {
fprintf(stderr, "Error getting input\n");
return 4;
}
} while (strcmp(plaintext, "") == 0); // Reprompt if entry is empty
size_t const plainlen = strlen(plaintext);
char* const restrict ciphertext = calloc(plainlen + 1, sizeof *ciphertext);
if (ciphertext == NULL) {
fprintf(stderr, "Memory error\n");
return 5;
}
for (size_t i = 0, j = 0; i < plainlen; i++) {
// Skip non-alphabetical characters
if (!(isalpha(plaintext[i]))) {
ciphertext[i] = plaintext[i];
continue;
}
// Check case
char const charcase = (isupper(plaintext[i])) ? 'A' : 'a';
// Wrapping conversion algorithm
ciphertext[i] = ((plaintext[i] + shifts[j] - charcase + NUMLETTERS) % NUMLETTERS) + charcase;
j = (j+1) % keylen;
}
ciphertext[plainlen] = '\0';
printf("%s\n", ciphertext);
free(ciphertext);
// Silence warnings about const not being maintained in cast to void*
free((char*) plaintext);
return 0;
}
char *get_input(void) {
char *const restrict buf = malloc(BUFSIZE * sizeof (char));
if (buf == NULL) {
return NULL;
}
fgets(buf, BUFSIZE, stdin);
// Get rid of newline
size_t const len = strlen(buf);
if (buf[len - 1] == '\n') buf[len - 1] = '\0';
return buf;
}
Test
Plain text: alligator
bmmjhbups
However, I think that you might have misunderstood the key, the key aaa will leave the plain text unchanged, if I understood correctly, but the key bbb will shift the positions one step down in the alphabet. Watch for corner cases such as shifting Z down or shifting A up.

Effective way of checking if a given string is palindrome in C

I was preparing for my interview and started working from simple C programming questions. One question I came across was to check if a given string is palindrome. I wrote a a code to find if the user given string is palindrome using Pointers. I'd like to know if this is the effective way in terms of runtime or is there any enhancement I could do to it. Also It would be nice if anyone suggests how to remove other characters other than letters (like apostrophe comas) when using pointer.I've added my function below. It accepts a pointer to the string as parameter and returns integer.
int palindrome(char* string)
{
char *ptr1=string;
char *ptr2=string+strlen(string)-1;
while(ptr2>ptr1){
if(tolower(*ptr1)!=tolower(*ptr2)){
return(0);
}
ptr1++;ptr2--;
}
return(1);
}
"how to remove other characters other than letters?"
I think you don't want to actually remove it, just skip it and you could use isalpha to do so. Also note that condition ptr2 > ptr1 will work only for strings with even amount of characters such as abba, but for strings such as abcba, the condition should be ptr2 >= ptr1:
int palindrome(char* string)
{
size_t len = strlen(string);
// handle empty string and string of length 1:
if (len == 0) return 0;
if (len == 1) return 1;
char *ptr1 = string;
char *ptr2 = string + len - 1;
while(ptr2 >= ptr1) {
if (!isalpha(*ptr2)) {
ptr2--;
continue;
}
if (!isalpha(*ptr1)) {
ptr1++;
continue;
}
if( tolower(*ptr1) != tolower(*ptr2)) {
return 0;
}
ptr1++; ptr2--;
}
return 1;
}
you might need to #include <ctype.h>
How about doing like this if you want to do it using pointers only:
int main()
{
char str[100];
char *p,*t;
printf("Your string : ");
gets(str);
for(p=str ; *p!=NULL ; p++);
for(t=str, p-- ; p>=t; )
{
if(*p==*t)
{
p--;
t++;
}
else
break;
}
if(t>p)
printf("\nPalindrome");
else
printf("\nNot a palindrome");
getch();
return 0;
}
int main()
{
const char *p = "MALAYALAM";
int count = 0;
int len = strlen(p);
for(int i = 0; i < len; i++ )
{
if(p[i] == p[len - i - 1])
count++;
}
cout << "Count: " << count;
if(count == len)
cout << "Palindrome";
else
cout << "Not Palindrome";
return 0;
}
I have actually experimented quite a lot with this kind of problem.
There are two optimisations that can be done:
Check for odd string length, odd stings can't be palindromes
Start using vectorised compares, but this only really gives you performance if you expect a lot of palindromes. If the majority of your strings aren't palindromes you are still best off with byte by byte comparisons. In fact my vectorised palindrome checker ran 5% slower then the non-vectorised just because palindromes were so rare in the input. The extra branch that decided vectorised vs non vectorised made this big difference.
Here is code draft how you can do it vectorised:
int palindrome(char* string)
{
size_t length = strlen(string);
if (length >= sizeof(uintptr_t)) { // if the string fits into a vector
uintptr_t * ptr1 = (uintptr_t*)string;
size_t length_v /= sizeof(uintptr_t);
uintptr_t * ptr2 = (uintptr_t*)(string + (length - (length_v * sizeof(uintptr_t)))) + length_v - 1;
while(ptr2>ptr1){
if(*ptr1 != bswap(*ptr2)){ // byte swap for your word length, x86 has an instruction for it, needs to be defined separately
return(0);
}
ptr1++;ptr2--;
}
} else {
// standard byte by byte comparison
}
return(1);
}

Resources