Using C (syscall) to write an integer matrix into a text file? - c

So, I have my matrix, let's say
int matC[N][N],
which is already filled with integer values.
What I have to do is to save this matrix into a .txt file.
I've tried this:
1: convert the integers contained in the matrix into a string
char *buffer;
for (int i = 0 ; i < N ; i++)
{
for (int j = 0 ; j < N ; j++)
{
snprintf(buffer, sizeof(matC[i][j]), "%d", matC[i][j]);
}
}
2: write the string in a file (fileC.txt)
int fdC = open("fileC.txt", O_RDWR);
write(fdC, buffer, sizeof(buffer));
I do get something in my fileC.txt, but it's some sort of bunch of unintelegible symbols.
Thanks in anticipation for any help.

A few things.
First, you need to allocate memory for your buffer. sizeof(buffer) will be the size of a pointer, not the buffer length, so you you store that in buf_len. Depending on how many digits the numbers in your matrix are, you might need more or less space in your buffer.
Then, you don't want to write to the beginning of buffer with each snprintf call, but strchr(buffer, '\0') will return a pointer to the spot you want to write to. The second argument should be the length of the buffer from the spot you're currently at, which is buf_len - strlen(buffer).
Finally, you only want to write strlen(buffer) bytes to the file so you don't write random bytes to your file.
char *buffer;
int buf_len = 100;
buffer = (char*)malloc(buf_len);
buffer[0] = '\0';
for (int i = 0 ; i < N ; i++)
{
for (int j = 0 ; j < N ; j++)
{
snprintf(strchr(buffer, '\0'), buf_len - strlen(buffer), "%d", matC[i][j]);
}
}
int fdC = open("fileC.txt", O_RDWR);
write(fdC, buffer, strlen(buffer));
free(buffer);

Related

Most efficient way to concatenate strings in c

Consider this simple program that concatenates all specified parameters and prints them in standard output. I used 2 for loops to append the strings, one to calculate the length of that string and one to concatenate the strings. Is there a way doing it with only one loop? It wouldn't be more efficient reallocating memory for each string to concatenate, would it? How would Java's StringBuilder be implemented in C? Would it loop twice as I did?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
size_t len = 0;
// start for loop at i = 1 to skip the program name specified in argv
for(int i = 1; i < argc; i++)
len += strlen(argv[i]) + 1; // +1 for the space
char* toAppend = (char*)malloc(len * sizeof(char) + 1);
toAppend[0] = '\0'; // first string is empty and null terminated
for(int i = 1; i < argc; i++)
{
strcat(toAppend, argv[i]);
strcat(toAppend, " ");
}
printf(toAppend);
free(toAppend);
}
Your method of allocation is efficient, measuring the total length and allocating just once. But the concatenation loop repeatedly measures the length of the output buffer from the start to concatenate to it, resulting in quadratic runtime.
To fix it track your position as you go:
size_t pos = 0;
for(int i = 1; i < argc; i++) {
size_t len = strlen(argv[i]);
memcpy(toAppend+pos, argv[i], len);
pos += len;
toAppend[pos] = ' ';
pos++;
}
toAppend[pos] = 0;
This is the most efficient way to actually concatenate in memory, but the most efficient of all is not to concatenate. Instead:
for(int i = 1; i < argc; i++)
printf("%s ", argv[i]);
The whole reason stdio is buffered is so you don't have to build arbitrary-length in-memory buffers to do efficient output; instead it buffers up to a fixed size automatically and flushes when the buffer is full.
Note that your usage of printf is wrong and dangerous in the event that your input contains a % character anywhere; it should be printf("%s", toAppend);.
If you're writing to POSIX (or POSIX-ish) systems rather than just plain C, another option would be fmemopen, which would allow you to write the loop just as:
for(int i = 1; i < argc; i++)
fprintf(my_memfile, "%s ", argv[i]);
efficient way to concatenate strings in c
An efficient way is to calculate the string lengths - and remember them.
size_t sum = 1; // for \0
if (argc > 2) sum += argc - 2. // spaces
size_t length[argc]; // This is a VLA, available C99 and optionally in C11
for(int i = 1; i < argc; i++)
length[i] = strlen(argv[i]);
sum += length[i];
}
Then allocate, and then check for errors.
char *dest = malloc(sum);
if (dest == NULL) Handle_OutOfMemory();
Copy each string in turn
char *p = dest;
for(int i = 1; i < argc; i++)
// Use either memcpy() or strcpy().
// memcpy() tends to be faster for long strings than strcpy().
memcpy(p, argv[i], length[i]);
p += length[i]; // advance insertion point
if (i > 1) {
*p++ = ' '; // space separators
}
}
*p = '\0';
Now use dest[].
printf("<%s>\n", dest);
Free resources when done.
free(dest);
It wouldn't be more efficient reallocating memory for each string to concatenate, would it?
Usually repetitive re-allocations is best avoided, yet for small short strings it really makes scant difference. Focus on big O. My answer is O(n). Relocating in a loop tends to be O(n*n).
If performance was critical, try various approaches and profile for the intended system. The point being what is fast on one machine may differ on another. Usually it is best to first code a reasonable clear approach.
The most efficient way is probably to not use any str functions and copy the characters "by hand":
char* toAppend = malloc(len + 1);
size_t j = 0;
for(size_t i = 1; i < argc; i++)
{
for(size_t k = 0; argv[i][k]; k++)
toAppend[j++] = argv[i][k];
toAppend[j++] = ' ';
}
toAppend[j - 1] = '\0'; // Remove the last space and NULL-terminate the string

