It is possible to use realloc on char** in one line? - c

I really do not know if it is the right title for my question, but I will try to explain my problem :
I'm working on a program which search all string permutes and saves those string in a char** array.
Everything looks fine, but the program takes too much time too finish and this happens because of realloc calls which are too many and takes too much time. I am talking about 13700 calls here:
for ( size_t i = 0; i < SIZE_2D; i++ ){ // SIZE_2D == 13700
multi[i] = calloc(LINELENGTH, sizeof(char));
}
It is possible to call realloc on char** in a single call ?
Like the example here :
#include <stdio.h>
#include <stdlib.h>
int main(void){
int *arr;
unsigned int row = 5, col = 10;
arr = malloc(sizeof *arr * row * col);
if(arr == NULL){
printf("Error, malloc\n");
exit(3);
}
free(arr);
}
This is the working code:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_2D 13700
#define LINELENGTH 8
void swap (char *x, char *y);
void permute(char *arr, char *ptr, size_t i, size_t n);
int compare(const void *a, const void *b);
void resizeBuffer ( char **arr, size_t length );
void resultFound( char **multi, char *buffer, size_t length );
//char multi[20240][50] = {0};
int main(void){
char str[] = "abcdefg";
char *arr = calloc(100000, sizeof(char));
char *multi[14000];
//char **multi = calloc(10240, sizeof(char*));
for ( size_t i = 0; i < SIZE_2D; i++ ){
multi[i] = calloc(LINELENGTH, sizeof(char));
}
permute( arr, str, 0, strlen( str ) );
resizeBuffer ( &arr, strlen( arr ) + 1 );
resultFound(multi, arr, strlen( arr ) );
free( arr );
for ( size_t i = 0; i < SIZE_2D; i++ ){
free(multi[i]);
}
}
void resultFound( char **multi, char *buffer, size_t length ){
printf("ARR LENGTH = %zu\n", length);
size_t i = 0;
char *ptr = buffer;
size_t p = 0;
size_t a = 0;
char *tmp = calloc(length + 1, sizeof(char));
size_t count = 0;
while ( i < length ){
if ( ptr[i] == '\n' ){
if ( count != 0){
//printf("Line Found! <-> Line Length = %zu <-> TMP = %s\n",count, tmp);
strcpy(multi[a++], tmp);
memset(tmp, 0, length);
count = 0;
p = 0;
}else{
//printf("Empty Line Found, Ignore it\n\n");
}
}else{
count++;
tmp[p++] = ptr[i];
}
i++;
}
for (size_t l = 0 ; l < a ; l++ ){
printf("Multi[%zu]\t= %s\n",l , multi[l]);
}
free(tmp);
}
void swap (char *x, char *y){
char temp;
temp = *x;
*x = *y;
*y = temp;
}
void permute(char *arr, char *ptr, size_t i, size_t n){
size_t j;
static char prev[80] = "";
if (i == n){
if (strcmp(prev, ptr)) {
strcat (arr, ptr);
strcat (arr, "\n");
strcpy(prev, ptr);
}
}else{
for (j = i; j <= n; j++)
{
swap( (ptr + i), (ptr + j) );
permute(arr, ptr, i+1, n);
swap( (ptr + i), (ptr + j) );
}
}
}
void resizeBuffer ( char **buffer, size_t length ){
*buffer = realloc(*buffer, (length)* sizeof(char) );
}

Related

C string manipulation for removing xx:xx:xx:xx:xx:xx

