C: cant access elements from an array of string in a struct - c

I am new to C and I don't fully understand all this pointer and memory allocation stuff, so sorry if I am conceptually wrong. I am trying to access string elements in an array of strings, but the array of strings is located in a struct, and every time I try to access it my program crashes.
I am getting an error when I try to do this if statement check
if (strcmp(functionList[holder].otherServers[i], "") == 0)
I just want to check if the current structure element in the array of structs (functionList[holder]) has a empty value filled for its elements in its array of strings (otherServers[i]). And when it finds its first empty element, all I want to do is copy a string in that index of the array of strings (otherServers[i])
And here is my code (note: I took out a lot of the code I thought was irrelevant for the question)
struct function {
char name[20];
int parameterNumer;
int canDo;
//currently the system has a 10 server max. You can change this easily
char *otherServers[10];
};
//global scope variables
//currently the system has a 10 server max. You can change this easily
char *serverList[10];
struct function functionList[10] = {{"",0, 0, {}}};
int numberofOtherServers;
while(strcmp(functionList[i].name, "") != 0 && i != -1)
{
//if the function exist in the functionList already, then just add server to the functions list of capable servers
if(strcmp(functionList[i].name, functionName) == 0 && functionList[i].parameterNumer == functionParam)
{
holder = i;
//function found so go through the functions list of servers and add it to the list
i = 0;
while(i >= 0)
{
if(strcmp(functionList[holder].otherServers[i], "") == 0)
{
strcpy(functionList[holder].otherServers[i], serverHelloName);
i = -1; //
}
if(i == 9)
{ //ran through entire list of all possible servers and couldnt find an empty slot
printf("server list full, should allow more room for other servers");
fflush(stdout);
i = -1;
}
}
printf("yay");
fflush(stdout);
}
if(i == 9)
{ //ran through entire list of all possible functions and did not see an empty slot or there is no match
printf("function list full so could not add, and there was no match for any functions");
fflush(stdout);
i = -1;
}
i++;
}

Your code does not show allocation of otherServers. When you have an array of character pointers, like otherServers, you need to allocate memory for each of the strings so there is something to point to.
This means you need to check the pointer points somewhere valid before you can do this strcmp() and strcpy():
if(strcmp(functionList[holder].otherServers[i], "") == 0) {
strcpy(functionList[holder].otherServers[i], serverHelloName);
i = -1;
}
Instead this snippet will check that otherServers[i] hasn't already been allocated and then allocate enough memory to store the string:
if ( functionList[holder].otherServers[i] == NULL ) {
// add one for the terminator
functionList[holder].otherServers[i] = malloc(strlen(serverHelloName) + 1);
// make sure the allocation worked
if ( functionList[holder].otherServers[i] == NULL ) {
// something went wrong so bail
break;
}
strcpy(functionList[holder].otherServers[i], serverHelloName);
}
When you have finished with otherServers[] or functionList[] itself, you need to free the memory allocated earlier:
for ( i = 0; i < 10; i++ ) {
if ( functionList[holder].otherServers[i] != NULL ) {
free(functionList[holder].otherServers[i]);
functionList[holder].otherServers[i] = NULL;
}
}

It's better to put a NUL in place of a plain "" in an initializer:
struct function functionList[10] = {{{'\0'},0, 0, {}}};
To check whether the name in your example is then assigned or not, you just dereference it and check for the NUL character:
*functionList[i].name == '\0'
strcmp checks for a nul character (aka zero-terminator), beginning at the offset supplied, and will keep going beyond the array if it doesn't find one - resulting in undefined behaviour, most likely an access violation, depending on how this buffer was allocated.
SpacedMonkey beat me to the remainder of the valid answer; you need to allocate storage for a string. By default a pointer just points to some area in memory - you must allocate it by hand with malloc before using it, and release it using free.

Related

How to create an array of strings in C dynamically without knowing the size of strings and characters?

