C - unable to pass int by pointer to nested function call - c

in Main function, calling a function to loop through a text and check if a column already exists. If not add it into an array of string.
Main:
char** departmentList = NULL;
int sizeOfDepartmentList = 0;
departmentList = collectAllDepartments(departmentList, &sizeOfDepartmentList,recordsPtr);
Function loop for a text and check for new elements:
char** collectAllDepartments(char** departmentList, int *sizeOfDepartmentList, char* records){
char* copyOfRecords = malloc(strlen(records)+1);
strcpy(copyOfRecords,records);
char* sav1 = NULL;
char* token = strtok_s(copyOfRecords,"\n",&sav1);
while(token != NULL){
//char *token_orig = _strdup(token);
char* sav2 = NULL;
char* innerToken = strtok_s(token,",",&sav2);
int counter = 1;
while(innerToken != NULL){
if(counter == 4){
if(!departmentExists(departmentList,*sizeOfDepartmentList,innerToken)){
departmentList = addDepartment(departmentList,&sizeOfDepartmentList,innerToken);
}
// allDepartments = (char*) realloc(allDepartments,strlen(innerToken) + strlen(allDepartments));
// strcat(allDepartments,innerToken);
// strcat(allDepartments,",");
}
++counter;
innerToken = strtok_s(NULL, ",", &sav2);
}
token = strtok_s(NULL, "\n", &sav1);
//free(token_orig);
}
free(copyOfRecords);
return departmentList;
}
The function that pushback new elements into the array of string:
char** addDepartment(char** deparmentList, int* sizeOfDepartmentList, char* department){
*sizeOfDepartmentList += 1;
deparmentList = realloc(deparmentList, *sizeOfDepartmentList * sizeof(char *));
deparmentList[*sizeOfDepartmentList - 1] = department;
return deparmentList;
}
The int need to be passed by pointer twice in order to be used in the pushback function. But the compiler complaint receiving pointer of pointer instead of pointer:

Related

How can I return list in C?

