How to dynamic malloc memory in function in c? - 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.

Related

How to properly access this realloc-ed array?

In this code below I am trying to create an array of ints that can be accessed from the main() function, however, Address-sanitizer gives me stack-buffer-overflow-error and I cannot figure out what I am doing wrong. What am I missing?
#include <stdlib.h>
void reallocFail(int **arrayOfInts) {
*arrayOfInts = (int *)malloc(sizeof(int));
for (int i = 1; i <= 10; i++) {
*arrayOfInts = (int *)realloc(*arrayOfInts, (i) * sizeof(int));
*arrayOfInts[i - 1] = i;
}
}
int main(void) {
int *arrayOfInts;
reallocFail(&arrayOfInts);
return 0;
}
There is just a simple typo in *arrayOfInts[i - 1] = i;. suffix operators such as [] bind stronger than prefix operators such as *. Hence you should write:
(*arrayOfInts)[i - 1] = i;
Note also that you should check for memory reallocation failure and you can initialize *arrayOfInts to NULL as realloc(NULL, size) is equivalent to malloc(size).
Here is a modified version:
#include <string.h>
#include <stdlib.h>
int reallocFail(int **pp, int n) {
int i;
*pp = NULL;
for (i = 0; i < n; i++) {
int *p = realloc(*pp, (i + 1) * sizeof(*p));
if (p == NULL)
break;
p[i] = i + 1;
*pp = p;
}
return i;
}
int main(void) {
int *arrayOfInts = NULL;
int n = reallocFail(&arrayOfInts, 10);
for (int i = 0; i < n; i++) {
printf("%d%c", arrayOfInts[i], " \n"[i == n-1]);
}
free(arrayOfInt);
return 0;
}
void reallocFail(int **arrayOfInts)
{
for (int i = 1; i <= 10; i++)
{
*arrayOfInts = realloc(*arrayOfInts, i * sizeof(**arrayOfInts));
arrayOfInts[0][i - 1] = i;
}
}
int main(void) {
int *arrayOfInts = NULL;
reallocFail(&arrayOfInts);
return 0;
}
But this code can be reduced to one realloc (I understand that you test if realloc works).
IT does not check if the realloc has succeeded or failed:
void reallocFail(int **arrayOfInts)
{
int *tmp;
for (int i = 1; i <= 10; i++)
{
tmp = realloc(*arrayOfInts, i * sizeof(**arrayOfInts));
if(tmp)
{
*arrayOfInts = tmp;
arrayOfInts[0][i - 1] = i;
}
else
printf("Alloction error\n");
}
}
For starters this memory allocation before the for loop
*arrayOfInts = (int*)malloc(sizeof(int));
is redundant. You could just write
*arrayOfInts = NULL;
Also you need to check whether memory allocation was successful.
Also this record
*arrayOfInts[i-1] = i;
is equivalent to
*( arrayOfInts[i-1] ) = i;
but you need
( *arrayOfInts )[i-1] = i;
The function can look the following way
size_t reallocFail( int **arrayOfInts, size_t n )
{
*arrayOfInts = NULL;
size_t i = 0;
if ( n != 0 )
{
int *tmp = NULL;
do
{
tmp = realloc( *arrayOfInts, ( i + 1 ) * sizeof( int ) );
if ( tmp != NULL )
{
tmp[i] = i + 1;
*arrayOfInts = tmp;
}
} while ( tmp != NULL && ++i != n );
}
return i;
}
And the function can be called for example like
int *arrayOfInts = NULL;
size_t n = reallocFail( &arrayOfInts, 10 );
for ( size_t i = 0; i != n; i++ )
{
printf( "%d ", arrayOfInts[i] );
}
putchar( '\n' );
free( arrayOfInts );
Here is a demonstration program.
#include <stdio.h>
#include <stdlib.h>
size_t reallocFail( int **arrayOfInts, size_t n )
{
*arrayOfInts = NULL;
size_t i = 0;
if ( n != 0 )
{
int *tmp = NULL;
do
{
tmp = realloc( *arrayOfInts, ( i + 1 ) * sizeof( int ) );
if ( tmp != NULL )
{
tmp[i] = i + 1;
*arrayOfInts = tmp;
}
} while ( tmp != NULL && ++i != n );
}
return i;
}
int main( void )
{
int *arrayOfInts = NULL;
size_t n = reallocFail( &arrayOfInts, 10 );
for ( size_t i = 0; i != n; i++ )
{
printf( "%d ", arrayOfInts[i] );
}
putchar( '\n' );
free( arrayOfInts );
return 0;
}
The program output is
1 2 3 4 5 6 7 8 9 10
Of course there is no great sense to reallocate the memory in the loop within the function. The function just demonstrates how to manage the function realloc.