I have tried everything and my code looks perfectly fine to me (it obviously isn't if it's not working).
I am trying to read from some text a list of words separated by a comma, and each word will be an element of an array of strings. I don't know how many elements there will be or how long it will be.
The for loop is grand, as I count how many characters there is before. The main problem is allocation memory, sometimes I get "Segmentation Fault: 11" when I run it (as it compiles grand), sometimes when I read the items it get something like:
P?? adios (null) heyya
When it should give me something like:
hola adios bye heyya
I think I am accessing memory I am not supposed to. Anyway, here the code:
// We allocate memory for one string
variables = (char**)calloc(1, sizeof(char*));
variables[0] = (char*)calloc(100, sizeof(char));
if (variables == NULL) {
return NULL;
}
// Now we start looking for the variables
for (int i = comma_pos+1; i < *(second_pos + pos); i++) {
deleteSpaces(string, &i);
// If the character is not a comma, we copy the character
if (*(string + i) != ',') {
*(variables[stringnum] + j) = *(string + i);
j++;
} else {
// If the character is a comma, we have to allocate more memory for a new string
*(variables[stringnum] + j) = '\0';
stringnum++;
j = 0;
char **temp = variables;
// We allocate more memory for a second array
variables = realloc(variables, sizeof(char*) * stringnum);
variables[stringnum] = (char*)calloc(100, sizeof(char));
// If we cannot allocate more memory then get out
if (variables == NULL) {
return temp;
}
} // end else
} // end for
*(variables[stringnum] + j) = '\0';
It's not immediately clear to me what is wrong with your code, but it's not at all how I would approach the problem.
I would start by determining how many substrings there are by counting delimiters in the source string and adding one. This does require a pre-scan of the string, but it's likely to be much cheaper than any alternative that requires performing multiple memory allocations.
As for space for the strings themselves, if you do not need to keep the comma-delimited form of the list, then you may be able to re-use that space. Use the strtok() function to tokenize it, and store the resulting pointers.
If you must preserve the original comma-delimited string, then I suggest making a copy of the whole thing, and then tokenizing as I suggested before (and you will know how long it is already from counting delimiters). You do not need more space overall for the individual strings than the original comma-delimited one occupies.
If you prefer to avoid strtok() then it's not hard to implement the same thing manually.
you have to alloc in both directions and maybe you are already.
you need to allocate the depth, an array of pointers, then for each pointer in that array need to allocate the width for that row.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( void )
{
unsigned int ra;
unsigned int rb;
char **x;
x=malloc(100*sizeof(char *));
printf("%p\n",x);
for(ra=0;ra<100;ra++)
{
x[ra]=malloc(ra*sizeof(char));
}
for(ra=0;ra<100;ra++)
{
printf("%p\n",x[ra]);
}
for(ra=0;ra<100;ra++)
{
for(rb=0;rb<ra;rb++) x[ra][rb]=rb;
}
for(ra=0;ra<100;ra++)
{
for(rb=0;rb<ra;rb++)
{
printf("%u ",x[ra][rb]);
}
printf("\n");
}
return(0);
}

How to recycle and reuse allocated memory?