I am trying to divide the string with *, and return the divided strings, as follows.
abc*d*efg*hijk -> [abc,d,efg,hijk]
This is my code, where *pattern is the given string, and I first count the number of asterisk(cnt), and make a empty list with length cnt. But it keeps getting the error and I don't get it... Can anyone help me?
error message
value computed is not used (*star_cnt++;)
function returns address of local variable(return units;)
Number 2 is my main error. I can't return the list
int Slice(char *pattern) {
int *star_cnt;
int cnt;
*star_cnt = *pattern;
cnt = 0;
while (*star_cnt != '\0') {
if (*star_cnt == '*') {
cnt++;
}
*star_cnt++;
}
int units[cnt];
int *unit;
int unit_cnt;
unit_cnt = 0;
*unit = *pattern;
while (*unit != '\0') {
int *new_unit;
while (*unit != '*'){
*new_unit = *unit;
unit++;
new_unit++;
}
unit++;
units[unit_cnt] = *new_unit;
}
return units;
I felt there were a number of things wrong, and that looking at a working example might actually help a bit more here.
You could try something like this:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
/**
* #fn Slice()
* #param [IN] pattern - pointer to string to be analysed
* #param
* #return pointer to array for strings, array is terminated by NULL
* */
char** Slice(char *pattern) {
char *star_cnt;
int cnt;
char** resultlist;
star_cnt = pattern;
cnt = 0;
while (*star_cnt != '\0') {
if (*star_cnt == '*') {
cnt++;
}
star_cnt++;
}
printf("%d items\n",cnt+1);
resultlist = malloc(sizeof(char*) * (cnt+2));
memset(resultlist,0,sizeof(char*) * (cnt+2));
star_cnt = pattern;
cnt = 0;
resultlist[cnt] = star_cnt;
//printf("item %d: %s\n",cnt,resultlist[cnt]);
cnt++;
while (*star_cnt != '\0') {
if (*star_cnt == '*') {
*star_cnt = '\0';
resultlist[cnt] = star_cnt+1;
//printf("item %d: %s\n",cnt,resultlist[cnt]);
cnt++;
}
star_cnt++;
}
return resultlist;
}
int main()
{
char working_string[] = "abc*d*efg*hijk";
char* backup_string = strdup(working_string);
char** list = NULL;
list = Slice(working_string);
int i;
i = 0;
if (list != NULL)
{
while(list[i] != NULL)
{
printf("%d : %s\n",i,list[i]);
i++;
}
free(list);
}
printf("original_string = %s\n",backup_string);
free(backup_string);
}
It produces an output like this:
4 items
0 : abc
1 : d
2 : efg
3 : hijk
original_string = abc*d*efg*hijk
The Slice function basically returns a pointer to char* strings, and the array list is terminated with a NULL in the last element. Keep in mind that in this solution the original string is modified so it cannot be used again.
For storing and returning the result you can also define string container like:
struct c_str_container{
char **arr;
size_t size;
};
And then you can define functions like init_c_str_container, add_element_to_c_str_container and free_c_str_container for dealing with the container.
then you can write the substrings function with using strchr function for finding the delimiters and splitting the string in to sub-strings.
Finally you can use this function to create the container and then after displaying the result from the container (and possibly doing other things with the container) you free the allocated memory by the predefined function free_c_str_container:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct c_str_container{
char **arr;
size_t size;
};
void init_c_str_container(struct c_str_container *container){
container->arr = NULL;
container->size = 0;
}
int add_element_to_c_str_container(struct c_str_container *container, const char *txt, size_t length){
char **newarr = (char **) realloc(container->arr, (container->size + 1) * (sizeof(char *)));
if(!newarr){
newarr = (char **) malloc((container->size + 1) * (sizeof(char *)));
if(!newarr){
return -1;
}else{
for(size_t counter = container->size; counter--;){
newarr[counter] = container->arr[counter];
}
if(container->size){
free(container->arr);
}
}
}
newarr[container->size] = malloc((length + 1) * sizeof(char));
memcpy(newarr[container->size], txt, length);
newarr[container->size][length] = '\0';
container->arr = newarr;
++container->size;
return 0;
}
void free_c_str_container(struct c_str_container *container){
for(size_t counter = container->size; counter--;){
free(container->arr[counter]);
}
free(container->arr);
container->size = 0;
}
struct c_str_container substrings(const char *input, const char delimiter){
const char *input_end = input + strlen(input);
struct c_str_container container;
init_c_str_container(&container);
while(strchr(input, delimiter) == input){
++input;
}
const char *end_point;
while((end_point = strchr(input, delimiter))){
add_element_to_c_str_container(&container, input, (end_point - input));
while(strchr(end_point, delimiter) == end_point){
++end_point;
}
input = end_point;
}
if(input < input_end){
add_element_to_c_str_container(&container, input, (input_end - input));
}
return container;
}
int main(void) {
struct c_str_container container = substrings("***as***we*grow*up", '*');
printf("number of elements is : %zu\n", container.size);
for(size_t counter = 0; counter < container.size; ++counter){
printf("element %zu is : %s\n", counter, container.arr[counter]);
}
free_c_str_container(&container);
printf("now elements are : %zu\n", container.size);
return EXIT_SUCCESS;
}
for the test string ="***as***we*grow*up" delimeter = '*' the result of the program is:
number of elements is : 4
element 0 is : as
element 1 is : we
element 2 is : grow
element 3 is : up
now elements are : 0

Realloc only works twice

For some reason, when I realloc an array to append an item to the array, it only works twice before segfaulting. The segfault occurs when I try to print the strings inside of the array. I currently have an array which is NULL terminated.
void apparr(char** arr, char* line) {
int length = 0;
// find the length of the array
while(arr[length] != NULL) {
length++;
}
// realloc with 2 extra spaces (1 for line, 1 for NULL)
arr = realloc(arr, sizeof(char*) * (length+2));
// set last element (which was NULL) to line
arr[length] = line;
// set the NULL terminator
arr[length+1] = NULL;
}
I have no clue where I could be going wrong here, my only guess would be with how I am calling realloc. However, I would understand that not working for 1 resize, but I have no clue why this works for two resizes then segfaults when I am printing back the array.
How it could be used in main:
int main(int argc, char** argv){
char** hist = malloc(sizeof(char**));
char* linep1;
char* linep2;
char* linep3;
char* linep4;
linep1 = (char*)malloc(strlen("test")*sizeof(char));
linep2 = (char*)malloc(strlen("test2")*sizeof(char));
linep3 = (char*)malloc(strlen("test3")*sizeof(char));
linep4 = (char*)malloc(strlen("test4")*sizeof(char));
strcpy(linep1, "test");
strcpy(linep2, "test2");
strcpy(linep3, "test3");
strcpy(linep4, "test4");
apphist(hist, linep1);
apphist(hist, linep2);
//apphist(hist, linep3); //uncommenting this line causes nothing to be printed
//apphist(hist, linep4); //uncommenting this line causes only test4 to be printed
int x = 0;
while (hist[x] != NULL) {
printf("%s\n", hist[x]);
x++;
}
}
In the main function you need to set the first element of hist as NULL as you are checking it in the function apphist
char** hist = malloc(sizeof(char*));
*hist = NULL;
The function apphist only changes the value of arr locally. To reflect the changes in the main function, you need to pass a pointer to a arr i.e. a 3D pointer char ***arr
You should always check the result of realloc and perform actions on failure.
Code for the function is below.
void apparr(char*** arr2, char* line) {
int length = 0;
char **arr = *arr2;
while(arr[length] != NULL) {
length++;
}
arr = realloc(arr, sizeof(char*) * (length+2));
if (arr == NULL) {
exit(1); // handle error
}
*arr2 = arr;
arr[length] = line;
arr[length+1] = NULL;
}
Alternatively, you can return a pointer to a pointer to char and update the value in main.
char** apparr(char** arr, char* line) {
int length = 0;
char **temp;
while(arr[length] != NULL) {
length++;
}
temp = realloc(arr, sizeof(char*) * (length+2));
if (temp == NULL) {
exit(1); // handle error
}
arr = temp;
arr[length] = line;
arr[length+1] = NULL;
return (arr);
}
//in main
hist = apphist(hist, linep1);
hist = apphist(hist, linep2);
I think you should dereference the arr before you use in realloc. Another observation; the sizeof(char*) is usually 4 in 32 bit architecture and 8 in 64 bit instead of 1.
For the general case I think you only need to call realloc with length +1
arr = realloc(arr, sizeof(char*) * (length+1));
This is because you already had space for the NULL terminating pointer from the prior state. With the code you are proposing what's happening is something like this
// state prior to realloc
String String NULL
// apparr() call
String String NULL undefined undefined // realloc
String String String undefined undefined // arr[length] = line;
String String String NULL undefined // arr[length+1] = NULL;
The first time it will work (leaving a dangling allocated node at the end) but the second time it can crash in multiple ways due to the extra allocation.
All errors and may pitfalls have been mentioned by others already.
Below find a more general implementation of the append-element-to-array function:
#include <stdlib.h>
#include <errno.h> /* for EINVAL */
int apparr(char *** parr, char * line) {
size_t length = 0;
if (NULL == *parr) {
if (NULL != line) {
errno = EINVAL;
return -1;
}
} else {
// find the length of the array
while (NULL != (*parr)[length]) {
++length;
}
}
{
// realloc with 2 extra spaces (1 for line, 1 for NULL)
void * pv = realloc(*parr, (length+1) * sizeof **parr);
if (NULL == pv) {
return -1; /* By convention -1 indicates failure. */
}
*parr = pv;
}
(*parr)[length] = line;
if (0 < length) {
(*parr)[length + 1] = NULL;
}
return 0; /* By convention 0 indicates success. */
}
And use it like this:
#include <stdlib.h>
#include <stdio.h>
int apparr(char *** parr, char * line) {
int main(int argc, char** argv) {
char ** hist = NULL;
char * linep1;
char * linep2;
char * linep3;
char * linep4;
if (-1 == apparr(&hist, NULL)) {
perror("apphist() failed initially\n");
exit(EXIT_FAILURE);
}
linep1 = malloc(strlen("test") + 1);
linep2 = malloc(strlen("test2") + 1); /* +1 for the c-string's 0-termination; sizeof (char) is 1 by definition */
linep3 = malloc(strlen("test3") + 1);
linep4 = malloc(strlen("test4") + 1);
strcpy(linep1, "test");
strcpy(linep2, "test2");
strcpy(linep3, "test3");
strcpy(linep4, "test4");
if (-1 == apphist(&hist, linep1)) {
perror("apphist() failed for line 1\n");
exit(EXIT_FAILURE);
}
if (-1 == apphist(&hist, linep2) {
perror("apphist() failed for line 2\n");
exit(EXIT_FAILURE);
}
if (-1 == apphist(&hist, linep3) {
perror("apphist() failed for line 3\n");
exit(EXIT_FAILURE);
}
if (-1 == apphist(&hist, linep4) {
perror("apphist() failed for line 4\n");
exit(EXIT_FAILURE);
}
{
size_t x = 0;
while (hist[x] != NULL) {
printf("%s\n", hist[x]);
++x;
}
}
}
You have several errors in your code:
This is your main error. You don't replace the value in the given pointer. It's correct to use a pointer to the pointer, but you need to dereference it. For this you need to pass the pointer to hist and dereference it at the re-allocation:
*arr = realloc(*arr, sizeof(char*) * (length + 2));
The list of pointers is not initialized, after the first allocation you need to set the first pointer:
hist[0] = NULL;
The allocations for your test strings are 1 off:
linep1 = malloc((strlen("test") + 1) * sizeof(char));
linep2 = malloc((strlen("test2") + 1) * sizeof(char));
linep3 = malloc((strlen("test3") + 1) * sizeof(char));
linep4 = malloc((strlen("test4") + 1) * sizeof(char));
Additional notes:
The includes are missing for a complete minimal reproducable example.
The name apparr() is wrong, you call apphist() in main().
Check the return values of any allocation for NULL, meaning that the allocation failed.
You don't use argc and argv, so write int main(void)
The first allocation has the "wrong" type, but both are pointers, so it's the same size: char** hist = malloc(sizeof(char*));
There is no need to cast pointers returned by malloc() as it returns a pointer to void. Pointers to void and other pointers can be assigned back and forth without casts.
You can replace the malloc()/strcpy() pairs with strdup().
You can even call apphist() with the string as "immediate" value like this: apphist(hist, "test");
main() should return an int, EXIT_SUCCESS is the right value.
You can put some const at the parameters and declarations to make things safer. But think about what is constant.

Segmentation Fault: double free or corruption (fast top)

I've a problem when I run this piece of code: a Segmentation Fault that appears during the free instruction of percorso. I cannot find the problem.
void ricerca(char nome[], struct node *radice, char percorso[], struct stringhe **indice) {
struct node *punt = radice;
int dim = len(percorso);
char *prov = NULL;
if (dim > 0) {
prov = malloc(2 * dim * sizeof(char));
prov[0] = '\0';
strcpy(prov, percorso);
free(percorso); //--------------------->here the SegFault
}
struct stringhe *nuovo = NULL;
int i = 0, fine = 0;
char *perc_orig = NULL;
if (punt != NULL) {
if (punt->array != NULL) {
dim = len(prov) + len(punt->nome) + 2;
percorso = malloc(dim * sizeof(char));
percorso[0] = '\0';
if (prov!=NULL)
strcpy(percorso, prov);
strcat(percorso, "/");
strcat(percorso, punt->nome);
perc_orig = malloc(dim * sizeof(char));
for (i = 0; i < N; i++) {
if (punt->array->vet[i] != NULL) {
perc_orig[0] = '\0';
strcpy(perc_orig, percorso);
ricerca(nome, punt->array->vet[i], perc_orig,indice);
}
}
free(perc_orig);
}
if (strcmp(nome,punt->nome) == 0) {
free(percorso);
dim = len(prov) + len(punt->nome) + 2;
percorso = malloc(dim * sizeof(char));
inizializza(percorso, dim);
if (prov != NULL)
strcpy(percorso, prov);
strcat(percorso, "/");
strcat(percorso, punt->nome);
nuovo = malloc(sizeof(struct stringhe));
nuovo->next = NULL;
nuovo->str = malloc(dim * sizeof(char));
inizializza(nuovo->str, dim);
strcpy(nuovo->str, percorso);
nuovo->next = (*indice);
*indice = nuovo;
}
while (punt->chain != NULL && fine == 0) {
ricerca(nome, punt->chain,prov, indice);
fine = 1;
if (prov!=NULL)
free(prov);
}
}
}
The len function is like strlen, but the difference is that I've made it myself.
the context is:
void find(char nome[], struct node *radice) {
char *perc = NULL;
struct stringhe **inizio = NULL;
inizio = malloc(sizeof(struct stringhe*));
*inizio = NULL;
int i = 0;
for (i = 0; i < N; i++) {
if (radice->array->vet[i] != NULL) {
perc = NULL;
ricerca(nome, radice->array->vet[i], perc, inizio);
}
}
if (*inizio != NULL) {
insertion(inizio);
stampap(*inizio);
} else
printf("no\n");
}
And the data structures:
struct tab {
struct node *vet[64];
};
struct node {
char nome[255];
int num;
int tipo;
char *dati;
struct tab *array;
struct node *chain;
};
This is really weird:
if (some condition)
free(percorso);
Later on we have:
perc_orig = malloc(dim*sizeof(char));
for(something){
if(something){
ricerca(nome,punt->array->vet[i],perc_orig,indice);
}
}
free(perc_orig);
If that if conditions happens, perc_orig will be freed twice. Kaboom.
I think your problem is you think that ricerca(..., char percico[], ...) copies percico. It doesn't; it's really ricerca(..., char *percico, ...) so you ended up freeing the memory twice.
the sizing for the char arrays needs to allow for the trailing NUL ('\0') character.
ALL fields that are referenced by strcpy() and similar functions need to have ALL source character arrays NUL terminated.
The code does not seem to be allocating enough room for those trailing NUL bytes NOR terminating every character array with a NUL char.
Segmentation fault occurs when you initialize a character pointer to NULL and try to point it to a not null value
For example,
char *a=NULL;
a='a';
Will cause segmentation fault. To avoid this you can try to initialize as,
char *a;
a='a';

Creating a dynamic array of char* from a char* text using strtok_s

My search here got many results, but none quite like so that I could find a solution to my problem.
I'm creating a Mathcad UserEFI DLL in C using Visual Studio 2013. I don't want to use strings, only char*.
Now, I want to emulate the console main function, which uses char* argv[] to access the parameters of a called executable. Mathcad will call the DLL with a string like "-T=3 z h 13". All I want is to parse this text into an array of char*, just like argv[] would be if I called an executable with this added parameters. I hope I expressed this in an understandable way.
I use strtok_s to parse the text and one has to consider, that every token can have a different size.
The error must lie in the following function:
typedef struct tArgReturnType {
int ACount;
char** Argus;
} ARGRETURN;
ARGRETURN ParseStringToArgs(char* text) {
char *token = NULL;
char *nextToken = NULL;
int argCount = 0;
char* temptext = NULL;
strcpy(temptext, text);
char** uebergabe = (char**)malloc(sizeof(char**));
token = strtok_s(temptext, " ", &nextToken);
while (token != NULL) {
argCount++;
uebergabe = (char**)realloc(uebergabe, sizeof(uebergabe)+sizeof(token));
uebergabe[argCount - 1] = token;
token = strtok_s(NULL, " ", &nextToken);
}
ARGRETURN ReturnVar;
ReturnVar.ACount = argCount;
ReturnVar.Argus = (char**)malloc(sizeof(uebergabe));
memcpy(ReturnVar.Argus, uebergabe, sizeof(uebergabe));
free(uebergabe);
return ReturnVar;
}
I'm sure that this is a complete mishmash of heap memory allocation failures (as indicated by the error the mathcad compiler gives me), since I modified this code multiple times while trying to find a solution. I'm just utterly confused now.
Updated Code:
typedef struct tArgReturnType {
int ACount;
char** Argus;
} ARGRETURN;
ARGRETURN ParseStringToArgs(char* text) {
char *token = NULL;
char *nextToken = NULL;
int argCount = 0;
char* temptext = malloc(strlen(text) + 1);
strcpy(temptext, text);
char** uebergabe = malloc(sizeof(char**));
token = strtok_s(temptext, " ", &nextToken);
while (token != NULL) {
argCount++;
uebergabe = (char**)realloc(uebergabe, sizeof(uebergabe)+sizeof(token));
uebergabe[argCount - 1] = token;
token = strtok_s(NULL, " ", &nextToken);
}
ARGRETURN ReturnVar;
ReturnVar.ACount = argCount;
ReturnVar.Argus = malloc(sizeof(uebergabe));
memcpy(ReturnVar.Argus, uebergabe, sizeof(uebergabe));
free(uebergabe);
free(temptext);
return ReturnVar;
}
ARGRETURN ParseStringToArgs(const char* text) {
ARGRETURN ReturnVar = { 0 };
int n = 0;
char temp[100];
while (sscanf(text += n, "%99s%n", temp, &n) == 1) {
ReturnVar.Argus = realloc(ReturnVar.Argus, ++ReturnVar.ACount*sizeof(*ReturnVar.Argus));
strcpy(ReturnVar.Argus[ReturnVar.ACount - 1] = malloc(strlen(temp) + 1), temp);
}
return ReturnVar;
}
'sizeof(text)' is a great mistake
don't use ugly strtok(_s), it's not reentrant, destroys the string, ...
use sscanf instead

split/parse and get value from a char array

I want to write a function in C, by which I can get value of the tag from a char array ::
Example ::
char a[]="name=RRR&school=AAA&roll=111&address=SSS";
I want to write a function - if I give "name" as a parameter of the function then the function will return RRR --- if I give "school" as a parameter of the function then the function will return AAA
i have done it in Java ...
public String getTagValue(String toSplit, String tag)
{
String CommandTypeValue="";
String[] FirstSplit;
String[] SecondSplit;
String delims = "&";
FirstSplit = toSplit.split(delims);
for(int i=0; i<FirstSplit.length; i++ )
{
delims = "=";
SecondSplit = FirstSplit[i].split(delims);
if(SecondSplit[0].equals(tag))
return SecondSplit[1];
//System.out.println(SecondSplit[0] +" "+ SecondSplit[1]);
}
return CommandTypeValue;
}
How to do it C ?? any easy library or function ??
strtok is what your are looking for.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* getTagValue(char* a_tag_list, char* a_tag)
{
/* 'strtok' modifies the string. */
char* tag_list_copy = malloc(strlen(a_tag_list) + 1);
char* result = 0;
char* s;
strcpy(tag_list_copy, a_tag_list);
s = strtok(tag_list_copy, "&");
while (s)
{
char* equals_sign = strchr(s, '=');
if (equals_sign)
{
*equals_sign = 0;
if (0 == strcmp(s, a_tag))
{
equals_sign++;
result = malloc(strlen(equals_sign) + 1);
strcpy(result, equals_sign);
}
}
s = strtok(0, "&");
}
free(tag_list_copy);
return result;
}
int main()
{
char a[]="name=RRR&school=AAA&roll=111&address=SSS";
char* name = getTagValue(a, "name");
char* school = getTagValue(a, "school");
char* roll = getTagValue(a, "roll");
char* address = getTagValue(a, "address");
char* bad = getTagValue(a, "bad");
if (name) printf("%s\n", name);
if (school) printf("%s\n", school);
if (roll) printf("%s\n", roll);
if (address) printf("%s\n", address);
if (bad) printf("%s\n", bad);
free(name);
free(school);
free(roll);
free(address);
free(bad);
return 0;
}
Check the strtok function out. You can use it to split your toSplit string on & and on each iteration split again on = to see if the tag matches what you want.
Use the strtok() family of the standard library:
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
char * p[10], temp;
temp = strtok(str,"&");
int i=0;
while (temp != NULL)
{
p[i++] = temp;
temp = strtok (NULL, "&");
}
Then you can use strtok for each parameter individually using "=" as the delimiter.

Resources