Trying to fill a char *array by using a helper function, but it prints hieroglyphics [duplicate]

I've tried using a tripple pointer, but it keeps failing. Code:
#include <stdlib.h>
#include <stdio.h>
int set(int *** list) {
int count, i;
printf("Enter number:\n");
scanf("%d", &count);
(*list) = (int **) malloc ( sizeof (int) * count);
for ( i = 0; i<count;i++ ) {
(**list)[count] = 123;
}
return count;
}
int main ( int argc, char ** argv )
{
int ** list;
int count;
count = set(&list);
return 0;
}
Thanks for any advice
What you call list is actually an array. You might do it the following way:
#include <stdlib.h>
#include <stdio.h>
ssize_t set(int ** ppList)
{
ssize_t count = -1;
printf("Enter number:\n");
scanf("%zd", &count);
if (0 <= count)
{
(*ppList) = malloc(count * sizeof **ppList);
if (*ppList)
{
size_t i = 0;
for (; i < count; ++i)
{
(*ppList)[i] = 42;
}
}
else
{
count = -1;
}
}
return count;
}
int main (void)
{
int * pList = NULL;
size_t count = 0;
{
ssize_t result = set(&pList);
if (0 > result)
{
perror("set() failed");
}
else
{
count = result;
}
}
if (count)
{
/* use pList */
}
...
free(pList);
return 0;
}
As far as I understand your question you want to return an array which is allocated in another function : here is the simple version of this
#include<stdio.h>
#include<stdlib.h>
int* set(int *list) {
int count, i;
printf("Enter number:\n");
scanf("%d", &count);
list = (int *) malloc ( sizeof (int) * count);
for ( i = 0; i<count;i++ ) {
list[i] = 123;
}
return list;
}
int main ( int argc, char ** argv )
{
int *list;
list = set(list);
//Use whatever you want to do with that array
free(list); // don't forget to free
return 0;
}
you have an array of integer arrays. Let's look at your set function closely:
for (i = 0; i < count;i++ ) {
(**list)[count] = 123;
}
As you can see you are treating every array object like an integer value.
That should be a nested loop:
for (i to n)
// allocate each array
for (k to m)
// assign value for each value of array

How to order split command line arguments in lexicographical order using a function?