I have a problem removing a substring xx:xx:xx:xx:xx:xx from one main string. Here is the background info for the problem:
in a function void funA():
void funA(const char* sth){
if (sth == THINGA){
// do A;
}
else if (sth == THINGB){
// do B;
}
eles{
// do C;
}
log_status("current status: - %s", sth);
}
sth is a string contains a substring in the format of xx:xx:xx:xx:xx:xx where x is either a number or a letter. The substring has a space in front of it but might not have one at the end of the string. I need to obfuscate this substring with a *. Since only the substring has :, I made a helper function to locate the first : and the last : and remove 2 characters before it. Delete the last 2 characters and append a *. I think this way is most the best solution. So I'm wondering if there are any more efficient design of a helper function aka a helper function has shorter runtime and uses less memory. Since the substring xx:xx:xx:xx:xx:xx has a very distinguish format, the only easier way I can think of is to do a string match to find the substring and then replace it with a *. I'm open to other more innovative way though.
#ifndef PARSER_STACK_H_INCLUDED
#define PARSER_STACK_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PATTERN_LEN 18
typedef struct{
unsigned int start;
unsigned int finish;
}index;
void remove_str_pattern(char *original, char *extract, unsigned int start, unsigned int finish);
void splitter(char *x, index *index_SF);
unsigned int count_points(const char *x);
void obscure(char *str, index index_SF);
char* return_obscure_string(char *str);
char* return_pattern(char *str);
char* return_pattern(char *str){
index index_SF = {0,0};
char *str_export = calloc(PATTERN_LEN, sizeof(char));
char *tmp = calloc(sizeof(str)/sizeof(char), sizeof(char));
strcpy(tmp, str);
splitter(str, &index_SF);
obscure(tmp, index_SF);
remove_str_pattern(str, str_export, index_SF.start, index_SF.finish);
return str_export;
}
char* return_obscure_string(char *str){
index index_SF = {0,0};
char *str_export = calloc(PATTERN_LEN, sizeof(char));
char *tmp = calloc(sizeof(str)/sizeof(char), sizeof(char));
strcpy(tmp, str);
splitter(str, &index_SF);
obscure(tmp, index_SF);
remove_str_pattern(str, str_export, index_SF.start, index_SF.finish);
return tmp;
}
void obscure(char *str, index index_SF){
for(unsigned int i = index_SF.start; i < index_SF.finish+1; ++i){
if(str[i] != ':'){
str[i] = '*';
}
}
}
void splitter(char *x, index *index_SF){
for(unsigned int i = 0, tmp = 0; i < strlen(x); ++i){
if(x[i] == ':'){
++tmp;
if(tmp == 1){
index_SF->start = i-2;
}else{
if(tmp == 5){
index_SF->finish = i+2;
}
}
}
}
}
unsigned int count_points(const char *x){
int c = 1;
for(unsigned int i = 0; i < strlen(x); ++i){
if((x[i] == ':' && x[i+2] == ':') || (x[i] == ':' && x[i-2] == ':')){
++c;
}
}
return c;
}
void remove_str_pattern(char *original, char *extract, unsigned int start, unsigned int finish){
for(unsigned int i = start, j = 0; i < finish+1; ++i, ++j){
extract[j] = original[i];
}
}
#endif // PARSER_STACK_H_INCLUDED
That is my personal header file for your request, create header file with this code and try it ! :D
Two "main" functions of this file are.
1. char* return_obscure_string(char *str);
For return original string with obscured sub-string..
2. char* return_pattern(char *str);
For return pattern value from a string..
Good Luck Man !
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PATTERN_LEN 18
typedef struct{
unsigned int start;
unsigned int finish;
}index;
void remove_str_pattern(char *original, char *extract, unsigned int start, unsigned int finish);
void splitter(char *x, index *index_SF);
unsigned int count_points(const char *x);
void obscure(char *str, index index_SF);
void main(){
index index_SF = {0,0};
char *origin = "this is first try for me in stack aa:bb:22:44:55:66 overflow...";
char *str_export = calloc(PATTERN_LEN, sizeof(char));
char *tmp = calloc(sizeof(origin)/sizeof(char), sizeof(char));
strcpy(tmp, origin);
splitter(origin, &index_SF);
obscure(tmp, index_SF);
remove_str_pattern(origin, str_export, index_SF.start, index_SF.finish);
printf("start index: %u finish index: %u\n", index_SF.start, index_SF.finish);
printf("obscured string %s\n", tmp);
printf("original str: %s\n", origin);
printf("pattern: %s\n", str_export);
}
void obscure(char *str, index index_SF){
for(unsigned int i = index_SF.start; i < index_SF.finish+1; ++i){
if(str[i] != ':'){
str[i] = '*';
}
}
}
void splitter(char *x, index *index_SF){
for(unsigned int i = 0, tmp = 0; i < strlen(x); ++i){
if(x[i] == ':'){
++tmp;
if(tmp == 1){
index_SF->start = i-2;
}else{
if(tmp == 5){
index_SF->finish = i+2;
}
}
}
}
}
unsigned int count_points(const char *x){
int count = 1;
for(unsigned int i = 0; i < strlen(x); ++i){
if((x[i] == ':' && x[i+2] == ':') || (x[i] == ':' && x[i-2] == ':')){
++count;
}
}
return count;
}
void remove_str_pattern(char *original, char *extract, unsigned int start, unsigned int finish){
for(unsigned int i = start, j = 0; i < finish+1; ++i, ++j){
extract[j] = original[i];
}
}

