simple XOR algorithm - c

Although I've used C++ a lot, I'm struggling with the C differences (mainly in strings).
Could you please show me a simple single function that encrypts a message with a key using XOR comparison.
Thank-you
EDIT:
Both the key and the message are char*

OK, I hacked around for a minute and came up with this (only vaguely tested):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * xorencrypt(char * message, char * key) {
size_t messagelen = strlen(message);
size_t keylen = strlen(key);
char * encrypted = malloc(messagelen+1);
int i;
for(i = 0; i < messagelen; i++) {
encrypted[i] = message[i] ^ key[i % keylen];
}
encrypted[messagelen] = '\0';
return encrypted;
}
int main(int argc, char * argv[]) {
char * message = "test message";
char * key = "abc";
char * encrypted = xorencrypt(message, key);
printf("%s\n", encrypted);
free(encrypted);
return 0;
}
Note that the function xorencrypt allocates and returns a new string, so it's the caller's responsibility to free it when done.

C is very close to Assembler, so this example is short:
while (*string)
*string++ ^= key;
assuming char *string; and char key.

For what it's worth, combine the answers from #ott-- & #Tim to form Xortron.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *xor(char *string, const char *key)
{
char *s = string;
size_t length = strlen(key), i = 0;
while (*s) {
*s++ ^= key[i++ % length];
}
return string;
}
int main(int argc, char **argv)
{
const char *key = "abc";
if (argc < 2) {
fprintf(stderr, "%s: no input\n", argv[0]);
return EXIT_FAILURE;
}
printf("%s\n", xor(xor(argv[1], key), key));
return EXIT_SUCCESS;
}

Related

Converting a comma separated string to array