I'm working on a program that takes command line arguments and splits them in half and then orders them in lexicographical order.
For example:
hello, world!
would turn into:
he
ld!
llo
wor
I have a main method that reads through the arguments, a function that splits the arguments, and finally a function that is supposed to order the halves in lexicographical order. I can't get this to run properly because of argument type errors in the lexicographicalSort method and an incompatible pointer type in the main method. I'm having issues to correct these syntax errors, how exactly would I correct them? Also, is there anything here that would cause logical errors? This is what I have so far:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int splitString(char arg[], int n)
{
int len = strlen(arg);
int len1 = len/2;
int len2 = len - len1; // Compensate for possible odd length
char *s1 = malloc(len1 + 1); // one for the null terminator
memcpy(s1, arg, len1);
s1[len1] = '\0';
char *s2 = malloc(len2 + 1); // one for the null terminator
memcpy(s2, arg + len1, len2);
s2[len2] = '\0';
printf("%s\n", s1);
printf("%s\n", s2);
free(s1);
free(s2);
return 0;
}
int lexicographicalSort(char *arg[], int n)
{
char temp[50];
for(int i = 0; i < n; ++i)
scanf("%s[^\n]",arg[i]);
for(int i = 0; i < n - 1; ++i)
for(int j = i + 1; j < n ; ++j)
{
if(strcmp(arg[i], arg[j]) > 0)
{
strcpy(temp, arg[i]);
strcpy(arg[i], arg[j]);
strcpy(arg[j], temp);
}
}
for(int i = 0; i < n; ++i)
{
puts(arg[i]);
}
return 0;
}
int main(int argc, char *argv[])
{
if (argc > 1)
{
for (int i = 1; i < argc; i++)
{
int j = 1;
int k = strlen(argv[i]);
splitString(argv[i], j);
lexicographicalSort(argv[i], j);
}
}
}
Basic scheme is simple. Make an array of tuples {start_pointer, length}. Do some programming on args to split the args. Fill in the array as appropriate. Make sorting with qsort, or any other sort of your choise.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
char *s = "hello, world! . hello.....";
char *pc;
int i, n, nargs;
struct pp{
char *p;
int l;
};
struct pp args[10], hargs[20];
struct pp *pargs;
int cmp(const void * v0, const void * v1) {
struct pp *pv0 = v0, *pv1 = v1;
return strncmp(pv0->p, pv1->p, pv0->l);
}
int main(void)
{
for(pc = s, i = 0; *pc; ++i){
sscanf(pc, "%*[^ ]%n", &n);
if(n > 0){
args[i].p = pc;
args[i].l = n;
}
for(pc += n, n = 0; isspace(*pc); ++pc);
}
for(nargs = i, i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, args[i].l, args[i].p);
putchar('\n');
for(i = 0, pargs = hargs; i < nargs; ++i){
if(args[i].l == 1){
pargs->p = args[i].p;
pargs->l = 1;
pargs = pargs + 1;
}else {
pargs->p = args[i].p;
pargs->l = args[i].l / 2;
pargs = pargs + 1;
pargs->p = args[i].p + args[i].l / 2;
pargs->l = args[i].l - args[i].l / 2;
pargs = pargs + 1;
}
}
putchar('\n');
for(nargs = pargs - hargs, i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, hargs[i].l, hargs[i].p);
qsort(hargs, nargs, sizeof(struct pp), cmp);
putchar('\n');
for(i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, hargs[i].l, hargs[i].p);
return 0;
}
https://rextester.com/GSH22767
Upon splitting a C string, one needs one extra char to store extra null-terminator. There is one answer that bypasses this by storing the length. For completeness, this is closer to your original intention: allocating enough space to copy the programmes arguments. It probably works slower, but one is free to use the strings elsewhere in the programme.
#include <stdlib.h> /* malloc free EXIT qsort */
#include <stdio.h> /* fprintf */
#include <string.h> /* strlen memcpy */
#include <errno.h> /* errno */
static int strcompare(const void *a, const void *b) {
const char *a_str = *(const char *const*)a, *b_str = *(const char *const*)b;
return strcmp(a_str, b_str);
}
int main(int argc, char **argv) {
char *spacev = 0, **listv = 0;
size_t spacec = 0, listc = 0;
int is_done = 0;
do { /* "Try." */
int i;
char *sv;
size_t j;
/* This requires argc > 1. */
if(argc <= 1) { errno = EDOM; break; }
/* Allocate maximum space. */
for(i = 1; i < argc; i++) spacec += strlen(argv[i]) + 2;
if(!(spacev = malloc(spacec)) || !(listv = malloc(argc * 2))) break;
sv = spacev;
/* Copy and split the arguments. */
for(i = 1; i < argc; i++) {
const char *const word = argv[i];
const size_t word_len = strlen(word),
w0_len = word_len / 2, w1_len = word_len - w0_len;
if(w0_len) {
listv[listc++] = sv;
memcpy(sv, word, w0_len);
sv += w0_len;
*(sv++) = '\0';
}
if(w1_len) {
listv[listc++] = sv;
memcpy(sv, word + w0_len, w1_len);
sv += w1_len;
*(sv++) = '\0';
}
}
/* Sort. */
qsort(listv, listc, sizeof listv, &strcompare);
for(j = 0; j < listc; j++) printf("%s\n", listv[j]);
is_done = 1;
} while(0); if(!is_done) {
perror("split");
} {
free(spacev);
free(listv);
}
return is_done ? EXIT_SUCCESS : EXIT_FAILURE;
}
It is simpler than your original; instead of allocating each string individually, it counts the maximum number of chars needed (plus two for two null terminators) and allocates the block all at once (space.) The pointers to the new list also need allocating, the maximum is 2 * argc. Once you copy and modify the argument list, one has an actual array of strings that one can qsort.