Trying to use memcpy to continuously update an array, but failing

Just some premilinary info, the below code is part of a user space HID driver Im building, so Im going to try my best
to skip over the sections relating to device conectivity, etc...
I have two main arrays that I focus on which is the buf[] array and the buffer[] array.
The buffer[] array will be comprised of ranges of hex values that are taken from the buf[] array and appended on to it.
With the purpose of the buffer[] basically holding a large number of bytes that can then be consumed else where.
But I seem to be running into issues with buffer size growing past 1400, I also feel as though my logic as far as adding
to the buffer is flawed and not working as I think it is. Is there another way that I should be going about trying to acomplish this end goal?
If this code does not show enough PLEASE let me know and I will make the neccesary edits, Im desperate for the help
and still very new to C. Thank you!
full code found here if necessary http://pastebin.com/cyawpXCq
int int main(int argc, char const *argv[])
{
unsigned char buf[64];
unsigned char buffer[1400]; //1400 is the max size this should ever be
int i;
size_t buffer_length = 0;
for (i = 0; i < 24; i++)
{
// in this loop I add elements to the buf[]
// these elements are sent to the device
// which then returns the buf[] with new elements
// in it.
// I then want to push a range of these elements
// into the buffer which I am attempeting like so
// I skip the first 7 elements and take the
// next 16 elements which follow and append those to
// the buffer[].
memcpy(buffer + buffer_length, buf + 8, 16);
printf("\nStored Buffer - \n");
for (size_t i= 0; i < sizeof(buffer); i++) {
printf("%02X ", buffer[i]);
}
// add another 16 to the length
buffer_length += 16;
// loop breaks based on another condition
break;
}
// This condition comes next and does a similar
// thing as above
if(true)
{
// buf[] gets returned to
// me containing hex values from a device. I now
// want to append these values into the buffer[]
// and take the 30 elements which come after the
// first 7.
memcpy(buffer + buffer_length, buf + 8, 30);
printf("\nStored Buffer - \n");
for (size_t i= 0; i < sizeof(buffer); i++) {
printf("%02X ", buffer[i]);
}
// add another 30 to the length
buffer_length += 30;
}
// this loop can can return up to about 200 unique buf[] arrays
// and again is doing a similar thing where buf[] is filled with device
// data
for( int address = 0x0370; address < 0x0370 + 1400 + 1400; address += 28)
{
// I want to append 28 elements following the 7th element from buf[]
// to the end of the buffer[] on each iteration
memcpy(buffer + buffer_length, buf + 8, 28);
printf("\nStored Buffer - \n");
for (size_t i= 0; i < sizeof(buffer); i++) {
printf("%02X ", buffer[i]);
}
// add 28 to length each time.
buffer_length += 28;
printf("buffer_length = %zu", buffer_length);
}
return 0;
}

printf cause problems with output