How to dynamic malloc memory in function in c?

I want to call a function like this:
char* Seg(char* input, char **segs, int* tags)
in fact input is the real input, segs tags is the return, and now return is the error message.
my program like this:
#include <stdio.h>
char* Seg(char* input, char **segs, int* tags) {
// dynamic malloc the memory here
int count = strlen(input); // this count is according to input
for (int i = 0; i < count; i++) {
segs[i] = "abc";
}
for (int i = 0; i < count; i++) {
tags[i] = i;
}
return NULL;
}
int main(int argc, char *argv[])
{
char** segs = NULL;
int* tags = NULL;
Seg("input", segs, tags);
return 0;
}
I am asking how can I return the value in segs and tags?
Edit
Now I change code to this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* input is input params, segs and tags is results
* return: error msg
*/
int Seg(char* input, char ***segs, int** tags) {
int n = strlen(input);
int *tags_ = malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
tags_[i] = i;
}
tags = &tags_;
char **segs_ = malloc(sizeof(char *) * n);
for (int i = 0; i < n; i++) {
segs_[i] = "haha";
}
segs = &segs_;
return n;
}
int main(int argc, char *argv[])
{
char** segs = NULL;
int* tags = NULL;
int n = Seg("hahahahah", &segs, &tags);
printf("%p", tags);
free(segs);
free(tags);
return 0;
}
Why tags is still nil?
If I have understood you correctly then you need something like the following.
I used sentinel values for the both dynamically allocated arrays. You can use your own approach instead of using sentinel values.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * Seg( const char *input, char ***segs, int **tags )
{
// dynamic malloc the memory here
size_t count = strlen( input ); // this count is according to input
*segs = malloc((count + 1) * sizeof(char *));
*tags = malloc((count + 1) * sizeof(int));
for ( size_t i = 0; i < count; i++ )
{
( *segs )[i] = "abc";
}
(*segs)[count] = NULL;
for ( size_t i = 0; i < count; i++ )
{
( *tags )[i] = ( int )i;
}
(*tags)[count] = -1;
return NULL;
}
int main( void )
{
char **segs = NULL;
int *tags = NULL;
Seg( "input", &segs, &tags );
for (char **p = segs; *p; ++p)
{
printf( "%s ", *p );
}
putchar('\n');
for (int *p = tags; *p != -1; ++p)
{
printf("%d ", *p);
}
putchar('\n');
free(segs);
free(tags);
return 0;
}
The program output is
abc abc abc abc abc
0 1 2 3 4
After you updated your post then the function can look also the following way
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t Seg( const char *input, char ***segs, int **tags )
{
// dynamic malloc the memory here
size_t count = strlen( input ); // this count is according to input
*segs = malloc(count * sizeof(char *));
*tags = malloc(count * sizeof(int));
for ( size_t i = 0; i < count; i++ )
{
( *segs )[i] = "abc";
}
for ( size_t i = 0; i < count; i++ )
{
( *tags )[i] = ( int )i;
}
return count;
}
int main( void )
{
char **segs = NULL;
int *tags = NULL;
size_t n = Seg( "input", &segs, &tags );
for (size_t i = 0; i < n; i++)
{
printf( "%s ", segs[i] );
}
putchar('\n');
for (size_t i = 0; i < n; i++)
{
printf("%d ", tags[i]);
}
putchar('\n');
free(segs);
free(tags);
return 0;
}
You can also add code to the function that checks whether the memory was allocated successfully.
As for your additional question then such a code like for example this
int *tags_ = malloc(n * sizeof(int));
tags = &tags_;
changes local variable tags of the type int ** (function parameters are function local variables) instead of changing the original pointer tags of the type int * passed to the function by reference as an argument.