C: strcmp error while finding longest repeated substring

I'm trying to create a program which returns the Longest repeated substring. I've almost got the solution, but for some reason my strcmp gives an error when he is busy to find the LRS. Could someone explain me why there is an error and how I solve this?
The code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NSTRINGS 4
char* searchLongestRepeatedSubstring(char* string);
char** makeSuffixArray(char* string);
void freeSuffixArray(char** suffixArray);
int cmp(const void*a, const void* b);
/* do not change this code */
int main(void)
{
char* strings[NSTRINGS] = {
"bananas",
"ask not what your country can do for you, but what you can do for your country",
"main",
"" };
char* result;
for (int i = 0; i < NSTRINGS; ++i)
{
result = searchLongestRepeatedSubstring(strings[i]);
if (result != NULL)
{
/* write out LRS */
printf("%s: \"%s\"\n", strings[i], result);
/* free() the result */
free(result);
result = NULL;
}
else
printf("Geen longest repeated substring.\n");
}
return 0;
}
/**
* Finds the LRS from a string using the function makeSuffixArray
*
* #param the given string
* #return the longest repeated substring
*/
char* searchLongestRepeatedSubstring(char* string)
{
char **p;
p = makeSuffixArray(string);
size_t length = strlen(string);
int max_sz = 0;
char max_word;
int curr_sz = 0;
int curr_word;
char* word1;
char* word2;
char s1, s2;
size_t length1;
size_t length2;
for (size_t i = 0; i < length; i++)
{
for (size_t j = i + 1; j < length; j++)
{
word1 = p[i];
word2 = p[j];
length1 = strlen(word1);
length2 = strlen(word1);
for (size_t x = 0; x < length1; x++)
{
s1 = word1[x];
for (size_t y = 0; y < length2; y++)
{
s2 = word2[y];
if (strcmp(s1, s2) == 0) {
curr_sz++;
strcat(curr_word, s1);
x++;
}
else
break;
}
}
if (curr_sz > max_sz) {
max_sz = curr_sz;
curr_sz = 0;
max_word = curr_word;
curr_word = "";
}
else {
curr_sz = 0;
curr_word = "";
}
}
}
return max_word;
}
/**
* Creates the suffix array of the given string
*
* #param the given string
* #return the suffix array
*/
char** makeSuffixArray(char* string)
{
size_t length = strlen(string);
char **p = (char**)malloc(length * sizeof(char*));
for (size_t i = 0; i < strlen(string); i++)
{
p[i] = &string[i];
puts(p[i]);
}
qsort(p, length, sizeof(char*), cmp);
return p;
}
int cmp(const void* a, const void* b)
{
char ** p = (char**)a;
char ** t = (char**)b;
return strcmp(*p, *t);
}
/**
* free() the memory allocated for the suffix array
*
* #param the given suffix array
*/
void freeSuffixArray(char** suffixArray)
{
free(suffixArray);
}
In your function char* searchLongestRepeatedSubstring-
if (strcmp(s1, s2) == 0) {
s1 and s2 are both char variables , and you pass them to strcmp which expects const char * as arguments , therefore, your compiler complaints .
You can compare them like this-
if(s1==s2)
Also this statement in same if block -
strcat(curr_word, s1);
instead you can do this -
size_t len=strlen(curr_word);
curr_word[len]=s1; // make sure curr_word is large enough
curr_word[len+1]='\0';

Using bsearch with key value equivalent to array element thats a pointer to a char in c

I am using bsearch with a key value equivalent to an array element thats value is a pointer. The key is the elements of an array thats an array of character pointers. I dont think you can dereference array element value by indexing and use value as pointer to char string. I tried casting element value to (char *) but that did not work. Im getting garbage for return value of bsearch.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int Compare(const void *elemA, const void *elemB){
return strcmp(*(char **)elemA, *(char **)elemB);
}
void SortStudents(const char *studentList[], size_t studentCount){
qsort(studentList, studentCount, sizeof(studentList[0]), Compare);
}
void DisplayClassStatus(const char *registrants[], size_t registrantCount,
const char *attendees[], size_t attendeeCount) {
int counter;
int *regnotattend_status = (int *)malloc(sizeof(int) * registrantCount);
int *attendeenotreg_status = (int *)malloc(sizeof(int) * attendeeCount);
char *attendeeStatus, *registrantstatus;
for ( counter = 0; counter < (int)registrantCount; counter++) {
attendeeStatus = (char *) bsearch(&registrants[counter], attendees,
attendeeCount, sizeof(attendees[0]), Compare);
if (attendeeStatus == NULL)
regnotattend_status[counter] = 0;
else{
regnotattend_status[counter] = 1;
printf(" attendeestatus = %s \n", attendeeStatus);
}
}
for (counter = 0; counter < (int)attendeeCount; counter++){
registrantstatus = (char *)bsearch(&attendees[counter], registrants,
registrantCount, sizeof(registrants[0]), Compare);
if ( registrantstatus == NULL)
attendeenotreg_status[counter] = 0;
else
attendeenotreg_status[counter] = 1;
printf("registrantstatus = %s \n", registrantstatus);
}
printf(" Not present: \n");
for ( counter = 0; counter < (int)registrantCount; counter++) {
if (regnotattend_status[counter] == 0)
printf(" %s \n", registrants[counter]);
}
printf( "\n");
printf(" Not registered: \n");
for ( counter = 0; counter < (int)attendeeCount; counter++) {
if (attendeenotreg_status[counter] == 0)
printf(" %s \n", attendeenotreg_status[counter]);
}
}
Since input array is of type const char* [], return value of bsearch would be const char**. Here is your modified code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int Compare(const void *elemA, const void *elemB){
return strcmp(*(char **)elemA, *(char **)elemB);
}
void SortStudents(const char *studentList[], size_t studentCount){
qsort(studentList, studentCount, sizeof(studentList[0]), Compare);
}
void DisplayClassStatus(const char *registrants[], size_t registrantCount,
const char *attendees[], size_t attendeeCount) {
int counter;
int *regnotattend_status = (int *)malloc(sizeof(int) * registrantCount);
int *attendeenotreg_status = (int *)malloc(sizeof(int) * attendeeCount);
char **attendeeStatus, **registrantstatus;
for ( counter = 0; counter < (int)registrantCount; counter++) {
attendeeStatus = (char **) bsearch(&registrants[counter], attendees,
attendeeCount, sizeof(attendees[0]), Compare);
if (attendeeStatus == NULL)
regnotattend_status[counter] = 0;
else{
regnotattend_status[counter] = 1;
printf(" attendeestatus = %s \n", *attendeeStatus);
}
}
for (counter = 0; counter < (int)attendeeCount; counter++){
registrantstatus = (char **)bsearch(&attendees[counter], registrants,
registrantCount, sizeof(registrants[0]), Compare);
if ( registrantstatus == NULL)
attendeenotreg_status[counter] = 0;
else {
attendeenotreg_status[counter] = 1;
printf("registrantstatus = %s \n", *registrantstatus);
}
}
}
int main(int argc, char **argv) {
(void)argc, (void)argv;
const char *attendies[] = {
"foo", "bar", "foobar"
};
const char *registrants[] = { "bar" };
SortStudents(attendies, 3);
DisplayClassStatus(registrants, 1, attendies, 3);
return 0;
}
Last loops are removed since it have a format error (as pointed in comment by WhozCraig) and I'm not really grasp what it meant to do, and it isn't relevant to the question. Please also note that you didn't free memory that you've allocated with malloc.
For possible future questions, please include complete use case whenever possible (somehting like what I've made up in main function).

Resources