An example says more than thousand words:
unsigned char *hello = (unsigned char*)malloc(STR_LEN * sizeof(unsigned char));
const char *str= "haha";
memcpy(hello, str, strlen(str) + 1);
How can I print the content of the whole hello-variable (printf("%s",..) would only respect the part before the \0-termination and not all STR_LEN characters).
You can use fwrite to write unformatted data:
char buf[4] = { 1, 2 };
fwrite(buf, 1, 4, stdout); // writes the bytes 1, 2, 0, 0
You could use fwrite(hello, 1, STR_LEN, stdout), but note that you're not allowed to read uninitialized data (so you should use calloc instead or initialize the data in some other way).
You'd have to write your own for loop that goes from hello to hello+STR_LEN, and prints each character one at a time.
for (unsigned char *c = hello, e = hello +STR_LEN; c < e; ++c) {
printf("%c", *c);
}
int i;
for(i = 0; i < STR_LEN; i++) {
putchar(hello[i]);
}
Related
I have 2 questions.
First question is that, I'm trying to find the frequency of the sentence and put them into another array. However, the output of the new frequency nfreq is different from what is appended in for loop.
void append(char* s, char c)
{
int len = strlen(s);
s[len] = c;
s[len+1] = '\0';
}
int main()
{
char str[] = "test sentence";
char nstr[] = "";
int freq[256] = {};
int nfreq[256] = {};
for(int i = 0; str[i] != '\0'; i++)
{
freq[str[i]]++;
}
printf("\nCharacter Frequency\n");
int j = 0;
for(int i = 0; i < sizeof(freq) / sizeof(int); i++)
{
if(freq[i] != 0)
{
printf("%5c%10d\n", i, freq[i]);
char c = i;
append(nstr, c);
int f = freq[i];
nfreq[j] = f;
printf("Num in nfreq[%d] is %d\n", j, nfreq[j]);
j++;
}
}
for(int i = 0; i < strlen(nstr); i++)
{
printf("%d ", nfreq[i]);
}
printf("\n");
printf("size of nfreq : %lu\n", sizeof(nfreq) / sizeof(nfreq[0]));
printf("size of str : %lu\n", strlen(str));
printf("size of nstr : %lu\n", strlen(nstr));
printf("nstr is : %s\n", nstr);
return 0;
}
The frequency of each letter is
Character Frequency
1
c 1
e 4
n 2
s 2
t 3
and nfreq should have those {1, 1, 4, 2, 2, 3} in its array with the code above and it even
says Num in nfreq[0] is 1 and etc in the loop, but when I try to check what's in nfreq outside the loop, it outputs {116, 1, 4, 2, 2, 3} this instead. What is this 116 and it should be 1 for the frequency of ' '.
Also the second question is that, if I were not to declare the size of an int array, int nfreq[] = {} like so in the beginning, does the size of this array, after appending int with for loop, changes dynamically? Or does it stay 0?
I tried fixing it by not declaring the size (which I don't think it matters) of nfreq array.
Thanks in advance for your help :)
Edit :
Sorry I forgot to add append function.
char nstr[] = "";
nstr is an array of one character.
append(nstr, c);
...
s[len+1] = '\0';
len is 0, so len + 1 is 1. This line is writing out-of-bounds to nstr. nstr is char [1]. You can only nstr[0] = something. nstr[1] is invalid.
Do:
char nstr[256] = "";
if I were not to declare the size of an int array, int nfreq[] = {} like so in the beginning, does the size of this array, after appending int with for loop, changes dynamically?
Notes: the {} is technically invalid, use {0} Is an empty initializer list valid C code? . int nfreq[] = {} is technically invalid code, it doesn't make sense, if it would, then nfreq would have zero size.
There are no "dynamic" changes of array size. Array has constant size. Writing out-of-bounds to an array is an error in the code.
Invalid initialization:
int freq[256] = {};
is invalid. ISO C forbids empty initializer braces. An initializer-list must contain at least one initializer.
Perhaps:
int freq[256] = { 0 };
Re:
if I were not to declare the size of an int array, int nfreq[] = {}
like so in the beginning, does the size of this array, after appending
int with for loop, changes dynamically? Or does it stay 0?
Answer: No.
int nfreq[] = {};
is not a valid statement. The space doesn't change dynamically.
Either declare an automatic array with fixed size like this:
int nfreq[SIZE] = { 0 };
or dynamically allocate memory with malloc(), and reallocate with realloc() as necessary.
Incorrect format specifier:
strlen() and sizeof() returns a type size_t. %lu might not be the correct format specifier for size_t. Use %zu instead.
See also:
Writing to out of bounds memory:
void append(char* s, char c)
{
int len = strlen(s);
s[len] = c;
s[len+1] = '\0';
}
You didn't allocate any memory for the array that has decayed to a pointer in append(). So this writes to out of bounds memory, and exhibits undefined behaviour.
I have a project in which I'm supposed to take in a file via the getchar() function and convert the binary characters within it to text.
Here is the code I have, that will produce the correct ASCII number for only one at a time. I don't know how to read in an entire text file's worth of binary and convert it:
#include <stdio.h>
#include <string.h>
typedef unsigned char byte;
typedef unsigned int uint;
int strbin_to_dec(const char *);
int main(void) {
char * wbin = "01001001";
int c = 0;
printf("%s to ascii %d.\n", wbin, strbin_to_dec(wbin));
printf("The character is %c", strbin_to_dec(wbin));
return 0;
}
int strbin_to_dec(const char * str) {
uint result = 0;
for (int i = strlen(str) - 1, j = 0; i >= 0; i--, j++) {
byte k = str[i] - '0';
k <<= j;
result += k;
}
return result;
}
The above code works when I enter exactly one character's worth of binary into the variable 'wbin', but I can't format this to accept the input from getchar() because getchar gives an int type. The above code produces the result:
01001001 to ascii 73.
The character is I
The file I'm supposed to translate looks like this:
0010001001001000011011110111011100100000011011110110011001110100011001010110111000100000011010000110000101110110011001010010000001001001001000000111001101100001011010010110010000100000011101000110111100100000011110010110111101110101
011101000110100001100001011101000010000001110111011010000110010101101110001000000111100101101111011101010010000001101000011000010111011001100101001000000110010101101100011010010110110101101001011011100110000101110100011001010110010000100000011101000110100001100101001000000110100101101101011100000110111101110011011100110110100101100010011011000110010100101100
01110111011010000110000101110100011001010111011001100101011100100010000001110010011001010110110101100001011010010110111001110011001011000010000001101000011011110111011101100101011101100110010101110010001000000110100101101101011100000111001001101111011000100110000101100010011011000110010100101100
01101101011101010111001101110100001000000110001001100101001000000111010001101000011001010010000001110100011100100111010101110100011010000011111100100010
0010110101010011011010010111001000100000010000010111001001110100011010000111010101110010001000000100001101101111011011100110000101101110001000000100010001101111011110010110110001100101001011000010000001010100011010000110010100100000010100110110100101100111011011100010000001001111011001100010000001000110011011110111010101110010
This is a trivial task to perform simply by using bit shifting. Also instead of using getchar, for performance, the below uses fread.
This implementation uses minimal RAM (no use of malloc), no slow string parsing or math functions such as strlen, strtol or pow, and can handle any stream of infinite size/length, including truncated streams that are not multiples of 8 bytes.
Usage:
./a.out < data.txt > out.txt
#include <stdio.h>
int main(int argc, char * argv[])
{
unsigned char byte = 0;
int bits = 0;
for(;;)
{
char buffer[1024];
int len = fread(buffer, 1, sizeof(buffer), stdin);
// if there was a read error or EOF, stop
if (len <= 0)
break;
for(int i = 0; i < len; ++i)
{
switch(buffer[i])
{
// if a binary 1, turn on bit zero
case '1':
byte |= 1;
break;
// if a binary 0, do nothing
case '0':
break;
// if antyhing else, skip
default:
continue;
}
// incrment the counter, if we dont yet have 8 bits
// shift all the bits left by one
if (++bits < 8)
byte <<= 1;
else
{
// write out the complete byte
fwrite(&byte, 1, 1, stdout);
// reset for the next byte
bits = 0;
byte = 0;
}
}
}
// write out any remaining data if the input was not a multiple of 8 in length.
if (bits)
fwrite(&byte, 1, 1, stdout);
return 0;
}
Input:
0010001001001000011011110111011100100000011011110110011001110100011001010110111000100000011010000110000101110110011001010010000001001001001000000111001101100001011010010110010000100000011101000110111100100000011110010110111101110101
011101000110100001100001011101000010000001110111011010000110010101101110001000000111100101101111011101010010000001101000011000010111011001100101001000000110010101101100011010010110110101101001011011100110000101110100011001010110010000100000011101000110100001100101001000000110100101101101011100000110111101110011011100110110100101100010011011000110010100101100
01110111011010000110000101110100011001010111011001100101011100100010000001110010011001010110110101100001011010010110111001110011001011000010000001101000011011110111011101100101011101100110010101110010001000000110100101101101011100000111001001101111011000100110000101100010011011000110010100101100
01101101011101010111001101110100001000000110001001100101001000000111010001101000011001010010000001110100011100100111010101110100011010000011111100100010
0010110101010011011010010111001000100000010000010111001001110100011010000111010101110010001000000100001101101111011011100110000101101110001000000100010001101111011110010110110001100101001011000010000001010100011010000110010100100000010100110110100101100111011011100010000001001111011001100010000001000110011011110111010101110010
Output:
"How often have I said to youthat when you have eliminated the impossible,whatever remains, however improbable,must be the truth?"-Sir Arthur Conan Doyle, The Sign Of Four
This is a function made by me! I dont know if you use the file as a parameter of execution like: ./text.exe -f binary.txt! But I dont add entries to the program! I has defined the file by my self!
I have created a function to write to a file, but if you want to use the command like ./text.exe -f binary.txt > translatedfile.txt you can simply remove the function write_to_file! Dont forget to remove the prints that you dont want because the parameter ">" will print everything!
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void binary_to_char(char *str);
void write_to_file(char *text);
int main(void)
{
printf("Getting line from file\n");
FILE *file;
char *line = NULL;
size_t len = 0;
ssize_t stringLength;
file = fopen("binary.txt", "r");
if (file == NULL)
{
fprintf(stderr, "[ERROR]: cannot open file -- binary.txt");
perror("");
exit(1);
}
while ((stringLength = getline(&line, &len, file)) != -1)
{
printf("\n%s", line);
binary_to_char(line);
}
free(line);
fclose(file);
return 0;
}
void binary_to_char(char *str)
{
char binary[9];
char *text = malloc((strlen(str) + 1) * sizeof(char));
char c;
int pos = 0;
int letter_pos = 0;
printf("\nConverting into characters\n");
for (size_t j = 0; j < strlen(str) / 8; j++)
{
for (int i = 0; i < 8; i++)
{
binary[i] = str[pos];
pos++;
}
c = strtol(binary, 0, 2);
text[letter_pos] = c;
letter_pos++;
}
printf("\n%s\n", text);
write_to_file(text);
free(text);
}
void write_to_file(char *text)
{
printf("\nContent saved to translatedfile.txt\n");
FILE *fp;
fp = fopen("translatedfile.txt", "w+");
fprintf(fp, "%s", text);
fclose(fp);
}
Content of File binary.txt:
001000100100100001101111011101110010000001101111011001100111010001100101011011100010000001101000011000010111011001100101001000000100100100100000011100110110000101101001011001000010000001110100011011110010000001111001011011110111010101110100011010000110000101110100001000000111011101101000011001010110111000100000011110010110111101110101001000000110100001100001011101100110010100100000011001010110110001101001011011010110100101101110011000010111010001100101011001000010000001110100011010000110010100100000011010010110110101110000011011110111001101110011011010010110001001101100011001010010110001110111011010000110000101110100011001010111011001100101011100100010000001110010011001010110110101100001011010010110111001110011001011000010000001101000011011110111011101100101011101100110010101110010001000000110100101101101011100000111001001101111011000100110000101100010011011000110010100101100011011010111010101110011011101000010000001100010011001010010000001110100011010000110010100100000011101000111001001110101011101000110100000111111001000100010110101010011011010010111001000100000010000010111001001110100011010000111010101110010001000000100001101101111011011100110000101101110001000000100010001101111011110010110110001100101001011000010000001010100011010000110010100100000010100110110100101100111011011100010000001001111011001100010000001000110011011110111010101110010
Read in all the input from the file, and pass in 8 chars at a time to a converter function to return a char. Each char is 8 bits, and each character in the file represents 1 bit.
char string_to_character(char * in)
{
char ret = 0;
int i;
for(i = 7; i >= 0; i--)
if(in[i] == '1')
ret += 1 << (7 - i);
return ret;
}
This function will decode each 8 chars from the file into one character. Simply call the function with an offset of 8 chars for the entire input string and save the result somewhere.
EDIT: Be sure to include and link math library math.h.
EDIT 2: Should be >= not >
For looping...
Say you have the entire file as one long string.
int num_chars = (sizeof(input) / sizeof(char)) / 8;
int i;
char output[num_chars + 1];
for(i = 0; i < num_chars; i++)
output[i] = string_to_character(input + (i * 8));
printf("%s", output);
This was the result I got from the program
"How often have I said to youthat when you have eliminated the impossible,whatever remains, however improbable,must be the truth?"-Sir Arthur
Conan Doyle, The Sign Of Four
EDIT: left bitshift vs pow
I'm having difficulty in generating a string of the form "1,2,3,4,5" to pass to a command line program.
Here's what I have tried:
int N=100;
char list[200];
for (i=0; i<2*N; i+=2) {
char tmp;
sprintf(tmp,'%d', i);
strcpy(list[i], tmp);
strcpy(list[i+1], ',');
}
Edit:
I don't feel this question is a duplicate as it is more to do with appending strings into a list and managing that memory and than literally just putting a comma between to integers.
The following code will do what you need.
#include <stdlib.h>
#include <stdio.h>
char* CommaSeparatedListOfIntegers(const int N)
{
if (N < 1)
return NULL;
char* result = malloc(1 + N*snprintf(NULL, 0, "%d,", N));
char* p = result;
for (int i = 1; i <= N; i++)
p += sprintf(p, "%d,", i);
*(p-1) = '\0';
return result;
}
Note that the function returns a heap allocated block of memory that the caller is responsible for clearing up.
Some points of note:
We put a crude upper bound on the length of each number when converted to text. This does mean that we will over allocate the block of memory, but not by a massive amount. If that is a problem for you then you can code a more accurate length. That would involve looping from 1 to N and calling snprintf for each value to determine the required length.
Note that we initially write out a comma after the final value, but then replace that with the null-terminator.
Let's forget about writing strings for the moment and write a function that just prints that list to the screen:
int range_print(int begin, int end, const char *sep)
{
int len = 0;
int i;
for (i = begin; i < end; i++) {
if (i > begin) {
len += printf("%s", sep);
}
len += printf("%d", i);
}
return len;
}
You can call it like this:
range_print(1, 6, ", ");
printf("\n");
The function does not write a new-line character, so we have to do that. It prints all numbers and a custom separator before each number after the first. The separator can be any string, so this function also works if you want to separate your numbers with slashes or tabs.
The function has printf semantics, because it returns the number of characters written. (That value is often ignored, but it can come in handy, as we'll see soon.) We also make the upper bound exclusive, so that in order to print (1, 2, 3, 4, 5) you have tp pass 1 and 6 as bounds.
We'll now adapt this function so that it writes to a string. There are several ways to do that. Let's look at a way that works similar to snprintf: It should tabe a pre-allocated char buffer, a maximum length and it should return the number of characters written or, if the output doesn't fit, the number of characters that would have been written had the buffer been big enough.
int range(char *buf, int n, int begin, int end, const char *sep)
{
int len = 0;
int m, i;
for (i = begin; i < end; i++) {
m = snprintf(buf, n, "%s%d",
(i > begin) ? sep : "", i);
len += m;
buf += m;
n -= m;
if (n < 0) n = 0;
}
return len;
}
This function is tricky because it has to keep track of the number of characters written and of the free buffer still available. It keeps printing after the buffer is full, which is a bit wasteful in terms of performace, but it is legal to call snprintf with a buffer size of zero, and that way we keep the semantics tidy.
You can call this function like this:
char buf[80];
range(buf, sizeof(buf), 1, 6, ", ");
printf("%s\n", buf);
That means that we need to define a buffer that is large enough. If the range of numbers is large, the string will be truncated. We might therefore want a function that allocates a string for us that is long enough:
char *range_new(int begin, int end, const char *sep, int *plen)
{
int len = (end - begin - 1) * strlen(sep) + 1;
char *str;
char *p;
int i;
for (i = begin; i < end; i++) {
len += snprintf(NULL, 0, "%d", i);
}
str = malloc(len);
if (str == NULL) return NULL;
p = str;
for (i = begin; i < end; i++) {
if (i > begin) p += sprintf(p, "%s", sep);
p += sprintf(p, "%d", i);
}
if (plen) *plen = len - 1;
return str;
}
This function needs two passes: in the first pass, we determine how much memory we need to store the list. Next, we allocate and fill the string. The function returns the allocated string, which the user has to free after use. Because the return value is already used, we lose the information on the string length. An additional argument, a pointer to int, may be given. If it is not NULL, the length will be stored.
This function can be called like this.
char *r;
int len;
r = range_new(1, 6, ", ", &len);
printf("%s (%d)\n", r, len);
free(r);
Note that the same can be achieved by calling our old range function twice:
char *r;
int len;
len = range(NULL, 0, 1, 6, ", ");
r = malloc(len + 1);
range(p, len + 1, 1, 6, ", ");
printf("%s (%d)\n", r, len);
free(r);
So, pick one. For short ranges, I recommend the simple range function with a fixed-size buffer.
What would be the fastest/shortest way to create a string of repeating characters.
For instance, n = 10, char = '*', resulting allocated string: **********
Use memset.
int n = 10;
char c = '*';
char* buf = malloc(n+1);
memset(buf, c, n);
buf[n] = '\0';
free(buf);
memset(buf, '*', 10); buf[10]=0;
Replace '*' and 10 with the values you want, and if the length is not known in advance and could be large, use buf=malloc(n+1); to get your buffer.
char *allocate(int c, size_t n)
{
if(!c) return calloc(n + 1);
char *s = malloc(n + 1);
memset(s, c, n);
s[n] = '\0';
return s;
}
Honestly, why are you trying to do it fastest? Why not just do it, and then speed it up later if you need to?
Particularly, if you're only creating this to output it, you could just
void printtimes(int c, size_t n, FILE *f)
{
while(n--) fputc(c, f);
}
A function returns an aray of integers and I want it to pass to another function which searches for some pattern. But the second function expects a string.
Example:
int IArray = {1, 2, 3};
// should be coverted into "123"
Is there a direct function available? If not, how do I convert the array of integers into a string?
There is no direct function to do that.
You'll have to use sprintf.
There is nothing in the C stdlib to do this, but it isn't hard to write the string manipulations:
#include <assert.h>
int transform_ints_to_string(int const* data, int data_length,
char* output, int output_length)
{
// if not enough space was available, returns -1
// otherwise returns the number of characters written to
// output, not counting the additional null character
// precondition: non-null pointers
assert(data);
assert(output);
// precondition: valid data length
assert(data_length >= 0);
// precondition: output has room for null
assert(output_length >= 1);
int written = 0;
for (; data_length; data_length--) {
int length = snprintf(output, output_length, "%d", *data++);
if (length >= output_length) {
// not enough space
return -1;
}
written += length;
output += length;
output_length -= length;
}
return written;
}
Example:
int main() {
char buf[100] = "";
int data[] = {1, 2, 3};
if (transform_ints_to_string(data, 3, buf, sizeof buf) == -1) {
puts("not enough room");
}
else {
printf("%s\n", buf);
}
return 0;
}
Is there a direct function available I
can use?
NO
most c and c++ compilers support itoa function, which converts an int to a char*, or you can use sprintf to do this. The next thing is to concatenate all strings into a single string, you can use strcat . Follow the links, you will find examples for these two functions.
If your IArray variable contains integer values in the range [0,9], then you can do something like this (pseudocode):
string := ""
While more numbers:
string.append(next + '0')
In C, it is guaranteed that '0', '1', ..., '9' have consecutive integral values.
If this is not what you want, you need to define your problem more clearly.
int IArray = {1, 2, 3};
That's not C!
Do you mean;
int IArray[3] = {1, 2, 3};
You could do this...
for( loop = 0 ; loop < 3 ; loop++ )
*(((char *) IArray)+loop) = '0' + IArray[loop];
*(((char *) IArray)+loop) = 0;
printf( "%s\n", (char *) IArray );
...but I wouldn't if I were you :-)