I have a little problem with the following C code. If I comment out "LINE 24" then I'll get the following output:
aaaaaaaaaaaaaaaaaaaaaaaaa
and if I don't comment it, I'll get the following:
aaaaaaaaaaaaaaaaaaaaaaaaadƔ?LƔ?LƔF?W?F?W?F?W?F?W?F?W?F?W?F?W?
Can somebody tell me why?
I am using mac os x 10.5.4 and gcc
void test(char* a , char* b);
int main()
{
char * str = "aaaaaaaaaaaaaaaaaaaaaaaaa";
char* str2 = malloc(4*sizeof(str));
test(str , str2);
return 0;
}
void test(char* a , char* b)
{
int i = 0;
printf("\n########\n");
for( i = 0 ; i < strlen(a) ; i++)
{
printf("%d" , i); /******** LINE 24 ********/
b[i] = a[i];
}
printf("\n########\n");
for( i = 0 ; i < strlen(b) ; i++)
{
printf("%c" ,*(b+i));
}
printf("\n########\n");
}
Thank you for responding.
I see two problems in your code:
First the allocation of str2:
char* str2 = malloc(4*sizeof(str)); // This will allocate 4 times the size of a char pointer. You cannot be sure that str will fit!
Second the copying of a to b.
You need to add a string terminator at the end of b:
for( i = 0 ; i < strlen(a) ; i++)
{
printf("%d" , i); /******** LINE 24 ********/
b[i] = a[i];
}
b[i] = '\0'; // Make sure b is properly terminated
char * str = "aaaaaaaaaaaaaaaaaaaaaaaaa";
char* str2 = malloc(4*sizeof(str));
str is a pointer which size is (presumably) 32 bit -> 4 bytes. So what you are allocating is not the size of the string, but the size four pointers to a string would require (16 bytes), whilke your string is 26 bytes long (including the 0 byte).
Addirtionally, when you output a string you must allocate one byte more than the length, to account for the 0 byte which indicates the end of the string.
char * str = "aaaaaaaaaaaaaaaaaaaaaaaaa";
char* str2 = malloc(strlen(str)+1);
int i;
for( i = 0 ; i < strlen(a) ; i++)
{
printf("%d" , i); /******** LINE 24 ********/
b[i] = a[i];
}
b[i] = 0; // Terminate the string.
If you don't terminate the string, then functions working on strings (like strlen, printf etc.) will scan the string untl they encounter the 0 byte which can be anywhere in your memory. So the strlen in your code, can sometimes seem to give the correct length if such a byte happens to be right at the end, but it will give wrong results more often (undefined behaviour), which accounts for the strange chars you see at your output.

How to use strncpy with a for-loop in C?

