C - fit string on a fixed width - c

I would like to fit a string into multiple rows of a fixed width. I managed to separate the string into different rows so that their length will not pass the fixed width, but the problem is that some rows are not width (80) characters long, this is why I am trying to distribute the extra_space by adding spaces between words.
#include <stdio.h>
#include <string.h>
#include "stringdefault.h"
#include <conio.h>
#include <stdlib.h>
int main(){
int width = 80;
char s1[10000];
char substring[100] = " ";
char space = ' ';
gets(s1);
removeSpaces(s1);
char *base,*right_margin;
int extraSpace, numWords, numSpaces, incrementEachSpaceby, ind1, ind2, k;
int length;
length = string_length(s1);
base = s1;
for(int i = 0; i < width; i++)
{
printf("%d", i%10);
}
printf("\n");
while(*base)
{
if(length <= width)
{
puts(base); // display string
return(0); //and leave
}
right_margin = base+width;
while(!isspace(*right_margin))
{
right_margin--;
if( right_margin == base)
{
right_margin += width;
while(!isspace(*right_margin))
{
if( *right_margin == '\0')
break;
right_margin++;
}
}
}
*right_margin = '\0';
if(string_length(base) < width)
{
char *newStr = malloc(width);
extraSpace = width - string_length(base);
numWords = numberOfWords(base);
numSpaces = numWords - 1;
incrementEachSpaceby = extraSpace/numSpaces;
ind1 = 0;
ind2 = 0;
while (ind2 < width)
{
newStr[ind2] = base[ind1];
ind1++;
ind2++;
}
for(int i = 0; newStr[i]!='\0'; i++)
if((isspace(newStr[i])))
{
if(extraSpace > 0)
k = extraSpace;
else
k = 1;
while(k)
{
insert_substring(newStr, substring, i);
k--;
}
}
puts(newStr);
}
else
puts(base);
length -= right_margin-base+1; // +1 for the space
base = right_margin+1;
}
return 0;
}
stringdefault.h
int string_length(char s[])
{
int length = 0;
for(int i=0; s[i]!='\0'; i++)
length++;
return length;
}
char *substring(char *string, int position, int length)
{
char *pointer;
int c;
pointer = malloc(length+1);
if( pointer == NULL )
exit(EXIT_FAILURE);
for( c = 0 ; c < length ; c++ )
*(pointer+c) = *((string+position-1)+c);
*(pointer+c) = '\0';
return pointer;
}
void insert_substring(char *a, char *b, int position)
{
char *f, *e;
int length;
length = strlen(a);
f = substring(a, 1, position - 1 );
e = substring(a, position, length-position+1);
strcpy(a, "");
strcat(a, f);
free(f);
strcat(a, b);
strcat(a, e);
free(e);
}
char *removeSpaces(char *str)
{
int ip_ind = 0;
char *ptr;
while(*(str + ip_ind))
{
if ( (*(str + ip_ind) == *(str + ip_ind + 1)) && (*(str + ip_ind)==' ') )
{
ptr = str + ip_ind+1;
do{
*(ptr-1) = *ptr;
}while(*ptr++ != '\0');
}
else
ip_ind++;
}
*(str + ip_ind) = '\0';
return str;
}
The output that I get without the while loop inside the if statement
It seems that the newStr set of characters, contains spaces before it's first character.

Related

Inserting a character into a char array