Function that return characters from string which occurrences is user definied

I really hitted the wall with this type of function. I need to make a function that returns characters from string.
user can enter any number and I need to find char in string where total number of occurrences is number that user specified.
Does someone knows how can it be done in C language?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int cmp(const void *a, const void *b){
unsigned char ac = *(unsigned char *)a;
unsigned char bc = *(unsigned char *)b;
return ac < bc ? -1 : ac > bc;
}
char *func(const char *str, size_t n){
size_t len = strlen(str);
char *dup = malloc(len + 1);
char temp[len + 1];//[256]
strcpy(dup, str);
qsort(dup, len, sizeof(*dup), cmp);
char *p = dup;
size_t i = 0;
while(*p){
char aChar[] = {*p, 0};
len = strspn(p, aChar);
if(len == n){
temp[i++] = *p;
}
p += len;
}
temp[i] = 0;
strcpy(dup, temp);
return dup;
}
int main(void){
char *occurs = func("111abcddaaa", 1);
for(char *p = occurs; *p; ++p){
printf("%c\n", *p);
}
free(occurs);
return 0;
}

how to store o/p into a buffer,and then from buffer to file

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<stdbool.h>
int compare (const void *a, const void * b){
return ( *(char *)a - *(char *)b ); }
// A utility function two swap two characters a and b
void swap (char* a, char* b)
{
char t = *a;
*a = *b;
*b = t; }
int findCeil (char str[], char first, int l, int h)
{
// initialize index of ceiling element
int ceilIndex = l;
int i;
// Now iterate through rest of the elements and find
// the smallest character greater than 'first'
for (i = l+1; i <= h; i++)
if (str[i] > first && str[i] < str[ceilIndex])
ceilIndex = i;
return ceilIndex;
}
// Print all permutations of str in sorted order
void sortedPermutations ( char str[] )
{
FILE *fp;
fp = fopen("out.txt","w+");
char buffer[100];
memset(buffer,'\0',100);
// Get size of string
int size = strlen(str);
// Sort the string in increasing order
qsort( str, size, sizeof( str[0] ), compare );
// Print permutations one by one
bool isFinished = false;
while ( ! isFinished )
{
// print this permutation
setvbuf(str, buffer, _IONBF, 1024);
printf ("%s \n", str);
fprintf(fp,"%s\n",buffer);
// Find the rightmost character which is smaller than its next
// character. Let us call it 'first char'
int i;
for ( i = size - 2; i >= 0; --i )
if (str[i] < str[i+1])
break;
// If there is no such chracter, all are sorted in decreasing order,
// means we just printed the last permutation and we are done.
if ( i == -1 )
isFinished = true;
else
{
// Find the ceil of 'first char' in right of first character.
// Ceil of a character is the smallest character greater than it
int ceilIndex = findCeil( str, str[i], i + 1, size - 1 );
// Swap first and second characters
swap( &str[i], &str[ceilIndex] );
// Sort the string on right of 'first char'
qsort( str + i + 1, size - i - 1, sizeof(str[0]), compare );
}
fclose(fp);
}
}
int main()
{
char str[] = "ABCD";
sortedPermutations( str );
return 0;
}
Hi ,I am trying jumble solver .I want to store the result of permutation to a buffer and then from buffer to some file,so that I can compare it with dictionary. getting errors for setvbuf.
My C is very rusty,not able to get the desired results.
there are plenty of errors. First you use setvbuf with wrong arguments and do that in cycle. Then you fprintf buffer value instead of str. And also close file in cycle.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare (const void *a, const void * b) {
return ( *(char *)a - *(char *)b );
}
void swap (char* a, char* b) {
char t = *a;
*a = *b;
*b = t;
}
int findCeil (const char str[], char first, int l, int h) {
int ceilIndex = l;
int i;
for (i = l+1; i <= h; i++) {
if (str[i] > first && str[i] < str[ceilIndex]) {
ceilIndex = i;
}
}
return ceilIndex;
}
void sortedPermutations ( char str[] ) {
FILE *fp;
char buffer[1024];
int size = strlen(str);
int isFinished = 0;
fp = fopen("out.txt","w+");
memset(buffer, 0, 100);
qsort( str, size, sizeof( str[0] ), compare );
setvbuf(fp, buffer, _IOFBF, 1024);
while ( !isFinished ) {
int i;
printf("%s \n", str);
fprintf(fp, "%s\n", str);
for ( i = size - 2; i >= 0; --i )
if (str[i] < str[i+1]) {
break;
}
if ( i == -1 ) {
isFinished = 1;
} else {
int ceilIndex = findCeil( str, str[i], i + 1, size - 1 );
swap( &str[i], &str[ceilIndex] );
qsort( str + i + 1, size - i - 1, sizeof(str[0]), compare );
}
}
fclose(fp);
}
int main() {
char str[] = "ABCD";
sortedPermutations( str );
return 0;
}
setvbuf is used to set custom buffer. It is used, for example, to set big buffer and to have direct access to it. fprintf will print to file only when buffer is full, or when you flush, or close file. And you also use _IONBF which means that stream is not buffered at all.
So - it works only, because it is not buffered, as you send buffer [100], and then try to print 1024. So also change size of buffer to 1024 and use _IOFBF.

