In the for loop, it prints the correct value 11100001 in each loop, but the main call print char_str is blank.
I hope it can return 11100001 as char.
//xor
char * xorencrypt(char * a, char * b) {
size_t alen = strlen(a);
size_t blen = strlen(b);
char * encrypted = malloc(alen + 1);
int i;
for (i = 0; i < 8; i++) {
encrypted[i] = a[i] ^ b[i];
printf("%s\n", encrypted[i]);
}
encrypted[alen] = '\0';
return encrypted;
}
main {
char * char_str = xorencrypt("11011000", "00111001");
printf("%s\n", char_str);
}
Your code needs a bit of refactoring.
1) You need to include some headers
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2) the 'main' function should return an int
int main() {
/* code here */
return 0;
}
3) You should make sure the call to malloc succeeds
char * encrypted = malloc(alen + 1);
assert(encrypted != (char*)0); /* requires #include <assert.h>
4) You should be careful when xor'ing ones and zeros. You are handling chars like integers
you are xoring zeros (value 48 in ascii) with ones (value 49 in ascii)
encrypted[i] = a[i] ^ b[i];
you want something like this instead
int a_i = a[i] - '0';
int b_i = b[i] - '0';
encrypted[i] = (a_i ^ b_i) + '0';
A reworked version of the code that assumes you are dealing exclusively with strings of the binary digits '0' and '1'. If you are dealing with more general strings, you will need a different solution.
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static
char *xorencrypt(char *a, char *b)
{
size_t alen = strlen(a);
char *encrypted = malloc(alen + 1);
assert(alen == strlen(b));
assert(encrypted != NULL);
for (size_t i = 0; i < alen; i++)
{
assert(a[i] == '0' || a[i] == '1');
assert(b[i] == '0' || b[i] == '1');
encrypted[i] = (a[i] ^ b[i]) + '0';
putchar(encrypted[i]);
}
encrypted[alen] = '\0';
putchar('\n');
return encrypted;
}
int main(void)
{
char *char_str = xorencrypt("11011000", "00111001");
printf("%s\n", char_str);
free(char_str);
return 0;
}
Amongst the changes:
Error check the memory assignment. Using assert() is a bad way to do it in production code, but it does ensure that you check that the memory is allocated.
Check that the strings are the same length.
Remove unused variable blen.
The static is optional; it means the code compiles cleanly under the stringent options I use (which require a prototype declaration of every non-static function before it is defined or used).
The loop index i is of the same type size_t as alen to avoid warnings about comparing signed and unsigned values. I'm using the C99 style 'declare a variable in a for loop' notation.
The upper bound of the loop is based on the measured length of the strings, not a fixed constant.
The original version of the XOR operation either generated a null '\0' or a control-A '\1' for each character.
The revised version of the crucial XOR operation ensures that the result is a printable digit.
The printf("%s\n", encrypted[i]); in the original passed a character to be printed as a string. If your compiler wasn't warning you, turn on the warning options or get a better compiler.
If you'd written printf("%s\n", &encrypted[i]); you would have had problems, potentially, with a string that is not guaranteed to be null terminated inside the loop (though you did null terminate the string after the loop, which was good).
The code in main() frees the allocated memory. It is good practice to ensure there is a free() for every malloc().
I prefer to explicitly return 0 from main(), even though C99 says you don't have to.
This answer was started while the question was active. Then life got in the way.
Related
Trying to take a lower case string, and create a new string after making characters uppercase
#include <ctype.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main (void)
{
string word = "science";
char new_word[] = {};
for (int i = 0, len = strlen(word); i < len; i++)
{
if (islower(word[i]))
{
new_word = new_word + toupper(word[i]);
}
}
}
I am getting "error: array type 'char[0]' is not assignable".
This isn't all, and I am sure with my full program there might be an easier way, but I built out everything else, and the only point that I am struggling with is looping through my string to get a new word that is uppercase.
Any assistance would be greatly appreciated!
char new_word[] = {};
Your new char array has length 0 and any access invokes undefined behaviour (UB) as you access it outside its bounds.
If your compiler supports VLAs:
string word = "science";
char new_word[strlen(word) + 1] = {0,};
if not:
string word = "science";
char *new_word = calloc(1, strlen(word) + 1);
and
new_word[i] = toupper((unsigned char)word[i]);
If you used calloc do not forget to free the allocated memory
Undefined behavior when word[i] < 0
Avoid that by accessing the string as unsigned char
As per C reference about toupper()
int toupper( int ch );
ch - character to be converted. If the value of ch is not representable as >unsigned char and does not equal EOF, the behavior is undefined.
This is not correct, compiler gives error , "error: assignment to expression with array type"
new_word = new_word + toupper(word[i]);
which is not allowed with an array type as LHS of assignment.
changed to
new_word[i] = toupper((unsigned char)word[i]);
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main (void)
{
char word[] = "science";
char new_word[sizeof word] = "";
int i;
for (i = 0; i < sizeof(word); i++)
{
if (islower(word[i]))
{
new_word[i] = toupper(word[i]);
}
else /* for Upper case latter, simply fill the array */
{
new_word[i] = word[i];
}
}
new_word[i] = '\0';
printf("%s", new_word);
}
OUTPUT:
SCIENCE
EDIT:
Just echo comment from solution given by M.M and comment from
David C. Rankin casting is not necessary for this example. read comment below from M.M and David C. Rankin
Removed unsigned char from islower() and toupper()
This is but one way of accomplishing the task. Make sure to come up with your way of doing.
#include <stdio.h>
#include <string.h>
#define MAX_BUFF 128
char *upperCase(char *c) {
//printf("%s, %d", c, strlen(c));
for(int i=0; i<strlen(c) && i<MAX_BUFF; i++) {
c[i] = c[i] - ' '; // convert char to uppercase
//printf(">> %c", c[i]);
}
return c;
}
int main (void)
{
char word[MAX_BUFF] = "science";
char new_word[MAX_BUFF];
printf("in>> %s \n", word);
strcpy(new_word, upperCase(&word[0]));
printf("out>> %s\n", new_word);
}
Output:
in>> science
out>> SCIENCE
Named arrays cannot be resized in C, you have to set the size correctly to start:
size_t len = strlen(word);
char new_word[len + 1]; // leaving room for null-terminator
Note that no initializer can be used for new_word when its size was determined by a function call (a lame rule but it is what it is); and you can take out the len loop variable since it is now defined earlier.
Then set each character in place:
new_word[i] = toupper(word[i]);
but be careful with the surrounding if statement: if that were false, then you need to set new_word[i] = word[i] instead.
(Pro tip, you can get rid of the if entirely, because toupper is defined to have no effect if the character was not lower case).
Lastly, there should be a null terminator at the end:
new_word[len] = 0;
NB. To be technically correct, the call to toupper should be: toupper((unsigned char)word[i]) -- check the documentation of toupper to understand more about this.
I wanted to unmask a hex string using the following algorithm in C
j = i MOD 4 transformed-octet-i = original-octet-i XOR masking-key-octet-j
#include<stdlib.h>
#include<string.h>
int main()
{
char masked[]="951bfdcdc113ebca921fe9dc";
char masking_key[]="e17e8eb9";
char *unmasked;
int length=strlen(masked);
unmasked=malloc(sizeof(char)*(length+1));
int i=0;
for(i=0;i<length;i++)
{
unmasked[i]=masked[i]^masking_key[i%4];
}
printf("%s\n",unmasked);
return 0;
}
The output I am getting is \UT instead of 74657374206d657373616765. It would be really helpful if someone could help me fix the error here.
You need to convert from string format to raw integers before doing the XOR, then convert back before printing it as a string. Otherwise you'll XOR the symbol values, not the raw values.
You can convert the whole string in one go with strtol(data, 0, 16). But one of the common details that makes programmers different from the code monkeys is the ability to code trivial string-integer conversions without the help of library functions. So here is a a simplified code doing just that - be aware of the complete lack of error handling, as this is just quick & dirty code:
#include <stdio.h>
#include <stdlib.h>
char hexlify (char nibble)
{
return "0123456789abcdef"[nibble];
}
char unhexlify (char ch)
{
if(ch>='0' && ch<='9')
return ch - '0';
if(ch>='a' && ch<='f')
return ch - 'a' + 0xA;
return 0;
}
int main (void)
{
char masked[]="951bfdcdc113ebca921fe9dc";
char masking_key[]="e17e8eb9";
char *unmasked;
size_t length = sizeof masked - 1;
unmasked = malloc(length + 1);
for(size_t i=0;i<length;i++)
{
char op1 = unhexlify(masked[i]);
char op2 = unhexlify(masking_key[i%4]);
unmasked[i]= hexlify(op1 ^ op2);
}
unmasked[length]='\0';
printf("%s\n",unmasked);
free(unmasked);
return 0;
}
Output:
74651cb3206d0ab4736108a2
What you're doing here is not xoring the hexadecimal bytes, but xoring the characters representing them.
While the ideal process would be (0x95 ^ 0xe1) + (0xbf ^ 7e) + ..., what you're doing is xoring the ascii values of each character, meaning ('9' ^ 'b') + ('5' ^ '1') + ....
What you need to do is first transform the hexadecimal string to the bytes themselves (bytes.fromhex("951bfdcdc113ebca921fe9dc") in python), and only then XOR them. The way I would do that is with sscanf("%2x", ...).
For example:
#include <stdio.h>
int main()
{
unsigned char a = 0;
scanf("%2hhx", &a);
}
I'm learning about arrays in C and I can't figure out why the following is not correct?
#include <cs50.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
string plaintext = get_string();
int x = 5;
long long N = strlen(plaintext);
string a = plaintext;
long long c = 0;
int z = x;
for(int i = 0; i < N + (N/x) ; i++)
{
if( i == x)
{
a[c] = 32;
c++;
z = (z + x);
//printf("%c\n", a[c]);
}
a[c] = plaintext[i];
//printf("%c\n", a[c]);
c++;
}
printf("%s\n", a);
}
It's meant to insert spaces into a string of text after every x chars... I know it's not efficient (I reckon I need something called pointers) but why isn't it working? I went through it using a debugger and it seems like my original string is changing as I go... but why?
Assuming string is char * then text and a point to the same string. That explains why your original string changes. What you can do is:
string a= malloc(N+1 + N/x +1);
This allocates space for a new string, into which you copy the original with a space after every x characters. Add 1 for the terminating null character and 1 "to be safe" when x or N are odd.
#include <bits/stdc++.h>
using namespace std;
#define freinput "input.txt","r",stdin
#define freoutput "output.txt","w",stdout
#define mp make_pair
#define fi first
#define sc second
#define ellapse printf("Time : %0.3lf\n",clock()*1.0/CLOCKS_PER_SEC);
typedef long long ll;
typedef unsigned long int uld;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
string s;
string stringInsertion(int x,string neww){
for(int i = 0;i<s.size();i++){
if(i!=0 && i%x==0){
neww=neww+' '+s[i];
}
else neww+=s[i];
}
return neww;
}
int main(){
cin>>s;
int x = 2;
string neww="";
cout<<stringInsertion(x,neww);
}
just set the x number.hope this help
Okay, let's do something similar first: Print out the string with spaces. Use i to loop through the string. Every time i is evenly divisibly by x, we print a space before we print the character, but not at the beginning:
void print_spaced(const char *s, int x)
{
int i;
for (i = 0; s[i]; i++) {
if (i && i % x == 0) putchar(' ');
putchar(s[i]);
}
putchar('\n');
}
You don't need to determine the length beforehand, because you can stop when you hit the terminating null character. That is, keep going as long as s[i] is not null. (Recall that s[i] is the same as s[i] != '\0' and similarly, i is the same as i != 0.)
Now let's fill a char array with the spaced out string instead of printing it:
int space_out_unsafe(char *res, const char *s, int x)
{
int i, k = 0;
for (i = 0; s[i]; i++) {
if (i && i % x == 0) res[k++] = ' ';
res[k++] = s[i];
}
res[k] = '\0';
return k;
}
This function takes an additional parameter: A char buffer to fill. It has a second index, k, which is the current length of the result buffer. Whenever we printed in the first version, we now append a character to the string:
res[k++] = '#';
Tis overwrites the current end and moves k on one position. We don't write a newline at the end, but we must null-terminate the result.
There is one problem, though: The buffer may overflow; note how I have labelled the function above unsafe. Arrays in C have a fixed size and won't grow automatically when something is appended. It is there fore a good idea to pass the maximum buffer size max to the function and check for overflow before appending:
int space_out(char *res, int max, const char *s, int x)
{
int i, k = 0;
for (i = 0; s[i]; i++) {
if (i && i % x == 0 && k < max - 1) res[k++] = ' ';
if (k < max - 1) res[k++] = s[i];
}
res[k] = '\0';
return k;
}
You can now use this function like this:
char res[20];
space_out(res, sizeof(res), "Doremifasola", 2);
puts(res);
There are other ways to accomplish this. You could allocate the memory dynamically, as Paul suggested. That way, you can cater for the additional space you need, but you also make the caller of the function take care of cleaning up the allocated memory with free. Dynamically allocating memory is something to look into after your first week. :)
Another possibility is to space out the string in place, that modify the contents of the original buffer. You still have to take care to provide the extra space, though. (Usually, in-place midofication is used when the result string is shorter, e.g. when filtering out characters.) You should also process your string from the and as not to overwrite data you need later with spaces. If you feel confident, that's an exercise for next week, too.
I have a variable length string where each character represents a hex digit. I could iterate through the characters and use a case statement to convert it to hex but I feel like there has to be a standard library function that will handle this. Is there any such thing?
Example of what I want to do. "17bf59c" -> int intarray[7] = { 1, 7, 0xb, 0xf, 5, 9, 0xc}
No, there's no such function, probably because (and now I'm guessing, I'm not a C standard library architect by a long stretch) it's something that's quite easy to put together from existing functions. Here's one way of doing it decently:
int * string_to_int_array(const char *string, size_t length)
{
int *out = malloc(length * sizeof *out);
if(out != NULL)
{
size_t i;
for(i = 0; i < length; i++)
{
const char here = tolower(string[i]);
out[i] = (here <= '9') ? (here - '\0') : (10 + (here - 'a'));
}
}
return out;
}
Note: the above is untested.
Also note things that maybe aren't obvious, but still subtly important (in my opinion):
Use const for pointer arguments that are treated as "read only" by the function.
Don't repeat the type that out is pointing at, use sizeof *out.
Don't cast the return value of malloc() in C.
Check that malloc() succeeded before using the memory.
Don't hard-code ASCII values, use character constants.
The above still assumes an encoding where 'a'..'f' are contigous, and would likely break on e.g. EBCDIC. You get what you pay for, sometimes. :)
using strtol
void to_int_array (int *dst, const char *hexs)
{
char buf[2] = {0};
char c;
while ((c = *hexs++)) {
buf[0] = c;
*dst++ = strtol(buf,NULL,16);
}
}
Here's another version that allows you to pass in the output array. Most of the time, you don't need to malloc, and that's expensive. A stack variable is typically fine, and you know the output is never going to be bigger than your input. You can still pass in an allocated array, if it's too big, or you need to pass it back up.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* str of length len is parsed to individual ints into output
* length of output needs to be at least len.
* returns number of parsed elements. Maybe shorter if there
* are invalid characters in str.
*/
int string_to_array(const char *str, int *output)
{
int *out = output;
for (; *str; str++) {
if (isxdigit(*str & 0xff)) {
char ch = tolower(*str & 0xff);
*out++ = (ch >= 'a' && ch <= 'z') ? ch - 'a' + 10 : ch - '0';
}
}
return out - output;
}
int main(void)
{
int values[10];
int len = string_to_array("17bzzf59c", values);
int i = 0;
for (i = 0; i < len; i++)
printf("%x ", values[i]);
printf("\n");
return EXIT_SUCCESS;
}
#include <stdio.h>
int main(){
char data[] = "17bf59c";
const int len = sizeof(data)/sizeof(char)-1;
int i,value[sizeof(data)/sizeof(char)-1];
for(i=0;i<len;++i)
sscanf(data+i, "%1x",value + i);
for(i=0;i<len;++i)
printf("0x%x\n", value[i]);
return 0;
}
I am looking for a (relatively) simple way to parse a random string and extract all of the integers from it and put them into an Array - this differs from some of the other questions which are similar because my strings have no standard format.
Example:
pt112parah salin10n m5:isstupid::42$%&%^*%7first3
I would need to eventually get an array with these contents:
112 10 5 42 7 3
And I would like a method more efficient then going character by character through a string.
Thanks for your help
A quick solution. I'm assuming that there are no numbers that exceed the range of long, and that there are no minus signs to worry about. If those are problems, then you need to do a lot more work analyzing the results of strtol() and you need to detect '-' followed by a digit.
The code does loop over all characters; I don't think you can avoid that. But it does use strtol() to process each sequence of digits (once the first digit is found), and resumes where strtol() left off (and strtol() is kind enough to tell us exactly where it stopped its conversion).
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
const char data[] = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
long results[100];
int nresult = 0;
const char *s = data;
char c;
while ((c = *s++) != '\0')
{
if (isdigit(c))
{
char *end;
results[nresult++] = strtol(s-1, &end, 10);
s = end;
}
}
for (int i = 0; i < nresult; i++)
printf("%d: %ld\n", i, results[i]);
return 0;
}
Output:
0: 112
1: 10
2: 5
3: 42
4: 7
5: 3
More efficient than going through character by character?
Not possible, because you must look at every character to know that it is not an integer.
Now, given that you have to go though the string character by character, I would recommend simply casting each character as an int and checking that:
//string tmp = ""; declared outside of loop.
//pseudocode for inner loop:
int intVal = (int)c;
if(intVal >=48 && intVal <= 57){ //0-9 are 48-57 when char casted to int.
tmp += c;
}
else if(tmp.length > 0){
array[?] = (int)tmp; // ? is where to add the int to the array.
tmp = "";
}
array will contain your solution.
Just because I've been writing Python all day and I want a break. Declaring an array will be tricky. Either you have to run it twice to work out how many numbers you have (and then allocate the array) or just use the numbers one by one as in this example.
NB the ASCII characters for '0' to '9' are 48 to 57 (i.e. consecutive).
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main(int argc, char **argv)
{
char *input = "pt112par0ah salin10n m5:isstupid::42$%&%^*%7first3";
int length = strlen(input);
int value = 0;
int i;
bool gotnumber = false;
for (i = 0; i < length; i++)
{
if (input[i] >= '0' && input[i] <= '9')
{
gotnumber = true;
value = value * 10; // shift up a column
value += input[i] - '0'; // casting the char to an int
}
else if (gotnumber) // we hit this the first time we encounter a non-number after we've had numbers
{
printf("Value: %d \n", value);
value = 0;
gotnumber = false;
}
}
return 0;
}
EDIT: the previous verison didn't deal with 0
Another solution is to use the strtok function
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," abcdefghijklmnopqrstuvwxyz:$%&^*");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " abcdefghijklmnopqrstuvwxyz:$%&^*");
}
return 0;
}
Gives:
112
10
5
42
7
3
Perhaps not the best solution for this task, since you need to specify all characters that will be treated as a token. But it is an alternative to the other solutions.
And if you don't mind using C++ instead of C (usually there isn't a good reason why not), then you can reduce your solution to just two lines of code (using AXE parser generator):
vector<int> numbers;
auto number_rule = *(*(axe::r_any() - axe::r_num())
& *axe::r_num() >> axe::e_push_back(numbers));
now test it:
std::string str = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
number_rule(str.begin(), str.end());
std::for_each(numbers.begin(), numbers.end(), [](int i) { std::cout << "\ni=" << i; });
and sure enough, you got your numbers back.
And as a bonus, you don't need to change anything when parsing unicode wide strings:
std::wstring str = L"pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
number_rule(str.begin(), str.end());
std::for_each(numbers.begin(), numbers.end(), [](int i) { std::cout << "\ni=" << i; });
and sure enough, you got the same numbers back.
#include <stdio.h>
#include <string.h>
#include <math.h>
int main(void)
{
char *input = "pt112par0ah salin10n m5:isstupid::42$%&%^*%7first3";
char *pos = input;
int integers[strlen(input) / 2]; // The maximum possible number of integers is half the length of the string, due to the smallest number of digits possible per integer being 1 and the smallest number of characters between two different integers also being 1
unsigned int numInts= 0;
while ((pos = strpbrk(pos, "0123456789")) != NULL) // strpbrk() prototype in string.h
{
sscanf(pos, "%u", &(integers[numInts]));
if (integers[numInts] == 0)
pos++;
else
pos += (int) log10(integers[numInts]) + 1; // requires math.h
numInts++;
}
for (int i = 0; i < numInts; i++)
printf("%d ", integers[i]);
return 0;
}
Finding the integers is accomplished via repeated calls to strpbrk() on the offset pointer, with the pointer being offset again by an amount equaling the number of digits in the integer, calculated by finding the base-10 logarithm of the integer and adding 1 (with a special case for when the integer is 0). No need to use abs() on the integer when calculating the logarithm, as you stated the integers will be non-negative. If you wanted to be more space-efficient, you could use unsigned char integers[] rather than int integers[], as you stated the integers will all be <256, but that isn't a necessity.