I have a char array containing a number.
char number[] = "12000000"
I need to have a function to insert a divider in every 3 digits. Like:
char result[] = "12,000,000"
My function accepts the number as a char pointer and it needs to return result as a char pointer too.
char* insert_divider(char* number) {
some magic;
return result;
}
I have no idea of working with pointers. Thanks.
Here you have a function that adds char c every num characters starting from the end. You need to make sure that the string buffer is long enough to accommodate the amended string.
char *addEvery(char *str, char c, unsigned num)
{
char *end = str;
if(str && *str && num)
{
size_t count = 1;
while(*(end)) end++;
while(end != str)
{
end--;
count++;
if(!(count % (num + 1)) && str != end)
{
memmove(end + 1, end, count);
*end = c;
count++;
}
}
}
return str;
}
int main(void)
{
char str[100] = "120000000000";
printf("%s", addEvery(str,',',3));
}
I came up with this piece of code:
char *result;
result = (char*) malloc(15);
int len= strlen(input);
uint8_t cursor= 0;
for(int i = 0; i < len; i++) {
if ((len- i) > 0 && (len- i) % 3 == 0) {
result[i + cursor] = ',';
cursor++;
}
result[i + cursor] = input[i];
}
result[len+ cursor] = '\0';
Thanks everyone for help and advice.
Here is another way to do it:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* insert_divider(char* number, size_t length) {
int j = length + length/3; // every 3 digits a ',' will be inserted
char *out = (char*)malloc(j + 1);
out[j--] = '\0';
for (int i = length - 1, k = 1; i >= 0; i--, k++) {
out[j--] = number[i];
if ((k%3) == 0) {
out[j--] = ',';
}
}
return out;
}
int main(){
char number[] = "12000000";
char *outNumber = insert_divider(number, strlen(number));
printf("%s", outNumber);
free(outNumber);
return 0;
}

how to write a function char* in c that returns words sorted in order of their length?

