I've got a very very simple function which simply converts a char to a char* which represents the binary value of the char with 0's and 1's as chars.
char* stringToBin(char symbol) {
int pos = 0;
int value = (int) symbol;
int rest;
char* result = (char*) malloc(sizeof(char) * 9);
while(value > 0) {
if(value % 2 == 0) {
result[7-pos] = '0';
}
else {
result[7-pos] = '1';
}
pos++;
value = value / 2;
}
while(pos < 8) {
result[7-pos] = '0';
pos++;
}
result[8] = '\0';
puts(result);
puts(strlen(result));
return result;
}
My problem is I can't print the length of the char*. Printing the whole char* works perfect but not calculating the size. I alway get a segmentation fault. I think the problem is pretty simple but I did not get it right now. So please give me the missing hint ;)
The problem is not with the NUL-termination of your string, that's fine. Instead,
puts(strlen(result));
is wrong. puts() expects a C string, and you're giving it a size_t. Write instead:
printf("%zu\n", strlen(result));
(This assumes that the C99 format specifier %zu for size_t is available. If it isn't, then use:
printf("%u\n", (unsigned)strlen(result));
instead.)
Related
I would like to convert a very long (arbitrary length, possibly 1000 characters long; university assignment) string into binary. How should I approach this problem? I have thought about it for a while, but I just can't seem to think of anything viable.
The string will be passed to me as const char *str. I want to read the number, which will be in Base 10, and convert it into binary.
Should I read certain number of least significant numbers and store them in unsigned long long int, and then work from there? Is there a better solution? I don't know how the method I suggested would pan out. I wanted to know if there's a better/easier way to do it.
Thank you.
Assuming your input is too large for the biggest integer type, you have to convert it to a unlimited size integer. For this purpose you can use gmplib. If you are not allowed to use external libraries, you can use a different approach:
is your string divisible by two (look at the last digit)?
if yes, write 0 to left side of your output
else, write 1 to left side of your output
divide the string by 2 (every digit)
repeat while string is not filled with 0
I am going to edit this answer, as soon as I wrote the code.
Here you go:
#include<stdbool.h>
#include<stdlib.h>
#include<memory.h>
#include<stdio.h>
typedef struct char_queue {
unsigned int len;
unsigned int capacity;
char* data;
} char_queue;
char_queue init_char_queue() {
return (char_queue) {
0,
4096,
malloc(4096)
};
}
void enqueue(char_queue* queue, char val) {
if (queue->len == queue->capacity) {
char* new_queue_data = malloc(queue->capacity + 4096);
memmove(new_queue_data, queue->data, queue->capacity);
free(queue->data);
queue->data = new_queue_data;
}
queue->len++;
queue->data[queue->capacity - queue->len] = val;
}
char* queue_get_arr(char_queue* queue) {
char* output = malloc(queue->len);
memcpy(output, &queue->data[queue->capacity - queue->len], queue->len);
return output;
}
void free_char_queue(char_queue* queue) {
if (queue->data) free(queue->data);
}
void convert_to_digit_arr(char* input, unsigned int len) {
for (unsigned int i = 0; i < len; i++) {
input[i] = input[i] - '0'; // '5' - '0' = 5
}
}
bool is_null(char* input, unsigned int len) {
for (unsigned int i = 0; i < len; i++) {
if (input[i] != 0) return false;
}
return true;
}
bool divisible_by_two(char* digit_arr, unsigned int len) {
return digit_arr[len - 1] % 2 == 0;
}
void divide_by_two(char* digit_arr, unsigned int len) {
for (unsigned int i = 0; i < len; i++) {
bool is_odd = digit_arr[i] % 2 == 1;
digit_arr[i] /= 2;
if (is_odd && i + 1 < len) { // and is not last (right) digit
digit_arr[i + 1] += 10;
}
}
}
int main(int argc, char** argv) {
for (int i = 1; i < argc; i++) {
unsigned int input_len = strlen(argv[i]);
char* input = malloc(input_len + 1);
strcpy(input, argv[i]);
convert_to_digit_arr(input, input_len);
char_queue queue = init_char_queue();
enqueue(&queue, 0); // null terminator to use the queue content as a string
while (!is_null(input, input_len)) {
enqueue(&queue, divisible_by_two(input, input_len) ? '0' : '1');
divide_by_two(input, input_len);
}
free(input);
char* output = queue_get_arr(&queue);
printf("%s\n", output);
free(output);
free_char_queue(&queue);
}
}
This is not the fastest approach, but it is very simple. Also feel free to optimize it.
How do I convert a really long string (as decimal characters) to binary?
Let us look at printing this.
print2(s)
If the decimal string is at least "2",
__ Divide the decimal string by 2 and notice its remainder.
__ Recursively call print2(s)
__ Print the remainder.
Else print the string.
Example code:
#include <stdio.h>
unsigned decimal_string_divide(char *dividend, unsigned divisor) {
// Remove a potential leading '0'
if (*dividend == '0') {
memmove(dividend, dividend+1, strlen(dividend));
}
// "divide", like we learned in grade school.
unsigned remainder = 0;
while (*dividend) {
unsigned sum = remainder*10 + (*dividend - '0');
remainder = sum%divisor;
*dividend = sum/divisor + '0';
dividend++;
}
return remainder;
}
void decimal_string_print_binary(char *dividend) {
//printf("<%s>\n", dividend); fflush(stdout);
if (dividend[0]) {
// If at least 2 digits or at least "2"
if (dividend[1] || (dividend[0] >= '2')) {
unsigned bit = decimal_string_divide(dividend, 2);
decimal_string_print_binary(dividend);
printf("%c", bit + '0');
} else {
printf("%c", *dividend);
}
}
}
void decimal_string_print_2(const char *dividend) {
printf("%-25s", dividend);
size_t sz = strlen(dividend) + 1;
char buf[sz]; // Use a VLA or allocate memory
strcpy(buf, dividend);
decimal_string_print_binary(buf);
printf("\n");
}
Test
int main(void) {
decimal_string_print_2("0");
decimal_string_print_2("1");
decimal_string_print_2("42");
decimal_string_print_2("8675309");
decimal_string_print_2("18446744073709551615");
}
Output
0 0
1 1
42 101010
8675309 100001000101111111101101
18446744073709551615 1111111111111111111111111111111111111111111111111111111111111111
To instead convert the string from decimal form into a binary string, allocate sufficient buffer (about log10(2) times string length) and instead of printing above, save to the buffer. Left for OP to do.
I am suggesting a better approach. whereby any arguments passed to a function that is not intended to be mutated, be received as a "const", and a local pointer be used to access the data of this "const".
IE:
void to_binary(const char *str) {
char *ptr = str;
...
Then use ptr.
I know that in this case, my argument is purely trivial and academic, but it is a good practice to get used to and may save you many headaches in the future.
Also, when dealing with binary data, use "unsigned char", to ensure that no type conversions are used. You will need bit 7 if the data is not ASCII or alike.
I tried to write a function to convert a string to an int:
int convert(char *str, int *n){
int i;
if (str == NULL) return 0;
for (i = 0; i < strlen(str); i++)
if ((isdigit(*(str+i))) == 0) return 0;
*n = *str;
return 1;
}
So what's wrong with my code?
*n = *str means:
Set the 4 bytes of memory that n points to, to the 1 byte of memory that str points to. This is perfectly fine but it's probably not your intention.
Why are you trying to convert a char* to an int* in the first place? If you literally just need to do a conversion and make the compiler happy, you can just do int *foo = (int*)bar where bar is the char*.
Sorry, I don't have the reputation to make this a comment.
The function definitely does not perform as intended.
Here are some issues:
you should include <ctype.h> for isdigit() to be properly defined.
isdigit(*(str+i)) has undefined behavior if str contains negative char values. You should cast the argument:
isdigit((unsigned char)str[i])
the function returns 0 if there is any non digit character in the string. What about "-1" and "+2"? atoi and strtol are more lenient with non digit characters, they skip initial white space, process an optional sign and subsequent digits, stopping at the first non digit.
the test for (i = 0; i < strlen(str); i++) is very inefficient: strlen may be invoked for each character in the string, with O(N2) time complexity. Use this instead:
for (i = 0; str[i] != '\0'; i++)
*n = *str does not convert the number represented by the digits in str, it merely stores the value of the first character into n, for example '0' will convert to 48 on ASCII systems. You should instead process every digit in the string, multiplying the value converted so far by 10 and adding the value represented by the digit with str[i] - '0'.
Here is a corrected version with your restrictive semantics:
int convert(const char *str, int *n) {
int value = 0;
if (str == NULL)
return 0;
while (*str) {
if (isdigit((unsigned char)*str)) {
value = value * 10 + *str++ - '0';
} else {
return 0;
}
}
*n = value;
return 1;
}
conversion of char* pointer to int*
#include
main()
{
char c ,*cc;
int i, *ii;
float f,*ff;
c = 'A'; /* ascii value of A gets
stored in c */
i=25;
f=3.14;
cc =&c;
ii=&i;
ff=&f;
printf("\n Address contained
in cc =%u",cc);
printf("\n Address contained
in ii =%u",ii);
printf(:\n Address contained
in ff=%u",ff);
printf(\n value of c= %c",
*cc);
printf(\n value of i=%d",
**ii);
printf(\n value of f=%f",
**ff);
}
void to_string(int x)
{
int value, i = 0;
char numericalChar[] = "0123456789";
char *string;
do
{
value = x % 10;
string[i++] = numericalChar[value];
x /= 10;
} while(x >= 0);
printf("%s\n", string);
}
I am trying to write a function that turns an integer into a string. I don't think there is nothing with my logic but I am getting a segfault and my printf() is not printing anything out. I probably missing something obvious. I have been sitting in front of the computer for an hour and still, I can't figure it out. Thanks in advance.
I guess you know that there are in fact standard function for this (e.g. sprintf - see example below) but just want to write it yourself, right...
In that case:
First of all you need to assign memory to hold the string. Using a char pointer is not enough. You get a seg fault because of that. A uninitialized pointer just points somewhere into memory where you are (most likely) not allowed to write. So when do... it seg faults. In this case just use a short fixed size char array instead.
Second it is much easier just to add each digit to the char '0' to get the correct digit. No need for an array as look up table.
Something like:
void to_string(int x)
{
char string[32] = "0";
if (x > 0)
{
char temp[32] = {0};
int i = 31;
// Build a temp string from from the end (right to left)
while(x > 0)
{
temp[--i] = '0' + (x % 10);
x /= 10;
}
// Copy the temp string to the target variable
strcpy(string, &temp[i]);
}
printf("%s\n", string);
}
Notice that this code only handles integers greater than or equal to zero. I'll leave negative integers as an exercise.
If you want to use e.g. sprintf it's as easy as:
int n = 42;
char string[32];
sprintf(string, "%d", n);
printf("%s\n", string);
So as people already commented on your question, you have not allocated space so:
char *string;
should be
char *string = malloc ( sizeof (char) * numberOfDigits);
and there is another seg fault that I could not figure out, while I fix it I will give you this:
itoa solutions
void to_string(int x) {
string s = "";
while(x){
s += (x % 10) + 48;
x /= 10;
}
printf("%s\n", s);
}
I used 'strlen' to find the length of a string, call it string a. I then did some other things to create a binary string. The binary strings value is longer than string a. I want to return the binary string as long as string a. How would I do that?
Let me try to code it out to maybe help clarify:
int main(int argc, char** argv)
{
int i, j, k, l, prefix_length, sum;
char *s, *dot, *binary_string, *ret_val, *temp_string;
char buf[] = "10.29.246.49/32";
s = strtok(buf, "/");
prefix_length = strlen(s);
for(i = 4; i > 0; i--){
dot = strtok(s, ".");
while (dot != NULL){
j = atoi(dot);
sum = sum + j;
s = strtok(NULL, ".");
}
*binary_string = dec_to_bin(sum);
}
strcpy(temp_string, "0");
for(l = prefix_length - strlen(binary_string); i > 0; i--){
strcat(temp_string, binary_string);
strcpy(binary_string, temp_string);
strcpy(tempstring, "0");
}
ret_val = binary_string;
return 0;
}
Also, can you look at my dec_to_bin and tell me if I'm calling it right and what have you:
char dec_to_bin(int decimal)
{
char *ret;
int d = decimal, i;
for (i = 128; i >= 1; i = i/2){
if(d / i){
ret += '1';
d -= i;
}
else
ret += '0';
}
return *ret;
}
Your dec_to_bin is trying to convert a number to a string of '1's and '0's, but is only returning the first char value
You are defining ret as a char * pointer, but you are using it like a std::string which it is not. It is a pointer to memory, and you have to provide it with some memory to point to. As it is you are overwriting random memory, although in debug mode ret probably is initialised to 0, so you will just get a memory exception.
You could allocate the memory with malloc, but this will lead to a world of pain as the way you call the function will simply result in memory leaks.
If you have to use char* pointers and not std::string then I would suggest passing it a buffer to write the string to. You know the string will always be 8 characters long plus the null terminator
char buffer[9];
dec_to_bin(sum, buffer);
ret += '1' is not doing what you think it does. It is adding a char value to a char* pointer which is totally different. You need to store the character at the location pointed to by ret, and then move ret to point to the next location
*ret = '1';
ret = ret + 1;
or
*ret++ = '1';
When this finishes ret will point to the end of the string, so you can't return that. There is not much benefit from returning a value you passed to the routine, but if you must then you need to save it
char* dec_to_bin(int decimal, char *buffer)
{
char *ret = buffer;
int d = decimal, i;
for (i = 128; i >= 1; i = i/2){
if(d / i){
*ret++ = '1';
d -= i;
}
else
*ret++ = '0';
}
return buffer;
}
You should run this program in a debugger, because that will teach you a lot about what is actually going on in your code
If binary_string was a std::string, which it needs to be for binary_string += to work, then
std::string return_val = binary_string.substr(0, strlen(a));
If you are limited to char * then
int l = strlen(a);
char* return_val = new char[l + 1];
strncpy(return_val, binary_string, l);
return_val[l] = 0;
specify variable name in only first call to strtok(). for operations on same string again use strtok() as,
strtok(NULL,".");
to know about using strtok() read this link.
To get the binary string you want, you can follow this procedure,
for(i = 4; i > 0; i--){
dot = strtok(s, ".");
if (dot != NULL){
j = atoi(dot);
sum=sum+j;
s = strok(NULL, ".");
}
else{
k = atoi(s);
sum=sum+j;
}
//printf("%s\n", dot);
}
binarystring=dec2bin(sum);
you can reduce this loop and use,
dot = strtok(s, ".");
while (dot != NULL)
{
j = atoi(dot);
sum=sum+j;
s = strok(NULL, ".");
}
binarystring=dec2bin(sum);
here instead of adding binary number, you can add integers and then convert the sum to binary. the result will be same number right.dec2bin() should convert decimal to binary and return binary number as string. then you add code similar to this to make binary_string length same as length of a,
strcpy(tempstring,"0");
for(i=strlen(a)-strlen(binary_string);i>0;i--)
{
strcat(tempstring,binary_string);
strcpy(binary_string,tempstring);
strcpy(tempstring,"0");
}
I'm trying to convert a string of binary characters to an integer value.
For example: "100101101001" I would split it into four segments using a for loop then store it in array[4]. However whenever I use the function atoi(), I encounter a problem where it does not convert the character string properly if the string starts with "0".
An example would be "1001" = 1001, but if it is 0110 it would be converted to 110, also with 0001 it would be come only 1.
Here is the code that I made:
for(i = 0; i < strlen(store); i++)
{
bits[counter] = store [i];
counter++;
if(counter == 4)
{
sscanf(bits, "%d", &testing);
printf("%d\n", testing);
counter = 0;
}
}
The atoi() function only converts decimal numbers, in base 10.
You can use strtoul() to convert binary numbers, by specifying a base argument of 2. There is no need to "split" the string, and leading zeroes won't matter of course (as they shouldn't, 000102 is equal to 102):
const char *binary = "00010";
unsigned long value;
char *endp = NULL;
value = strtoul(binary, &endp, 2);
if(endp != NULL && *endp == '\0')
printf("converted binary '%s' to integer %lu\n", binary, value);
atoi() convert from char array to int and not to binary
you can use the following function
int chartobin(char *s, unsigned int *x) {
int len = strlen(s), bit;
*x = 0;
if(len>32 || len<1) return -1;
while(*s) {
bit = (*s++ - '0');
if((bit&(~1U))!=0) return -1;
if (bit) *x += (1<<(len-1));
len--;
}
return 0;
}
Tested and it works