What I'm working on right now is a state-based parser for any input from a stream. My professor tells me this is the best way to avoid special cases. The way I've got it set up is using functions, and I'm having a little bit of trouble trying to reuse allocated memory so I don't cause any leaks. What I am parsing are multiple parameters. Each parameter has a name and a value. An example input would be:
parameterName = 500;
The name is parameterName and it is of type integer with a value of 500.
I am successfully able to parse one of these without memory leaks. However, doing a second parameter will cause leaks and I know why: It's the multiple uses of malloc on my parameter name.
Take a look at the parsing code:
int main()
{
int x;
char c;
char *nameTemp;
int hasName = 0;
int hasEqual = 0;
/* ParameterManager values */
ParameterManager *pm;
pm = PM_create(500);
if((PM_manage(pm, "name", INT_TYPE, 1)));
while((x = getchar()) != EOF)
{
/* Cast int to char */
c = (char)x;
/* Whitespace state */
if((isspace(c)))
{
c = whitespace();
}
/* Comment state */
if(c == '#')
{
c = comment();
}
/* Name state */
if(((isalnum(c)) && hasEqual == 0 && hasName == 0))
{
nameTemp = name(c);
printf("Name: %s\n", nameTemp);
hasName = 1;
}
/* Equal state */
if(c == '=' && hasName == 1 && hasEqual == 0)
{
hasEqual = 1;
}
/* Value state */
if((isalnum(c)) && hasName == 1 && hasEqual == 1)
{
getValues(c, nameTemp, pm->t_List, pm->m_List);
hasName = 0;
hasEqual = 0;
}
}
free(nameTemp);
if((PM_destroy(pm)) && DEBUG) printf("Success destroying PM.\n");
return 0;
}
The line nameTemp = name(c), under /* Name state */, returns an allocated string. This string is later passed to do other work. However, since this whole parsing idea is in a loop, multiple mallocs to the same string will be made. I can only free nameTemp once but there are multiple mallocs on that name. How can I reuse nameTemp over and over without causing any leaks?
Here is a piece of code (in function name()) where nameTemp is allocated:
/* Make sure temp is not NULL before mallocing */
if(temp[0] != '\0')
{
returnName = malloc(sizeof(char)*strlen(temp)+1);
strncpy(returnName, temp, strlen(temp)+1);
temp[0] = '\0';
return returnName;
}
I apologize if a few things are unclear. I'm trying to be as general as I can so if you need more clarification please let me know.
malloc() does not keep track of allocated blocks. You need to locate all the places where you're finished dealing with the memory you requested, and free() it there.
If I read your code correctly, that would be at the end of your while loop's body.
Edit : pulling up the comments.
It's undefined behaviour to try and use a block of memory that you already free()'d.
However, the pointer you use to keep a handle on the block is just a regular pointer, and won't go stale after you pass it to free(). In fact, it won't budge at all, since free() takes it by copy.
It is thus common to see said pointer set to NULL after it has been passed to free(), to ensure one does not accidentally reuse the now-unusable block.
You can then very well reuse it to be a handle on a brand new block returned by malloc(), as usual.
nameTemp = name(c); causes an inevitable leak, when nameTemp stores a pointer which is not saved somewhere else and is also not freed at this time.
There are quite a few options to avoid this (depends on what you are trying to achieve and how much you are willing to change your code structure).
Three possibilities (ordered from least amount of code change to most):
Free the memory before its assigned again (and free it again at the end of the program)
free(nameTemp);
nameTemp = name(c);
Free the memory when it becomes obsolete
/* Value state */
if((isalnum(c)) && hasName == 1 && hasEqual == 1)
{
getValues(c, nameTemp, pm->t_List, pm->m_List);
hasName = 0;
hasEqual = 0;
free(nameTemp);
nameTemp=NULL;
}
Use a general purpose buffer, allocate a big enough junk of memory at the beginning and free it at the end again.
char* nameTemp;
nameTemp = (char*)malloc(512); //Or any other size, just check that its actually big enough before writing to it, otherwise buffer overflow errors will occur.
// Somwhere in your program
write_name( nameTemp, 512 , c ); // Pass the buffer to be filled by the function, instead of returning a new pointer.
// At the end of your program
free(nameTemp);
nameTemp = NULL; //Prevent access of freed memory.

How to get the value of a string from char* not the address

