Suppose we have a matrix in C (a 2D array).
I wonder how could I print the matrix into a string in C.
For example, if I have
double M[2][2]={{1.2,3.4},{3.14,2.718}}
I want to get a string like this:
"1.200 3.400\n3.140 2.718"
which could be printed as
1.200 3.400
3.140 2.718
If print to screen, the problem will become easier because we need not consider the buffer size. However, when printing to a string, it seems hard to know how large the string buffer should be, if I want to use functions like 'sprintf'.
I searched google and stackoverflow but almost all of what I get is about how to convert string to numerical...
How to do this in C? Are there any libs?
Could you please help? Thank you!
EDIT:
The 'snprintf' solution works well for the situation of just one number.
But for matrix, it is supposed to use loops to go through every element.
And then add a little to the string in each loop. Will this work with 'snprintf'?
You'll need to do this in two steps, first calculate the total size to hold the string, then allocate it and compose the string. Could be done in a function like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
static char * matrix2D_to_string(const double *matrix, size_t rows, size_t columns)
{
const char format[] = "%f";
const char column_separator[] = " ";
const char row_separator[] = "\n";
int *column_widths = NULL;
size_t r = 0, c = 0;
char *buffer = NULL, *p = NULL;
size_t size = 0;
if (!rows || ! columns) {
errno = EINVAL;
return NULL;
}
// calculate maximum width for each column
column_widths = (int *)calloc(columns, sizeof(*column_widths));
for (r = 0; r < rows; ++r) {
for (c = 0; c < columns; ++c) {
char buf[256];
int width = sprintf(buf, format, matrix[r * columns + c]);
if (width > column_widths[c]) {
column_widths[c] = width;
}
}
}
// calculate total buffer size...
// ... values
for (c = 0; c < columns; ++c) {
size += column_widths[c] * rows;
}
// ... column separators
size += (columns - 1) * strlen(column_separator);
// ... row separators
size += (rows - 1) * strlen(row_separator);
// ... nul terminator
++size;
// make the string
buffer = (char *)malloc(size);
p = buffer;
for (r = 0; r < rows; ++r) {
if (r) {
strcpy(p, row_separator);
p += strlen(row_separator);
}
for (c = 0; c < columns; ++c) {
if (c) {
strcpy(p, column_separator);
p += strlen(column_separator);
}
int width = sprintf(p, format, matrix[r * columns + c]);
p += width;
if (width < column_widths[c]) {
width = column_widths[c] - width;
memset(p, ' ', width);
p += width;
}
}
}
*p = '\0';
// cleanup
free(column_widths);
return buffer;
}
int main()
{
double M[3][2]={{1.2,3.4},{3.14,2.718},{100.999,0.000005}};
char *s = matrix2D_to_string((const double *)M, ARRAY_SIZE(M), ARRAY_SIZE(M[0]));
puts(s);
free(s);
return 0;
}
This prints:
1.200000 3.400000
3.140000 2.718000
100.999000 0.000005
You may use snprintf to get buffer length you need first and then allocate and print into it:
char* PrettyPrint(const char* format, ...)
{
va_args va;
va_start(va, format);
char c[1] = {};
int len = vsnprintf(c, 1, format, va);
char* s = malloc(len + 1);
vsnprintf(s, len + 1, format, va);
va_end(va);
return s;
}
You can start with some estimated size, and use realloc if it isn't enough.
If snprintf returns more than the remaining buffer size, it means it didn't have enough room. In this case, you should reallocate, and retry the same snprintf.
Its array.
considering float values.
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
printf("%f \t",M[i][j]);
}
printf("\n");
}
Hope this will help you.
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
printf("%f \t",M[i][j]);
}
printf("\\n");//Change printf("\n") as printf("\\n")
}
#include <stdio.h>
#include <stdlib.h>
long GetFileSize(FILE *fp){
long fsize = 0;
fseek(fp,0,SEEK_END);
fsize = ftell(fp);
fseek(fp,0,SEEK_SET);//reset stream position!!
return fsize;
}
char *ReadToEnd(const char *filepath){
FILE *fp;
long fsize;
char *buff;
if(NULL==(fp=fopen(filepath, "rb"))){
perror("file cannot open at ReadToEnd\n");
return NULL;
}
fsize=GetFileSize(fp);
buff=(char*)malloc(sizeof(char)*fsize+1);
fread(buff, sizeof(char), fsize, fp);
fclose(fp);
buff[fsize]='\0';
return buff;
}
char *printStrMatrix(const char *fmt, const int col, const int row, const double* matrix ){
FILE *fp;
int c,r;
char *str;
if(NULL==(fp=fopen("printStr.tmp", "wb"))){//use tmpnam() better
perror("temporary file cannot open at printStr\n");
return NULL;
}
for(r=0;r<row;++r){
for(c=0;c<col;++c){
fprintf(fp, fmt, *matrix++);
if(c != col-1)
fprintf(fp, " ");
}
fprintf(fp, "\n");
}
fflush(fp);
fclose(fp);
str=ReadToEnd("printStr.tmp");
remove("printStr.tmp");
return str;
}
int main(void){
double M[2][2]={{1.2,3.4},{3.14,2.718}};
char *str;
str=printStrMatrix("%1.3lf", 2, 2, &M[0][0]);
printf("%s", str);
free(str);
return 0;
}
Related
I am having trouble with the very last line in my function, where I am stilly learning the basics of C. I have the signature of this function given and am tasked to write a function to concatenate two strings. The commented line outputs the correct result.
#include <stdio.h>
#include <stdlib.h>
// 1) len = dst-len + max_dst_len
int strlcat(char *dst, const char *src, int max_dst_len) {
int len = 0;
while (dst[len] != '\0') {
len++;
}
int total_len = len + max_dst_len;
char *new_str = malloc(sizeof(char) * total_len);
for (int i = 0; i < len; i++) {
new_str[i] = dst[i];
}
for (int i = len; i < total_len; i++) {
new_str[i] = src[i - len];
}
new_str[total_len] = '\0';
//printf("%s <--\n", new_str);
dst = *new_str;
return total_len;
}
int main() {
char test1[] = "dst";
char test1src[] = "src";
printf("%s\n", test1);
printf("%d\n", strlcat(test1, test1src, 10));
printf("%s\n", test1);
}
You should not be adding max_dst_len to the length of dst. max_dst_len is the amount of memory that's already allocated in dst, you need to ensure that the concatenated string doesn't exceed this length.
So you need to subtract len from max_dst_len, and also subtract 1 to allow room for the null byte. This will tell you the maximum number of bytes you can copy from src to the end of dst.
In your main() code, you need to declare test1 to be at least 10 bytes if you pass 10 as the max_dst_len argument. When you omit the size in the array declaration, it sizes the array just big enough to hold the string you use to initialize it. It's best to use sizeof test1 as this argument, to ensure that it's correct for the string you're concatenating to.
#include <stdio.h>
int strlcat(char *dst, const char *src, int max_dst_len) {
int len = 0;
while (dst[len] != '\0') {
len++;
}
int len_to_copy = max_dst_len - len - 1;
int i;
for (i = 0; i < len_to_copy && src[i] != '\0'; i++) {
dst[len+i] = src[i];
}
dst[i] = '\0';
//printf("%s <--\n", new_str);
return i + len;
}
int main() {
char test1[6] = "dst";
char test1src[] = "src";
printf("%s\n", test1);
printf("%d\n", strlcat(test1, test1src, sizeof test1));
printf("%s\n", test1);
}
I have an assignment, I need to create a method that receives (char * * ch,site_t size).
ch is an array of addresses to char arrays, I need to make it so that the shortest element will be first (address and place) and longest will be last one (address and place). Here is what made so far although it doesn't work on array size 5 (tried only on size 4):
(Note: I used char * arr[] but I planned to changing it once I get the program working with this type of variable.)
void AdressSwitcher(char * arr[],size_t size){
char*shortest=arr[0];
char*shortestFollower=NULL;
char*longest=arr[1];
char*longestFollower=NULL;
for(size_t i=0;i<size;i++){
if(strlen(arr[i])<(strlen(shortest))){
shortest=arr[i];
arr[i]=arr[0];
}
arr[0]=shortest;
}
for(size_t i=1;i<size;i++){
if(strlen(arr[i])>(strlen(longest))){
longest=arr[i];
arr[i]=arr[size-1];
}
arr[size-1]=longest;
// }
for(size_t i=0;i<size;i++){
printf("%s %p", arr[i],arr[i]);
printf("\n");
}
}
Welcome to SO. This problem can be easily solved with the following method:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *escape_double_quotes(const char *s)
{
char *result = calloc((strlen(s) * 2) + 1, sizeof(char));
size_t resultIndex = 0;
for (size_t i = 0; s[i] != '\0'; i++)
{
if (s[i] == '"')
{
result[resultIndex] = '\\';
resultIndex++;
result[resultIndex] = '"';
resultIndex++;
continue;
}
result[resultIndex] = s[i];
resultIndex++;
}
return result;
}
void longestAndShortest(char **arr, const size_t size)
{
if (size <= 1)
return;
size_t shortIndex = 0;
size_t shortSize = strlen(arr[0]);
size_t longIndex;
size_t longSize = 0;
for (size_t i = 0; i < size; i++)
{
size_t b = strlen(arr[i]);
if (b > longSize)
{
longIndex = i;
longSize = b;
}
if (b < shortSize)
{
shortIndex = i;
shortSize = b;
}
}
printf("The shortest size of the array was %lu, the index of that being %lu and the contents of that being \"%s\".\n", shortSize, shortIndex, escape_double_quotes(arr[shortIndex]));
printf("The longest size of the array was %lu, the index of that being %lu and the contents of that being \"%s\".\n", longSize, longIndex, escape_double_quotes(arr[longIndex]));
return;
}
int main(void)
{
char **array = malloc(sizeof(char*) * 8);
array[0] = malloc(128);
strcpy(array[0], "World!");
array[1] = malloc(128);
strcpy(array[1], "Hello");
longestAndShortest(array, 2);
for (size_t i = 0; i < 2; i++)
free(array[i]);
free(array);
return 0;
}
From here you should be able to complete the rest.
Please work on writing more tidy code. Your future self will thank you.
Have a great day!
I want to compare 2 files for identical lines: mytab2411.txt(15,017,210 bytes in size) and shadow.txt (569 bytes in size) but when I compiled this code and ran the program, I get a segmentation fault. I know that it's because the "mytab2411.txt" file exceeds the size of "char buf" but how do I go about solving this problem without overflowing the buffer?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
int cmp(const void * s1, const void * s2)
{
return strcasecmp(*(char **)s1, *(char **)s2);
}
int cmp_half(const char * s1, const char * s2)
{
int i;
for (i = 0; i < 3; i++)
{
int res = strncasecmp((char *)s1+i*3, (char *)s2+i*3, 2);
if (res != 0) return res;
}
return 0;
}
char * line[1024];
int n = 0;
int search(const char * s)
{
int first, last, middle;
first = 0;
last = n - 1;
middle = (first+last)/2;
while( first <= last )
{
int res = cmp_half(s, line[middle]);
if (res == 0) return middle;
if (res > 0)
first = middle + 1;
else
last = middle - 1;
middle = (first + last)/2;
}
return -1;
}
int main()
{
FILE * f1, * f2;
char * s;
char buf[1024*1024], text[1024];
f1 = fopen("shadow.txt", "rt");
f2 = fopen("mytab2411.txt", "rt");
s = buf;
while (fgets(s, 1024, f2) != NULL)
{
line[n] = s;
s = s+strlen(s)+1;
n++;
}
qsort(line, n, sizeof(char *), cmp);
while (fgets(text, 1024, f1) != NULL)
{
text[strlen(text)-1] = 0;
int idx = search(text);
if (idx >= 0)
{
printf("%s matched %s\n", text, line[idx]);
}
else
{
printf("%s not matched\n", text);
}
}
return 0;
}
Your method assumes that each line in the file is 1024 bytes long. In practice the lines can be up to 1024 bytes, but most lines are much shorter. Use strdup or malloc to allocate memory for each line based on line's length.
Store the lines in dynamically allocated arrays. This is about 15 MB of data and it should not be a problem unless there are resource limitations.
int main(void)
{
char buf[1024];
char **arr1 = NULL;
char **arr2 = NULL;
int size1 = 0;
int size2 = 0;
FILE * f1, *f2;
f1 = fopen("shadow.txt", "r");
f2 = fopen("mytab2411.txt", "r");
while(fgets(buf, 1024, f1))
{
size1++;
arr1 = realloc(arr1, sizeof(char*) * size1);
arr1[size1 - 1] = strdup(buf);
}
while(fgets(buf, 1024, f2))
{
size2++;
arr2 = realloc(arr2, sizeof(char*) * size2);
arr2[size2 - 1] = strdup(buf);
}
for(int i = 0; i < size1; i++)
for(int j = 0; j < size2; j++)
{
if(strcmp(arr1[i], arr2[j]) == 0)
printf("match %s\n", arr1[i]);
}
return 0;
}
I tried to store strings in an array. But there is a mistake. My code is here:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <malloc.h>
const long long max_size = 2000; // max length of strings
const long long N = 40; // number of closest words that will be shown
const long long max_w = 50; // max length of vocabulary entries
int main(int argc, char **argv) {
FILE *f;
char st1[max_size];
char kelimeler[max_size];
char *kelimelerim[max_size]; //string array initialization here
char *bestw[N];
char file_name[max_size], st[100][max_size];
float dist, len, bestd[N], vec[max_size];
long long words, size, a, b, c, d, cn, bi[100];
char ch;
float *M;
char *vocab;
strcpy(file_name, argv[1]);
f = fopen(file_name, "rb");
if (f == NULL) {
printf("Input file not found\n");
return -1;
}
fscanf(f, "%lld", &words);
fscanf(f, "%lld", &size);
vocab = (char *)malloc((long long)words * max_w * sizeof(char));
for (a = 0; a < N; a++) bestw[a] = (char *)malloc(max_size * sizeof(char));
M = (float *)malloc((long long)words * (long long)size * sizeof(float));
if (M == NULL) {
printf("Cannot allocate memory");
return -1;
}
for (b = 0; b < words; b++) {
a = 0;
int sayac=0;
while (1) {
sayac++;
vocab[b * max_w + a] = fgetc(f);
if (feof(f) || (vocab[b * max_w + a] == ' ')) {
strcpy(kelimeler,&vocab[b * max_w + a-sayac+2]); //gets the string here
kelimelerim[b] = kelimeler; //and store it into string array here
printf("%s %lld\n",kelimelerim[b],b);
sayac=0;
break;
}
if ((a < max_w) && (vocab[b * max_w + a] != '\n'))
a++;
}
vocab[b * max_w + a] = 0;
for (a = 0; a < size; a++)
fread(&M[a + b * size], sizeof(float), 1, f);
len = 0;
for (a = 0; a < size; a++)
len += M[a + b * size] * M[a + b * size];
len = sqrt(len);
for (a = 0; a < size; a++)
M[a + b * size] /= len;
}
fclose(f);
int index;
for (index = 0; index < words; index ++){
printf("%s %d \n",kelimelerim[index ], index );
}
// here, the loop prints last string stored into array, for all indexes.
I deleted the unimportant rows. When I run the above code and print the kelimelerim array, the last string is printed for all indexes of the array. Where is my mistake? Could you help me, please.
You never initialize vocab, so the following has undefined behaviour:
vocab[b * max_w + a] = fgetc(f);
From that point on, all bets are off.
This
kelimelerim[b] = kelimeler;
does not copy any data, but only stores the address of kelimeler to kelimelerim[b]. If then looping over kelimelerim[b]'s elements, only references to kelimeler are found and as kelimeler gets re-used for each iteration, it contains the string read last, which then in turn is printed for each of element of kelimelerim[b].
Update:
To fix this either replace kelimelerim[b] by an array of "string" not just pointers to strings and do
strcpy(kelimelerim[b], kelimeler);
or dynamically create a real copy of kelimeler by doing:
kelimelerim[b] = strdup(kelimeler);
Be aware that for this latter case each call to strdup() allocates memory from the heap, which you shall free if not used anymore, by calling free() on each elelment of kelimelerim.
Also strdup() isn't Standard C but a POSIX extension. You might need to #define something to have it avaliable. See your implementation's documentaion on strdup() for details.
If strdup() is not available you might like to use this:
#include <stdlib.h> /* for malloc() */
#include <string.h> /* for strcpy() */
#include <errno.h> /* for errno */
char * strdup(const char * s)
{
char * p = NULL;
if (NULL == s)
{
errno = EINVAL;
}
else
{
p = malloc(strlen(s) + 1);
if (NULL == p)
{
errno = ENOMEM;
}
else
{
strcpy(p, s);
}
}
return p;
}
You are using char *vocab; as uninitialized pointer. This results in undefined behavior. You have to initialize this pointer before using it with a valid memory ( e.g. using malloc).
In Python, one can print XXXX using print "X"*4; Is there any easy equivalent in C?
C doesn't have much in the way of builtin/standard library, so you'd have to go through the process of allocating a new buffer and concatenating four strings to it, then freeing the buffer, it's simpler just to print "X" four times.
int i;
for (i=0; i<4; ++i) {
printf("X");
}
printf("\n");
You could write your own, though.
char* x(const char* s, unsigned int reps) {
size_t len = strlen(s);
char* buf = (char*)malloc(len*reps + 1);
while (reps--) {
memcpy(buf, s, len);
buf += len;
}
*buf = '\0';
return buf;
}
char* repeated = x("X", 4);
printf("%s\n", repeated);
free(repeated);
But as you can see, the result is almost as long.
Yes. Welcome to C:
int i;
for (i=0; i<4; i++)
printf("X");
Not really. In C you would need to use a loop.
No there is no standard library in C that can do that, but you can always implement easily with yourself. A simple implementation in C:
char * strmul(const char * src, size_t times) {
size_t s_len = strlen(src);
char * res = (char*)malloc(s_len * times + 1);
int i;
for(i = 0; i < times; i++) {
strcpy(res + s_len * i, src);
}
return res;
}
Improved version as suggested by #ikegami
char * strmul(const char * src, size_t times) {
size_t s_len = strlen(src);
char * res = (char*)malloc(s_len * times + 1);
int i;
for(i = 0; i < times; i++) {
memcpy(res + s_len * i, src);
}
res[s_len * times + 1] = '\0';
return res;
}