Write a function that takes a string as a parameter and returns its words sorted in order of their length first and then in alphabetical order on line separated by '^'
here is examples of output
There will be only spaces, tabs and alphanumeric caracters in strings.
You'll have only one space between same size words and ^ otherwise.
A word is a section of string delimited by spaces/tabs or the start/end of the string. If a word has a single letter, it must be capitalized.
A letter is a character in the set [a-zA-Z]
here is my code, but it returns nothing I think issue in last function....
#include <unistd.h>
#include <stdlib.h>
int is_upper(char c)
{
return c >= 'A' && c <= 'Z';
}
int my_lower(char c)
{
if (is_upper(c))
return c + 32;
return c;
}
int my_strlen(char *s)
{
int i = 0;
for (; s[i]; i++)
;
return i;
}
int my_is(char c)
{
return c == ' ' || c == '\t';
}
char *my_strsub(char *s, int start, int end)
{
char *res = malloc(end - start);
int i = 0;
while (start < end)
res[i++] = s[start++];
res[i] = 0;
return res;
}
int cmp_alpha(char *a, char *b)
{
while (*a && *b && *a == *b)
{
a++;
b++;
}
return my_lower(*a) <= my_lower(*b);
}
int cmp_len(char *a, char *b)
{
return my_strlen(a) <= my_strlen(b);
}
void my_sort(char *arr[], int n, int(*cmp)(char*, char*))
{
char *tmp;
for (int i = 0; i < n; i++)
for (int j = 0; j < n - 1; j++)
{
if ((*cmp)(arr[j], arr[j + 1]) == 0)
{
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
char* long(char *s)
{
int start = 0, idx = 0;
char *words[my_strlen(s) / 2 + 1];
for (int i = 0; s[i]; i++)
{
if (!my_is(s[i]) && i > 0 && my_is(s[i - 1]))
start = i;
if (my_is(s[i]) && i > 0 && !my_is(s[i - 1]))
words[idx++] = my_strsub(s, start, i);
if (!s[i + 1] && !my_is(s[i]))
words[idx++] = my_strsub(s, start, i + 1);
}
my_sort(words, idx, &cmp_alpha);
my_sort(words, idx, &cmp_len);
char* res = malloc(100);
int pushed=0;
for (int i = 0; i < idx - 1; i++)
{
res[pushed]=*words[i];
if (my_strlen(&res[pushed]) < my_strlen(&res[pushed + 1]))
{
res[pushed]=res[94];
}
else
{
res[pushed]=res[32];
}
pushed++;
}
res[pushed]='\0';
return res;
}
int main()
{
long("Never take a gamble you are not prepared to lose");
return 0;
}
Apart from the off-by-one allocation error in my_strsub, separating and sorting the words seems to work well. Only then you confuse the result character array with a character pointer array, e. g. with res[pushed]=*words[i] you write only the first character of a word to the result. The last for loop of ord_alphlong could rather be:
if (idx)
for (int i = 0; ; )
{
char *word = words[i];
int lng = my_strlen(word);
if (100 < pushed+lng+1) exit(1); // too long
for (int i = 0; i < lng; ) res[pushed++] = word[i++];
if (++i == idx) break; // last word
res[pushed++] = lng < my_strlen(words[i]) ? '^' // other size
: ' '; // same size
}
Of course in order to see the result of the function, you'd have to output it somehow.

can't able to return pointer value of function to main

link of program question https://www.hackerrank.com/challenges/cut-the-sticks/problem
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* readline();
char** split_string(char*);
int* cutTheSticks(int arr_count, int* arr, int* result_count) {
int c=arr_count,min;
int result[c];
for (int k=0;k<arr_count;k++){
min = *arr;
for (int i = 0; i < c; i++) {
if (*(arr + i) < min)
min = *(arr + i);
}
int count=0;
for (int i=0; i < c; i++) {
if(min==*(arr+i))count++;
}
for (int i=0; i < c; i++) {
*(arr+i)=*(arr+i)-min;
}
int temp=0;
for(int i=0;i<c;i++){
for(int x=i;x<c;x++){
if(*(arr+i)<*(arr+x)){
temp=*(arr+i);
*(arr+i)=*(arr+x);
*(arr+x)=temp;
}
}
}
result[k]= c;
*(result_count)=*(result_count)+1;
c = c - count;
if(c==0)break;
}
return result;
}
int main()
{
FILE* fptr = fopen(getenv("OUTPUT_PATH"), "w");
char* n_endptr;
char* n_str = readline();
int n = strtol(n_str, &n_endptr, 10);
if (n_endptr == n_str || *n_endptr != '\0') { exit(EXIT_FAILURE); }
char** arr_temp = split_string(readline());
int* arr = malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
char* arr_item_endptr;
char* arr_item_str = *(arr_temp + i);
int arr_item = strtol(arr_item_str, &arr_item_endptr, 10);
if (arr_item_endptr == arr_item_str || *arr_item_endptr != '\0') {
exit(EXIT_FAILURE); }
*(arr + i) = arr_item;
}
int arr_count = n;
int result_count;
int* result = cutTheSticks(arr_count, arr, &result_count);
for (int i = 0; i < result_count; i++) {
fprintf(fptr, "%d", *(result + i));
if (i != result_count - 1) {
fprintf(fptr, "\n");
}
}
fprintf(fptr, "\n");
fclose(fptr);
return 0;
}
char* readline() {
size_t alloc_length = 1024;
size_t data_length = 0;
char* data = malloc(alloc_length);
while (true) {
char* cursor = data + data_length;
char* line = fgets(cursor, alloc_length - data_length, stdin);
if (!line) { break; }
data_length += strlen(cursor);
if (data_length < alloc_length - 1 || data[data_length - 1] == '\n') {
break; }
size_t new_length = alloc_length << 1;
data = realloc(data, new_length);
if (!data) { break; }
alloc_length = new_length;
}
if (data[data_length - 1] == '\n') {
data[data_length - 1] = '\0';
}
data = realloc(data, data_length);
return data;
}
char** split_string(char* str) {
char** splits = NULL;
char* token = strtok(str, " ");
int spaces = 0;
while (token) {
splits = realloc(splits, sizeof(char*) * ++spaces);
if (!splits) {
return splits;
}
splits[spaces - 1] = token;
token = strtok(NULL, " ");
}
return splits;
}
This above code is my full code from harkerrank, below is main fuction.
i can't able to return my pointer value from cutTheStricks to main function.
// Please store the size of the integer array to be returned in
result_count
pointer. For example,
// int a[3] = {1, 2, 3};
//
// *result_count = 3;
//
// return a;
int* cutTheSticks(int arr_count, int* arr, int* result_count) {
int c=arr_count,min;
int result[c];
for (int k=0;k<arr_count;k++){
min = *arr;
for (int i = 0; i < c; i++) {
if (*(arr + i) < min)
min = *(arr + i);
}
int count=0;
for (int i=0; i < c; i++) {
if(min==*(arr+i))count++;
}
for (int i=0; i < c; i++) {
*(arr+i)=*(arr+i)-min;
}
int temp=0;
for(int i=0;i<c;i++){
for(int x=i;x<c;x++){
if(*(arr+i)<*(arr+x)){
temp=*(arr+i);
*(arr+i)=*(arr+x);
*(arr+x)=temp;
}
}
}
result[k]= c;
*(result_count)=*(result_count)+1;
c = c - count;
if(c==0)break;
}
return result;
}
I am not getting any output but my logic is correct.
I know there is there is something missing therefore i can't able to return my output;
I can't figure out which pointer value(*result or *result_count ) is not passing
or what is happening i can't able to figure out.
You are returning the address of a local array whose life time ends with the function, change
int result[c];
to
int *result = malloc(sizeof(*result) * c);
You are also using the address of an uninitialized value here:
*(result_count)=*(result_count)+1;
change
int result_count;
to
int result_count = 0;

C histogram of words printing problems

I have this code, what i want it to do is print the string that represents the word, and print the number of times it occurred in the file, instead it outprints something liek this: (a load of blank space) and then this number -1076720020, which i have no idea where it came from, how would i go about fixing this?
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
struct podatki {
char beseda[1000];
int frekvenca;
};
void zamenjaj(char *str1, char *str2) {
char *beseda2 = (char *)malloc((strlen(str1) + 1) * sizeof(char));
strcpy(beseda2, str1);
strcpy(str1, str2);
strcpy(str2, beseda2);
free(beseda2);
}
int posodobi(struct podatki s[], const char unit[], int count) {
int i =0;
for (i = 0; i < count; i++) {
if (strcmp(s[i].beseda, unit) == 0) {
s[i].frekvenca++;
return count;
}
}
strcpy(s[count].beseda, unit);
s[count].frekvenca++;
return (count + 1);
}
int main() {
int stBes;
scanf("%d", &stBes);
//zacetne deklaracije
struct podatki s[1000];
char string[1000], unit[2000], c;
int i = 0;
int frekvenca = 0;
int j = 0;
int count = 0;
int num = 0;
//branje
for (i = 0; i < 1000; i++) {
s[i].frekvenca = 0;
}
i = 0;
do {
fflush(stdin);
c = getchar();
string[i++] = c;
} while (c != '\n');
//pretvori v majhne crke
char *p;
for (p = string; *p != '\0'; ++p) {
*p = tolower(*p);
}
string[i - 1] = '\0';
for (i = 0; i < strlen(string); i++) {
while (i < strlen(string) && string[i] != ' ' && !ispunct(string[i])) {
unit[j++] = string[i++];
}
if (j != 0) {
unit[j] = '\0';
count = posodobi(s, unit, count);
j = 0;
}
}
int a;
for (i = 0; i < count; ++i) {
for (j = i + 1; j < count; ++j) {
if (s[i].frekvenca < s[j].frekvenca) {
a = s[i].frekvenca;
s[i].frekvenca = s[j].frekvenca;
s[j].frekvenca = a;
zamenjaj(s[i].beseda, s[j].beseda);
}
}
}
for (i = 0; i < count; i++) {
for (j = 1; j < count; j++) {
if (s[i].frekvenca == s[j].frekvenca){
if (strcmp(s[i].beseda, s[j].beseda) < 0) {
a = s[i].frekvenca;
s[i].frekvenca = s[j].frekvenca;
s[j].frekvenca = a;
zamenjaj(s[i].beseda, s[j].beseda);
}
}
}
}
//printanje
for (i = 0; i < stBes; i++) {
printf("%s\t %d\n", s[i].beseda, s[i].beseda);
if (s[i].frekvenca > 1) {
num++;
}
}
return 0;
}
The problem is that you convert the string to lower case before nul terminating it.
Here
i = 0;
do {
fflush(stdin);
c = getchar();
string[i++] = c;
} while (c != '\n');
/* Goes here <---------------------+ */
/* | */
//pretvori v majhne crke | */
char *p; /* | */
for (p = string; *p != '\0'; ++p) {/* | */
*p = tolower(*p);/* | */
} /* | */
/* | */
string[i - 1] = '\0'; /* ---------------------+ */
You should also remove the fflush(stdin) and instead use getchar() to fetch the white space characters ignored by the previous scanf(), and please use scanf() correctly and check it's returned value.

Align text by 16 characters

I'm trying to create a function to center text on a 16*8 screen (8 lines and 16 letters in one line), the part with a length < 16 is working fine but when i have more than one line i can't find how to solve the problem, here is my code :
char* align_text(char* text)
int i=0, j=0, k;
int modulo, diff;
int size = strlen(text);
char space[16];
char tmp[16];
char tmp2[16];
char* tmp3;
char median[150];
char* final;
if(size==16)
return text;
else if(size<16)
{
diff = 16 - size;
modulo = diff%2;
if(modulo==0)
{
for(j=0;j<diff/2;j++)
space[j] = ' ';
space[j] = '\0';
strcat(median, space);
strcat(median, text);
strcat(median, space);
}
else
{
for(j=0;j<(int)(diff/2);j++)
space[j] = ' ';
space[j] = '\0';
strcat(median, space);
strcat(median, text);
space[j] = ' ';
space[j+1] = '\0';
strcat(median, space);
}
final = (char*)malloc(strlen(median)*sizeof(char));
strcpy(final, median);
return final;
}
else
{
while(text[i] != '\0')
{
if(text[i] == ' ')
{
if(strlen(tmp2)>16 && strlen(tmp)<=16)
{
tmp3 = align_text(tmp);
if(strlen(median) == 0)
strcpy(median, tmp3);
else
strcat(median, tmp3);
free(tmp3);
j=0;
tmp2[0] = '\0';
i = k;
}
strcpy(tmp, tmp2);
tmp2[j++]=text[i++];
tmp2[j]='\0';
k = i;
}
else
{
tmp2[j++]=text[i++];
tmp2[j]='\0';
}
}
if(strlen(tmp2)>16 && strlen(tmp)<=16)
{
tmp3 = align_text(tmp);
if(strlen(median) == 0)
strcpy(median, tmp3);
else
strcat(median, tmp3);
free(tmp3);
}
j=0;
tmp2[0] = '\0';
i = k;
while(text[i] != '\0' )
{
tmp2[j] = text[i];
tmp3 = align_text(tmp2);
strcat(median, tmp3);
free(tmp3);
}
final = (char*)malloc(strlen(median)*sizeof(char));
strcpy(final, median);
return final;
}
}
I believe this works after some testing. I won't claim a high "level of elegance", but it's clean and functional.
The approach here is that it takes the input as one null-terminated string of text. A copy of the input string is made since strtok is used to pull out each non-blank string, and strtok modifies the string. The output is managed by building it a single line at a time (in the line buffer), then centering that line when it's deemed full as it is copied to the output. The function, format_line, does the copy of a line to the output that must be centered. If you want left or right justification, that could be done just by modifying format_line. Because strtok is used to pull "tokens" from the input with blank delimiters, a single blank is re-inserted between each word on output.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static const int cols = 16;
static const int rows = 8;
void format_line(char *out_text, char line[], int col)
{
int nspaces;
// Back off the trailing space if there is one
//
if ( line[col-1] == ' ' )
col -= 1;
line[col] = '\0';
// Center the text to the output buffer
//
nspaces = cols - col;
memset(out_text, ' ', nspaces/2);
out_text += nspaces/2;
*out_text = '\0';
strcat(out_text, line);
out_text += strlen(line);
memset(out_text, ' ', nspaces - nspaces/2);
out_text += nspaces - nspaces/2;
*out_text = '\0';
}
char *align_text(char *text)
{
int col, row;
char *fit_text, *ret_text;
char *np;
char line[cols+1];
char *ptext;
// Copy the input text so we don't destroy the original w/strtok
ptext = malloc(strlen(text) + 1);
strcpy(ptext, text);
// Create the buffer for the output text
ret_text = fit_text = malloc(cols * rows + 1);
// Initialize the working line/row
line[col = 0] = '\0';
row = 0;
// Parse each string in the input text with space as delimeter
//
for (np = strtok(ptext, " "); (np != NULL) && (row < rows); np = strtok(NULL, " "))
{
// If the next string fits on the current line
// then we'll put it there
//
if ((col + strlen(np)) < cols)
{
col += strlen(np);
strcat(line, np);
// Append a space delimeter if there's room
//
if (col < cols)
line[col++] = ' ';
line[col] = '\0';
// If we hit the end of the line, copy it to the output text
// buffer and reset the to the beginning of the working line
//
if (col == cols)
{
memcpy(fit_text, line, col);
fit_text += cols;
line[col = 0] = '\0';
row += 1;
}
}
else // The next string doesn't fit on the current line
{
// If there is text on the current line, then
// space pad it, append it to the output (centered), and reset working line
//
if ( col > 0 )
{
format_line(fit_text, line, col);
fit_text += cols;
}
// If the current string is longer than a line, then
// copy over the long chunks
//
while ( strlen(np) >= cols )
{
memcpy(fit_text, np, cols);
fit_text += cols;
np += cols;
row += 1;
}
// Copy the rest of the current string to the fresh working line
//
strcpy(line, np);
col = strlen(np);
line[col++] = ' ';
line[col] = '\0';
row += 1;
}
}
// Copy over and center the last one
//
if ( (col > 0) && (row < rows) )
{
format_line(fit_text, line, col);
fit_text += cols;
}
*fit_text = '\0';
return ret_text;
}
int main(int argc, char *argv[])
{
if ( argc > 1 )
{
printf("%s\n", align_text(argv[1]));
printf("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF\n");
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum { left, center, right } position;
int pos_calc(int width, int max_width, position pos){
int d;
if((d=max_width - width)< 0)
return -1;
switch(pos){
case left: return 0;
case right: return d;
case center: return d/2;
}
}
char *puton(char *buff, int width, position pos, const char *data){
int len = strlen(data);
int offset = pos_calc(len, width, pos);
memset(buff, ' ', width);
buff[width]='\0';
memcpy(buff + offset, data, len);
return buff;
}
char* join(char c, size_t arrsize, const char *arr[]){
size_t i, total, len[arrsize];
char *buff, *ret;
for(total=i=0;i<arrsize;++i)
total+=(len[i]=strlen(arr[i]));
if(NULL==(ret=buff=malloc((total + arrsize)*sizeof(char))))
return NULL;
for(i=0;i<arrsize;++i){
memcpy(buff, arr[i], len[i]);
buff+=len[i];
*buff++=c;
}
*--buff='\0';
return ret;
}
char *align_text(const char *str){
static const int row = 8;
static const int col = 16;
static const char *delimiter = " \t\n";
char *text = strdup(str);
char *words[col], *p, *cat;
int wc, total_len, r;
char *buff = malloc(row * col * sizeof(char) + 1);
//memset(buff, ' ', row*col);
//buff[row*col] = '\0';
for(r=total_len=wc=0, p=strtok(text, delimiter); p ; p = strtok(NULL, delimiter)){
int len = strlen(p);
//if(len > col){...}
words[wc++] = p;
total_len += len;
if(total_len + wc - 1 > col){
cat = join(' ', wc - 1, words);
puton(buff + col * r++, col, center, cat);
//if(r >= row){...}
free(cat);
words[0] = words[wc-1];
wc = 1;
total_len = len;
}
}
cat = join(' ', wc, words);
puton(buff + col * r++, col, center, cat);
free(cat);
free(text);
return buff;
}
void print(const char *text, int width){
int i;
for(i=1;*text;++i){
putchar(*text++);
if(i % width == 0)
putchar('\n');
}
}
int main(){
char *text = align_text("Hello how are you");
//printf("%s", text);
print(text, 16);
free(text);
return 0;
}

Resources