I am trying to compare patterns. So I have structs which hold the patterns as strings, however I want to be able to build a string and store the VALUE of that string in the struct. At the moment, I am only copying the address of my string.
typedef struct
{
int emp;
char *context;
int numOnes;
int numZeros;
}Pattern;
char *patt, str[t+1];
patt = str;
while(count<t){
//printf("Stream: %d\n", stream[end]);
if(stream[end] == 1){
patt[count]= '1';
//writeBit(1);
}
else{
patt[count]='0';
//writeBit(0);
}
end--;
count++;
}
patt[count]=0;//building string
if(found == 0){//if pattern doesnt exist, add it in
patterns[patternsIndex].context = patt; //NEED HELP HERE. This copies the address not the actual value, which is what i need
patterns[patternsIndex].emp = 1;
prediction = 0;
checkPredict(prediction,stream[end],patternsIndex);
patternsIndex++;
found =1;
}
To avoid making Pattern.context a fixed size array and to be certain there is enough space to copy into you will need to dynamically allocate memory for Pattern.context to store a copy of patt. Either:
use malloc() (remembering to allocate strlen(patt) + 1 for the null terminator) and strcpy():
patterns[patternsIndex].context = malloc(strlen(patt) + 1);
if (patterns[patternsIndex].context)
{
strcpy(patterns[patternsIndex].context, patt);
}
use strdup():
patterns[patternsIndex].context = strdup(patt);
In either case, remember to free() the string copy when no longer required:
free(patterns[patternsIndex].context);
If you mean you want to take the string "14" and make it be a number with the value of 14, then look at the atoi standard function.

Deleting string from array of strings (C)

I have an array of pointers (char**) which contain some strings. The array ends with an empty string ('\0'). I am supposed to search for a specific word in that array of strings and delete the whole line (ofc using realloc and shortening the array of strings). I'm having hard time doing this, I keep getting 'bad ptr' error.
My code:
void deleteSentence(char **text){
char *word,*fptr;
int i=0;
word=(char*)calloc(BUFFER,sizeof(char));
printf("Enter word to delete sentences:\n");
gets(word);
while(text[i][0]!='\0'){
char *str=(char*)malloc((strlen(text[i])+1)*sizeof(char));
strcpy(str,text[i]);
fptr=strtok(str,DELIM);
while(fptr!=NULL){
if(strcmp(fptr,word)==0){
int j=i;
while(text[j][0]!='\0'){
text[j]=(char*)realloc(text[j],(strlen(text[j+1]))*sizeof(char));
strcpy(text[j],text[j+1]);
j++;
}
free(text[j]);
}
fptr=strtok(NULL,DELIM);
if(fptr!=NULL)
i++;
}
}
}
Help much appreciated :)
You're leaking memory like a sieve leaks water, and overrunning your arrays in at least two places. Furthermore the integration of input with the functional purpose of this code does literally nothing to help. The function should do one thing and one thing only:
Given a pointer to an array of char* pointers terminated with an empty string (or NULL), delete all strings in the pointer array that contain word. The resulting potentially compacted array is the return value of the function.
Consider this:
char ** deleteSentances(char **text, const char *word)
{
char **dst = text, **src = text, **res = text;
size_t size = 1, deleted = 0;
// loop while we have a non-null string that isn't empty
while (*src && (*src)[0])
{
char *tmp = strdup(*src);
if (tmp == NULL)
{
perror("Failed to allocate tmp");
exit(EXIT_FAILURE);
}
char *token = strtok(tmp, DELIM);
// search for matching word
while (token && strcmp(word, token))
token = strtok(NULL, DELIM);
// if not found, keep the string. otherwise delete it.
if (!token)
{
*dst++ = *src++;
size++;
}
else
{
free(*src++);
++deleted;
}
// don't need this.
free(tmp);
}
// resize the original array (which could have only gotten smaller)
if (deleted > 0)
{
res = realloc(text, size * sizeof(*res));
if (res == NULL)
{
perror("Failed to allocate res");
exit(EXIT_FAILURE);
}
res[size-1] = *src;
}
return res;
}
Hopefully that explains enough. The code is called like this:
char **text, *word;
//... populate text with strings
//... populate word with prospect word
text = deleteSentances(text, word);
Memory Leaks O'Festival
The OP wanted to understand where memory leaks were in the original posted algorithm. Consider the following first and foremost: For every allocation, there should be a known point of free'ing that memory. This example is somewhat difficult to nail that concept down simply because you're bringing dynamic allocations to the function, and some of them are going to be kept.
That said, consider the following places of interest. We assume coming in to this that at some point we allocated a pointer-array of this form:
char **text = malloc(N * sizeof(*text));
I.e. we have N character points. In each of those, we further assume a dynamic allocation for a character string has also transpired:
for (int i=0; i<(N-1); ++i)
{
//... compute length of next string
text[i] = malloc(length * sizeof(**text));
//... copy in next string to text[i]
}
And finally, the last character pointer in the text array is either NULL or points to a dynamic string of length 0 (i.e. a 0-length terminated string).
Whew. Ok. after all of that lets look at your algorithm:
void deleteSentence(char **text)
{
char *word,*fptr;
int i=0;
// Leak 1: allocate a single buffer of BUFFER-length.
// this is never freed anywhere in this function
word=(char*)calloc(BUFFER,sizeof(char));
printf("Enter word to delete sentences:\n");
// Problem: gets() is so evil and bad it has been deprecated from
// the C langage and will not be available in the next release.
// use fgets() instead.
gets(word);
while(text[i][0]!='\0')
{
// Leak 2: Done N times, where N is the number of strings in
// your original array. again, this is never freed.
char *str=(char*)malloc((strlen(text[i])+1)*sizeof(char));
strcpy(str,text[i]);
fptr=strtok(str,DELIM);
while(fptr!=NULL)
{
if(strcmp(fptr,word)==0)
{
int j=i;
while(text[j][0]!='\0')
{
// Leak 3: Done M-N times for ever string we find in position
// M of the original array. This can be *huge* if there are
// a decent number of number of reductions that crunch your
// original array down.
text[j]=(char*)realloc(text[j],(strlen(text[j+1]))*sizeof(char));
strcpy(text[j],text[j+1]);
j++;
}
// Problem: this just freed the termination string, which should
// never be done. We now have undefined behavior for the rest
// of this algorithm since the terminatingg string is invalid.
free(text[j]);
// Problem: You shoud break right here. See below for why
}
// Problem: you're missing an else condition here. At this point
// if the strcmp() found a match there is no reason to continue
// the loop. You found a match and deleted the string, crunching
// all the other string down one slot in a most-inefficient
// memory-leaking algorihm.
fptr=strtok(NULL,DELIM);
// Problem: the logic here is completely wrong. The i in this case
// should be incremented OUTSIDE the inner while loop. Furthermore
// the test is backwards.
if(fptr!=NULL)
i++;
}
}
}
In short, if it were possible to leak more memory than you did in that algorithm, I'm hard pressed to see how. The posted code I provided will work given the confines of the description I presented, and should be carefully looked to, even stepped through with a debugger line-y-line, to better understand how it works.