I am writing a program which will take every 3 numbers in a file and convert them to their ASCII symbol. So I thought I could read the numbers into a character array, and then make every 3 elements 1 element in a second array, convert them to int and then print these as char.
I am stuck on taking every 3 elements, however. This is my code snippet for this part:
char arry[] = "073102109109112"; <--example string read from a file
char arryNew[16] = {0};
for(int i = 0; i <= sizeof(arryNew); i++){
strncpy(arryNew, arry, 3);
arryNew[i+3]='\0';
puts(arryNew);
}
What this code gives me is the first 3 numbers, fifteen times. I've tried incrementing i by 3, which gives me the first 3 numbers 5 times. How do I write a for-loop with strncpy so that after copying n chars, it moves to the next n chars?
You pass always the pointer to the beginning of the array, so you will always have the same result of course. You must include the loop counter to get at the next block:
strncpy(arryNew, &arry[i*3], 3);
Here you have a problem:
arryNew[i+3]='\0';
First of all, you don't need to set the null byte every time, because this will not change anyway. Additionally you will corrupt memory, because you use i+3 as the index so when you reach 14 and 15, it will write beyond the arrayboundary.
Your arrayNew must be longer, because your original array is 16 characters, and your target array is also. If you intend to have several 3char strings in there, then you must have 5*4 characters for your target, because each string also has the 0-byte.
And of course, you must also use the index here as well. The way it is written now, it will write beyond the array boundary, when i reaches 14 and 15.
So what you seem to want to do (not sure from your description) is:
char arry[] = "073102109109112"; <--example string read from a file
char arryNew[20] = {0};
for(int i = 0; i <= sizeof(arry); i++)
{
strncpy(&arryNew[i*4], &arry[i*3], 3);
puts(&arryNew[i*4]);
}
Or if you just want to have the individual strings printed then you can just do:
char arry[] = "073102109109112"; <--example string read from a file
char arryNew[4] = {0};
for(int i = 0; i <= sizeof(arry); i++)
{
strncpy(arryNew, &arry[i*3], 3);
puts(arryNew);
}
Making things a bit simpler: your target string doesn't change.
char arry[] = "073102109109112"; <--example string read from a file
char target[4] = {0};
for(int i = 0; i < strlen(arry) - 3; i+=3)
{
strncpy(target, arry + i, 3);
puts(target);
}
Decoding:
start at the beginning of arry
copy 3 characters to target
(note the fourth element of target is \0)
print out the contents of target
increment i by 3
repeat until you fall off the end of the string.
Some problems.
// Need to change a 3 chars, as text, into an integer.
arryNew[i] = (char) strtol(buf, &endptr, 10);
// char arryNew[16] = {0};
// Overly large.
arryNew[6]
// for(int i = 0; i <= sizeof(arryNew); i++){
// Indexing too far. Should be `i <= (sizeof(arryNew) - 2)` or ...
for (i=0; i<arryNewLen; i++) {
// strncpy(arryNew, arry, 3);
// strncpy() can be used, but we know the length of source and destination,
// simpler to use memcpy()
// strncpy(buf, a, sizeof buf - 1);
memcpy(buf, arry, N);
// arryNew[i+3]='\0';
// Toward the loop's end, code is writing outside arryNew.
// Lets append the `\0` after the for() loop.
// int i
size_t i; // Better to use size_t (or ssize_t) for array index.
Suggestion:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char Source[] = "073102109109112"; // example string read from a file
const int TIW = 3; // textual integer width
// Avoid sprinkling bare constants about code. Define in 1 place instead.
const char *arry = Source;
size_t arryLen = strlen(arry);
if (arryLen%TIW != 0) return -1; // is it a strange sized arry?
size_t arryNewLen = arryLen/TIW;
char arryNew[arryNewLen + 1];
size_t i;
for (i=0; i<arryNewLen; i++) {
char buf[TIW + 1];
// strncpy(buf, a, sizeof buf - 1);
memcpy(buf, arry, TIW);
buf[TIW] = '\0';
char *endptr; // Useful should OP want to do error checking
// TBD: test if result is 0 to 255
arryNew[i] = (char) strtol(buf, &endptr, 10);
arry += TIW;
}
arryNew[i] = '\0';
puts(arryNew); // prints Ifmmp
return 0;
}
You could use this code to complete your task i.e. to convert the given char array in form of ascii value.
char arry[] = "073102109109112";
char arryNew[16] = {0};
int i,j=0;
for(i = 0; i <= sizeof(arryNew)-2; i+=3)
{
arryNew[j]=arry[i]*100+arry[i+1]*10+arry[i+2]*1;
j++;
arryNew[j+1]='\0';
puts(arryNew);
}

How to copy integer array contents to a character pointer?

I have a character pointer , char *buf;
I have a array of integers , int console_buffer[256];
I need to copy the console_buffer contents to character buf.
How do I do this? The buf and console_buffer are part of different structures.
Going by your comment,
buf = malloc(256); // 257 if console_buffer may be full without EOF
/* if you want to allocate just as much space as needed, locate the EOF in console_buffer first */
for(int i = 0; i < 256 && console_buffer[i] != -1; ++i){
buf[i] = (char)console_buffer[i];
}
If you already allocated the memory for buf, and if each integer is between 0 and 9, you can do:
for(int i = 0; i < 256; i++)
{
buf[i] = '0' + console_buffer[i]; /* convert 1 to '1', etc. */
}
If the integers are larger than 9, you can use the sprintf function.
Reading your new comment, perhaps you can also achieve your goal by reading from console buffer directly to an array of chars until you have -1 (check by integers comparison, or by strcmp, or by comparing the 2 last characters to 0 and to 1).
I think this is a better way to convert values to chars
int i = 0;
while (i <= 256) {
buf[i] = (char) console_buffer[i];
i++;
}

Resources