expands shorthand notations like 1-3 in the string to array of strings in C

Lets say I have a string XYZ1-3.
I would like to convert it to a array of strings.
XYZ1,
XYZ2,
XYZ3.
is there an elegant way to do it in C?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **expand(const char *string, int *num){//num : out var
char *id = strdup(string);
int start, end, len;
sscanf(string, "%*[A-Z]%n%d-%d", &len, &start, &end);
id[len] = '\0';
*num = end-start+1;
char **array = malloc(*num * sizeof(char*));
for(int i=0;i < *num ;++i){
len = snprintf(NULL, 0, "%s%d", id, start + i);
array[i] = malloc(++len);
sprintf(array[i], "%s%d", id, start + i);
}
free(id);
return array;
}
int main(){
int n;
char **array = expand("XYZ1-3", &n);
for(int i=0;i<n;++i){
printf("%s\n", array[i]);
free(array[i]);
}
free(array);
return 0;
}
Allow the non-alphabetical(not A-Z) id part
#include <ctype.h>
int id_length(const char *string){
//return length of id part.
int i, len;
for(i=0;string[i];++i);
if(i==0)return 0;
for(i=i-1;isdigit(string[i]) && i>=0;--i);
if(string[i]!='-') return 0;//bad format
for(i=i-1;isdigit(string[i]) && i>=0;--i);
return i+1;
}
char **expand(const char *string, int *num){//num : out var
char *id = strdup(string);
int start, end, len;
len = id_length(string);
sscanf(string+len, "%d-%d", &start, &end);
id[len] = '\0';
*num = end-start+1;
char **array = malloc(*num * sizeof(char*));
for(int i=0;i < *num ;++i){
len = snprintf(NULL, 0, "%s%d", id, start + i);
array[i] = malloc(++len);
sprintf(array[i], "%s%d", id, start + i);
}
free(id);
return array;
}
Try this--
#include<stdio.h>
#include<conio.h>
#include<string.h>
void main()
{
int len,i,c,d,p,j;
char arr[50];
char arr2[50];
char arr3[30][30];
char temp[30];
scanf("%s",arr);
len=strlen(arr);//calculating length of entire input
for(i=0;i<len;i++)
{
if(arr[i]!='-')
arr2[i]=arr[i];//arr2[] will hold the string without the numeral
else
break;
}
c=(int)arr[i-1]-48;//char is converted into int
d=(int)arr[i+1]-48;
for(i=0;i<len-3;i++)
temp[i]=arr2[i];
p=0;
for(i=c;i<=d;i++)
{
temp[len-3]=(char)(i+48);//int is converted into character
for(j=0;j<=len-3;j++)
arr3[p][j]=temp[j];//this 2d array holds array of strings
p++;
}
for(i=0;i<=(d-c);i++)
{
for(j=0;j<=len-3;j++)
{
printf("%c",arr3[i][j]);//printing the strings one by one
}
printf("\n");
}
getch();
}

Resources