check whether structure is null

I populated a structure(ORDER_EXPIRY_TP *OrderReqXml) and now I want to check whether structure conatains any value or not? Here is my code:
OrderReqXml->fIntOrderNumbe =at_int_ord_req->fIntOrderNumber;
OrderReqXml->dLocationCode = 0;
OrderReqXml->dQzUser = at_int_ord_req->dUserId
OrderReqXml->dSuperUserId = 0;
So basically i want 2 check whether OrderReqXml is null or not.
Really depends on what you are trying to achieve.
If you allocate your struct like this:
Order* OrderReqXml = malloc(...);
then, you should indeed check for the pointer being != NULL before assigning values to your struct. A good way would be:
Order* OrderReqXml = malloc(...);
if (OrderReqXml != NULL) {
// fill data
} else { /* error handling */ }
If you obtain the pointer from somewhere else, e.g. from a static structure in memory and you want to check whether the struct has been populated or not, you need to check the single struct elements:
bool structIsNotFilled(Order* o) {
return ((o->fIntOrderNumber == 0) &&
(o->dLocationCode == 0) &&
(o->dQzUser == 0) &&
(o->dSuperUserId == 0))
}
The question then is however, if you wanted to trust this struct in memory to be initialized with zeros. (You must not trust memory allocated with malloc() to be initialized to zero.)

Resources