I have been trying to convert a string in array of integers, floats and characters. While I could get it work for integers and floats, there is some problem for characters.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s1;
int k, no=5;
char* variable = "R1,R2,R3,R4,R5";
void* value;
s1 = calloc(no,sizeof(char)*81);
for (k=0; k<no; k++) s1[k] = strdup(mchar);
ListChar(variable, s1, no, ",");
memcpy(value, s1, no*sizeof(char)*81);
free(s1);
int i;
for (i = 0; i < no; i++)
printf("%s", value[i]);
printf("\n");
return 0;
}
In the header file I have
#define mchar "A...(81times)"
Implementation:
int ListChar(char *buf, char *list, int maxloop, char* delim)
{
int n = 0;
char *s,*t;
s= strdup(buf);
t= strtok(s,delim);
while ( t && (n<maxloop))
{
if (list!=NULL) list[n] =strdup(t);
n++;
t=strtok(NULL,delim);
}
free(s);
return(n);
}
During the calloc memory assignment when I watch s1 its 0xsomeadress ""
After the for loop s1 becomes 0xsomeadress "Garbage value 81 times"
When s1 is assigned to list its still reads the same garbage value.
And when list [n] = strdup(t) list[0] reads the first block of garbage value like -21 '\221 ṗ'.
t is getting delimited correctly. I even tried initializing char *s1[81] = {"something"} and looping it on j but it wont work, same problem, and I need to free s1 at the end because this function runs for number of times. I did it for integers and floats by list[n]=atoi(t) it works fine. Can anyone suggest me something?
There seems to be a fundamental misunderstanding about how strings work. Your s1 clearly needs to be a char ** and the usage of strdup is incorrect. If s1 is of type char *, then s1[k] is of type char. But strdup returns a char *, so s1[k] = strdup ... is clearly an error which your compiler ought to warn you about. Perhaps you want something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void * xmalloc(size_t s);
void
ListChar(const char *buf, char **list, int maxloop, int delim)
{
char set[] = {delim, 0};
for( int n = 0; n < maxloop; n += 1 ){
size_t len = strcspn(buf, set);
list[n] = xmalloc(len + 1);
memcpy(list[n], buf, len);
buf += len + 1;
}
}
int
main(int argc, char **argv)
{
int delim = ',';
(void)argc; /* Suppress compiler warning */
while( *++argv ){
char **s1;
int k, num = 1;
char *input = *argv;
for( const char *p = input; *p; p += 1 ){
if( *p == delim ){
num += 1;
}
}
s1 = xmalloc(num * sizeof *s1);
ListChar(input, s1, num, delim);
for( int i = 0; i < num; i += 1 ){
printf("%s\n", s1[i]);
}
free(s1);
}
return 0;
}
void *
xmalloc(size_t s)
{
void *rv = malloc(s);
if( rv == NULL ){
perror("malloc");
exit(EXIT_FAILURE);
}
return rv;
}
Note that the above code scans each string twice, which is not ideal. Rather than scanning the string to find the number of delimiters and then parsing the string, it would be better to do both in one pass. But for the purposes of demonstrating how to break up the string, that seems like unnecessary complexity. (Though it's actually simpler, IMO)

What's wrong with my function? I have function that finds all common chars and concatenates them into one string

I have function that finds all common chars and concatenates into one string.
char* commonString(char* p1,char* p2)
{
char* res = "";
for (int k=0;k<strlen(p1);k++)
{
for (int h=0;h<strlen(p2);h++)
{
if (p1[k] == p2[h])
{
strcat(res,&p1[k]);
}
}
}
return res;
}
What's wrong with it? Can you review and help to fix it?
Example of I/O:
Example 00
Input: "padinton" && "paqefwtdjetyiytjneytjoeyjnejeyj"
Output:
Return Value: "padinto"
P.S. I also have function that removes all duplicated chars except the first ocurrence of it from strings.
This function works after removing them
The two main problems in your code are that you are not allocating space for the resulting string and you are using the strcat function inappropriately. Below is a brief implementation of what you are trying to achieve.
#include <stdlib.h>
#include <string.h>
char *commonString(char* p1,char* p2)
{
const size_t lenp1 = strlen(p1);
char *res = malloc(lenp1 + 1);
size_t j = 0;
for (size_t i = 0; i < lenp1; ++i)
if (strchr(p2, p1[i]))
res[j++] = p1[i];
res[j] = 0;
return res;
}
Important Note: The pointer returned by the malloc function must be checked against NULL before being dereferenced. It is omitted here for brevity.
There are so many issues in your code.
Not allocating memory,
Modifying string literals
returning local variables
etc etc.
Your function is also inefficient. You call strlen on every iteration, call strcat (which is very expensive) just to add 1 char.
This function does what you want with or without the duplicates.
#include <stdlib.h>
#include <stdio.h>
char *mystrnchr(const char *str, const char ch, size_t size)
{
char *result = NULL;
while(size--)
{
if(*str == ch)
{
result = (char *)str;
break;
}
str++;
}
return result;
}
char *mystrchr(const char *str, const char ch)
{
char *result = NULL;
while(*str)
{
if(*str == ch)
{
result = (char *)str;
break;
}
str++;
}
return result;
}
char* commonString(char *buff, const char* p1, const char* p2, int duplicates)
{
size_t size = 0;
char p1c;
while((p1c = *p1++))
{
if(!duplicates)
{
if(mystrnchr(buff, p1c, size))
{
continue;
}
}
if(mystrchr(p2, p1c))
{
buff[size++] = p1c;
}
}
buff[size] = 0;
return buff;
}
int main()
{
char result[23];
char *str1 = "paaaadiiiiinton";
char *str2 = "paqefwtdjetyiytjneytjoeyjnejeyj";
printf("%s\n", commonString(result, str1, str2, 0));
printf("%s\n", commonString(result, str1, str2, 1));
}
You can experiment with it yourself here: https://godbolt.org/z/qMnsfa
Here's a solution along those lines:
#include <stdio.h>
#include <string.h>
#define MAX_LENGTH 512
void removeDup(char *result, char *string)
{
for (int i = 0; i < strlen(string); i++)
{
char C[2] = { string[i], '\0' };
if (strstr(result, C) == NULL)
strcat(result, C);
}
}
char *commonString(char *p1, char *p2)
{
char r[MAX_LENGTH] = { };
for (int i = 0; i < strlen(p1); i++)
for (int j = 0; j < strlen(p2); j++)
if (p1[i] == p2[j])
strcat(r, &p1[i]);
static char res[MAX_LENGTH] = { };
removeDup(res, r);
return res;
}
int main()
{
printf("%s\n", commonString("padinton", "paqefwtdjetyiytjneytjoeyjnejeyj"));
return 0;
}
$ cc string.c -o string && ./string
padinto

how can I multiply strings in C like I do in python?

in python you can easily type:
str = "hi"
print(str * 10)
and the output would be hi printed 10 times. I'm currently learning how to code in C and I have to do this. Can someone teach me how I can do this kind of thing in C? Thanks in advance
Use for() loop:
Example:
#include <stdio.h>
int main() {
char* str = "hi";
for (int i = 0; i < 10; ++i) {
printf("%s", str);
}
}
And if you need to actually multiply the string (not just print n times) you can use the following mulstr(), just don't forget to test for NULL and to free():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
char* mulstr(char* str, size_t i) {
size_t len = strlen(str);
char* newstr = malloc(len * i + 1);
if (newstr) {
char* writer = newstr;
for (; i; --i) {
memcpy(writer, str, len);
writer += len;
}
*writer = 0;
} else {
perror("malloc");
}
return newstr;
}
int main() {
char* str = "hi";
char* newstr = mulstr(str, 10);
if (newstr) {
printf("%s", newstr);
free(newstr);
}
}
Using for-loop is the best way to implement this.
You can just create a customized print function which will do the same thing as python does. I am just giving a prototype here.
#include <stdio.h>
void print(char *string,int n)
{
int i;
for(i=0;i<n;i++)
{
printf("%s\n",string);
}
}
int main()
{
char *str="Hi";
print(str,2);
return 0;
}
Here second argument in the function n will tell you how many times you want to print the string.
The output will look like
Hi
Hi

Conflicting types for 'reverse_string' function

I was using this SO question as part of a program that needs to reverse a string. The problem I am having is that I cannot seem to get the function to work. Here is the code I have:
int main(int argc, char *argv[]){
char *test = "Testing";
fputs(test, stdout);
fputs(reverse_string(test), stdout);
}
char* reverse_string(char *str){
char temp;
size_t len = strlen(str) - 1;
size_t i;
size_t k = len;
for(i = 0; i < (len +1)/2; i++){
temp = str[k];
str[k] = str[i];
str[i] = temp;
k--;
}
return str;
}
I am getting an error that there is conflicting types for 'reverse_string'
Edit: For anyone wondering here is the code that works. See #chux's answer for an explanation.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* reverse_string(char *str){
char temp;
size_t len = strlen(str) - 1;
size_t i;
size_t k = len;
for(i = 0; i < (len +1)/2; i++){
temp = str[k];
str[k] = str[i];
str[i] = temp;
k--;
}
return str;
}
int main(int argc, char *argv[]){
char test[] = "Testing";
fputs(test, stdout);
fputs(reverse_string(test), stdout);
}
You can not pass a const char * to a char *
char *test = "Testing";
fputs(reverse_string(test), ... // bad, attempting to change constant data.
// bad as reverse_string() is assumed to return int, but fputs() expects char *
char* reverse_string(char *str) { // Bad, there's now a function conflict
Instead
char* reverse_string(char *str); // Need to declare/define function first
char test[] = "Testing";
fputs(reverse_string(test), ... // good
[Edit]
You problem was well identified (missing function declaration) by others. My suggestion takes care of the next problem. In C, a missing declaration of a function will assume int reverse_string(...) which does not match char* reverse_string(char *str).
[Edit]
As #Shafik Yaghmou suggests, modifying a string literal char *test = "Testing" will result in undefined behavior. Hence the char test[] = "Testing" which initializes test with "Testing\0", but may be modified.
[Edit]
#GreenAsJade correctly points out OP's original error message is due to the assumed int reverse_string(...) supplying an int to s in int fputs(const char * s, FILE * stream);
char *test1 = "Testing" is not the same thing as char test2[] = "Testing". test1 becomes a char * with the size of a pointer. The initial pointer value is to a string "Testing" located elsewhere in memory. test2 is a char array with size 8: length of "Testing" + 1 for '\0'. The array test2 is initialized with 'T', 'e', ... '\0' etc.
FWIW:
(h2hh)momerath:Documents mgregory$ cat test.c
char* reverse_string(char *str) {
return str;
}
char *test = "Testing";
int main() {
reverse_string(test);
}
(h2hh)momerath:Documents mgregory$ gcc test.c
(h2hh)momerath:Documents mgregory$
I think that the answer to the OP's question is that reverse_string has to be declared before being used, to be not int.

Null terminating char pointer

I am completely newbie in C.
I am trying to do simple C function that will split string (char array).
The following code doesn't work properly because I don't know how to terminate char array in the array. There are to char pointers passed in function. One containing original constant char array to be split and other pointer is multidimensional array that will store each split part in separate char array.
Doing the function I encountered obviously lots of hustle, mainly due to my lack of C experience.
I think what I cannot achieve in this function is terminating individual array with '\0'.
Here is the code:
void splitNameCode(char *code, char *output);
void splitNameCode(char *code, char *output){
int OS = 0; //output string number
int loop;
size_t s = 1;
for (loop = 0; code[loop]; loop++){
if (code[loop] == ':'){
output[OS] = '\0'; // I want to terminate each array in the array
OS ++;
}else {
if (!output[OS]) {
strncpy(&output[OS], &code[loop], s);
}else {
strncat(&output[OS], &code[loop], s);
}
}
}
}
int main (int argc, const char * argv[]) {
char output[3][15];
char str[] = "andy:james:john:amy";
splitNameCode(str, *output);
for (int loop = 0; loop<4; loop++) {
printf("%s\n", output[loop]);
}
return 0;
}
Here is a working program for you. Let me know if you need any explanation.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void splitNameCode(char *code, char **output) {
int i = 0;
char* token = strtok(code, ":");
while (token != NULL) {
output[i++] = token;
token = strtok(NULL, ":");
}
}
int main (int argc, const char *argv[]) {
char* output[4];
char input[] = "andy:james:john:amy";
splitNameCode(input, output);
for (int i = 0; i < 4; i++) {
printf("%s\n", output[i]);
}
return 0;
}
If I understand your intent correctly, you are trying to take a string like andy:james:john:amy and arrive at andy\0james\0john\0amy. If this is the case, then your code can be simplified significantly:
void splitNameCode(char *code, char *output){
int loop;
strncpy(code, output, strlen(code));
for (loop = 0; output[loop]; loop++){
if (output[loop] == ':'){
output[loop] = '\0'; // I want to terminate each array in the array
}
}
}

Resources