when using qsort() to try and organize an array of pointers I always get garbage on the first element of the double pointer. I have a suspicion that it's pointing to the wrong memory address and I'm just not understanding.
I'm pretty pretty new to C (about 3-4 weeks) and if someone could help me understand why I'm getting the bad value and suggest how I could get around the problem I would appreciate it.
code:
char *token;
char **string_array = calloc(wordcount, sizeof(char));
if (!string_array){
fprintf(stderr, "couldn't make double pointer\n");
}
size_t str_array = 0;
token = strtok(w2->data, "\n\t ");
printf("token %ld: %s\n",str_array, token);
size_t tok_len = strlen(token);
string_array[str_array] = calloc(tok_len,sizeof(char));
if (!string_array[str_array]){
fprintf(stderr, "could not find any of your words\n");
return;
}
if (!strncpy(string_array[str_array++], token, tok_len)){
return;
}
for (int x = 1; x<wordcount; x++){
token = strtok(NULL, "\n\t ");
tok_len = strlen(token);
string_array[str_array] = calloc(tok_len,sizeof(char));
if (!string_array[str_array]){
fprintf(stderr, "failed somewhere with other tokens\n");
return;
}
printf("token %ld: %s\n",str_array, token);
if (!strncpy(string_array[str_array++], token, tok_len)){
puts("could not find one of your words\n");
return;
}
}
qsort(string_array, str_array, sizeof(*string_array), lexsort);
for (int x = 0; x<wordcount; x++){
printf("%s\n",string_array[x]);
}
return;
}
the output of the program looks like:
**//shows me what flags the user has set**
a selected
this is the most recent character: a
**//debugging though print statements**
The struct was made
gathering words
Allocated space
** //lines of words read in from file passed on the command line**
token 0: is
token 1: a
token 2: file
token 3: of
token 4: 123:LK
token 5: words
token 6: 123456789
**//output after the array has been sorted**
123456789
123:LK
**//this blank spot is the first element of the array and sometimes it's random garbage from memory (depending on the word)**
a
file
of
words
Already tried:
I thought if I expanded the double pointer array +1 (calloc((wordcount + 1), sizeof(char)) and started added the elements at the first index of the array instead of the zeroth index (str_array = 1;) it might help but it just seg faults (naturally...)
First, double pointers are pointers that point to pointers, so in the calloc you must use char * instead of char and you should remember to initialize inner pointers too, which you actually did here string_array[str_array] = calloc(tok_len,sizeof(char));.
Second, strings in C are null terminated which means C stores Hello as H e l l o NULL so when you have strlen equals to 5 you need an array of 6 elements to store it.
string_array[str_array] = calloc(tok_len,sizeof(char) + 1);
The following line in your code is correct:
if (!strncpy(string_array[str_array++], token, tok_len)){
return;
}
but it is better to write it as to make more readable:
if (!strncpy(string_array[str_array], token, tok_len)){
return;
}
str_array++;
About the qsort, I think it is correct and will work as expected. Again, using sizeof(char *) is more readable than sizeof(*string_array).
Related
I am having a hard time getting an array of pointer to structures to save and retrieve the data I filled, the code snippet has the core of my program.
I was able to make the program itself work using an array of struct, but I figure that is more memory intensive and I am trying to only realloc the array of pointers to the structures instead of all the structs at each loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dados_aluno {
int matricula;
char nome[60];
int situacao;
float nota1, nota2, nota3, media;
}dados_aluno;
int main(void){
int done = 0;
int i;
int n_alunos = 0;
int matricula_atual;
dados_aluno *novo_aluno;
dados_aluno **alunos_da_turma;
alunos_da_turma = malloc(sizeof(dados_aluno*));
while (done == 0){
printf("Matricula: ");
scanf("%d", &matricula_atual);
fflush(stdin);//scanf followed by gets = bad time!
if (matricula_atual == -1){
done = 1;
continue;
}
n_alunos++;
novo_aluno = calloc(1, sizeof(dados_aluno));
novo_aluno->matricula = matricula_atual;
printf("\nNome: ");
gets(novo_aluno->nome);
//the code below rises warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
//and returns garbage on the for loop at the end of the program
alunos_da_turma[n_alunos - 1] = &novo_aluno;
//using memcpy instead doesnt rise an error, but the first field is garbage and the 3ยบ interation of the loop crashes
//memcpy(alunos_da_turma[n_alunos -1],&novo_aluno,sizeof(dados_aluno *));
alunos_da_turma = realloc(alunos_da_turma, (sizeof(dados_aluno *) * (n_alunos + 1)));
}
for (i=0;i<(n_alunos);i++){
printf("%d %s\n",alunos_da_turma[i]->matricula,alunos_da_turma[i]->nome);
}
}
I expect to dynamic allocate a struct "dados_alunos" and also dynamic allocate an array of pointers to said structs, insert user input "nome" and "matricula_atual" to the fields of the struct "dados_alunos" and be able to read them after exiting the while loop.
On trying to save the address to the current struct to the array using
alunos_da_turma[n_alunos - 1] = &novo_aluno;
gives the warning "assignment from incompatible pointer type [-Wincompatible-pointer-types]" and seems to save to all the positions of the array the first pointer/garbage written to it no matter how many interactions.
Using memcpy instead store garbage on the first field if I only try one interaction and crashes within 2 interactions or more on the while loop.
alunos_da_turma[n_alunos - 1] = &novo_aluno;
is refused because alunos_da_turma is a dados_aluno ** so alunos_da_turma[n_alunos - 1] is a dados_aluno *, but novo_aluno is a dados_aluno * so &novo_aluno is a dados_aluno **
you wanted
alunos_da_turma[n_alunos - 1] = novo_aluno;
Warning
gets(novo_aluno->nome);
is dangerous (and deprecated since years) because if the input string is greater than 59 characters you write out of the field with an unexpected behavior, do
fgets(novo_aluno->nome, sizeof(novo_aluno->nome), stdin);
However except if you enter the name on the same line you enter the matricula you will get an empty line because the rest of the line/newline is not flush by fflush(stdin);, fflush does not work out of a file
If the name cannot contain separator use scanf("%59s", novo_aluno->nome); rather than fgets, else bypass characters up to the newline explicitely
Note also in
alunos_da_turma = realloc(alunos_da_turma, (sizeof(dados_aluno *) * (n_alunos + 1)));
you reallocate with one extra element, you already increased n_alunos
Doing
int done = 0;
...
while (done == 0){
...
if (matricula_atual == -1){
done = 1;
continue;
}
...
}
is quite complicated for nothing and can be replaced by
for (;;) {
...
if (matricula_atual == -1)
break;
...
}
alunos_da_turma[X] is a pointer to struct dados_aluno, not a pointer to a pointer to a struct dados_aluno.
What would be valid is alunos_da_turma[n_alunos-1] = novo_aluno
So, some solution for general problem:
dados_alunos** alunos_da_turma = malloc (10 * sizeof(dados_aluno*)); //array for 10 pointers
int length = 0; //number of inserted alunos_dados elements
int size = 10; //number of allocated pointers spaces
while(done == 0){
//ask for input
dados_aluno* novo_aluno = malloc (sizeof(dados_aluno));
novo_aluno->matricula = //input
//etc
dados_alunos[length] = novo_aluno;
length++;
if (length == size){
dados_alunos = realloc(dados_alunos, 2 * size * sizeof(dados_aluno*));
size += size; //doubles size
}
}
I am trying to get string of numbers and put it inside an int array.
I have no idea how many numbers I am going to get so I need to use dynamic allocation.
I created an array by using malloc and tried to resize it by +1 every time inside the loop.
This is my code
void main()
{
char *s;
int *polyNums;
int count = 0;
char *token;
s = gets();
polyNums = (int *)malloc(sizeof(int));
if (polyNums == NULL)
{
printf("Could not allocate required memory\n");
exit(1);
}
token = strtok(s, " ");
while (token != NULL)
{
polyNums[count] = *token - '0';
count++;
polyNums = realloc(polyNums, count+1);
token = strtok(NULL, " ");
}
}
My problem is that every time it's doing realloc, all the saved numbers are gone, if my string is "1 2 3" so in loop 1 the polyNums[0] is 1, but I am loosing it in loop 2 after reallocating. Can some one please tell me where I went wrong?
You do not allocate enough memory for your array.
int *polyNums; // Holding integer!
int count = 0;
polyNums = (int *)malloc(sizeof(int)); // enough space for interger. OK!
...
while(...)
{
polyNums[count] = *token - '0';
count++;
polyNums = realloc(polyNums, count+1); // Not enough space for intergers!
...
}
You access an array holding int values but you only allocate 1 byte per element.
While your first allocation can hold the first integer, you allocate less memory for any forther number.
polyNums = realloc(polyNums, (count+1)*sizeof(*polyNums));
Aside from that:
Do not cast the return value of malloc
Do not assign the return value of realloc directly to your pointer. In case of NULL return value you lose your old data.
You should take a look at pointers and resource management, more specifically you should learn what deep copy is and how to reallocate dynamic memory.
In general, you should define a temporary pointer for the new larger chunk of memory, copy all the old values to the new memory location and then you can reassign the temporary pointer to the initial pointer, polyNums. Then you are safe to add more new data.
I'm pretty new to C and was wondering if I could get some help! I've been working on this bug for +15 hours.
So, this program is a tokenizer.
Basically, the program is supposed to take a string, or "token stream," and break it up into "tokens." A "token" is a string of either a word, hexadecimal int, octal int, decimal int, floating point int, or symbol.
The code I'm posting is only the code where things go wrong, the other portion of my program is what creates the token.
The gist of how the below code works is this: It takes a "token stream", and then finds the next token from that stream. Once that is completed, it will create a substring of the "token stream" minus the new token, and return that as the new "token stream."
Essentially, when the string "0x4356/*abdc 0777 */[]87656879jlhg kl(/j jlkh 'no thank you' /" is passed through, the program will do everything properly except when "jlhg kl(/j jlkh 'no thank you' /" passes. Once that passes through my program, a "jlhg" token is created BUT then it is added to the end of the token stream again. So, the new token stream to be broken down becomes " kl(/j jlkh 'no thank you' / jlhg" where jlhg is added on at the end, where it wasn't there before. It does this same weird thing once more, right afterwards, but with "kl" instead.
It only does this under extremely weird conditions, so I'm not sure the cause. I put print statements throughout my program and things flow normally except seemingly out of no where, the program will just add those at the end. This I why I feel like it might be a memory problem, but I have absolutely no clue where to go from here.
Any help would be GREATLY appreciated!!!!
EDIT: If you pass the string "array[xyz ] += pi 3.14159e-10 A12B" output should be:
word "array"
left brace "["
word "xyz"
right brace "]"
plusequals "+="
word "pi"
float "3.14159e-10"
word "A12B"
My TokenizerT is this:
struct TokenizerT_
{
char *tokenType;
char *token;
};
typedef struct TokenizerT_ TokenizerT;
Relevant code:
/*
* TKNewStream takes two TokenizerT objects.
* It will locate the index of the end of the last token,
* and create a substring with the new string to be tokenized.
* #tokenStream: old token stream
* #newToken: new token created from old token stream
*
*/
char *TKGetNextStream(char *tokenStream, char *newToken)
{
int i,
index = 0,
count = 0;
char last = newToken[strlen(newToken)-1];
for(i = 0; i < strlen(newToken); i++)
{
if(newToken[i] == last)
{
count++;
}
}
for(i = 0; i < strlen(tokenStream); i++)
{
if(tokenStream[i] == last && count == 1)
{
index = i + 1;
break;
}
else if(tokenStream[i] == last)
{
count--;
}
}
char *ret = malloc(sizeof(char)*(strlen(tokenStream) - index));
for(i = 0; i < strlen(tokenStream) - index; i++)
{
ret[i] = tokenStream[i+index];
}
return ret;
}
/*
* This is my main
*/
int main(int argc, char **argv)
{
char *string = "0x4356/*abdc 0777 */[]87656879jlhg kl(/j jlkh 'no thank you' /";
TokenizerT *newToken = malloc(sizeof(struct TokenizerT_)),
*tokenStream = malloc(sizeof(struct TokenizerT_));
tokenStream->token = string;
while(newToken != NULL)
{
newToken = TKCreate(TKGetNextToken(tokenStream));
if(newToken != NULL)
{
tokenStream->token = TKGetNextStream(tokenStream->token,
newToken->token);
printf("%s \"%s\"\n",
newToken->tokenType,
newToken->token);
}
}
TKDestroy(newToken);
return 0;
}
The string created in ret isn't properly null terminated. So all the functions dealing with strings will assume it goes on until the next random zero byte that happens to be found after the allocated memory.
To fix this allocate one more byte of space for ret and set that to zero, or use an existing function like strdup() to copy the string:
ret = strdup(tokenStream + index);
So I have the following question:
I have this struct ListAut
struct ListAut{
char* biggestn;
int sizeof_biggestn;
int total_len;
struct node* avl;
};
Its typedef is as it follows:
typedef struct ListAut *IndexOfAuts;
IndexOfAuts *newIndexOfAuts()
{
int i;
IndexOfAuts *ioa = malloc(27 * sizeof(struct ListAut));
for (i = 0; i < 27; i++)
{
ioa[i]->biggestn = "";
ioa[i]->sizeof_biggestn = 0;
ioa[i]->total_len = 0;
ioa[i]->avl = NULL;
}
return ioa;
}
void insertName(IndexOfAuts * ioa, char *nome)
{
char *aux = malloc(sizeof(nome));
aux = trim(nome);
int index = getIndexOfLetter(aux);
if (nameLen(aux) > getSizeOfLongName(ioa[index]))
{
strcpy(ioa[index]->biggestn, aux);
ioa[index]->sizeof_biggestn = nameLen(aux);
}
ioa[index]->total_len += nameLen(aux);
insert(ioa[index]->avl, aux);
}
This is an important part of a module I need for a project, and on its main it's Seg Faulting. I suspect it's on the creation of an "object" newIndexOfAuts(),
The idea of this module is to have an array of 27 pointers to those structures, one to each letter and another to the special characters;
Now I'm just confused because it might be from the problem above or from a module loader I made:
void loadModules(char *filename, IndexOfAuts * ioa, StatTable st)
{
char *nameofile = malloc(20);
strcpy(nameofile, filename);
FILE *file = fopen(nameofile, "r");
if (file != NULL)
{
int counter, ano;
char *buff, *field, *auxil;
buff = malloc(1024);
field = malloc(200);
auxil = malloc(200);
while (fgets(buff, 1024, file))
{
counter = 0;
field = strtok(buff, ",");
printf("inserting 1st name\n");
insertName(ioa, field);
counter++;
while (!atoi(field))
{
if ((auxil = strtok(NULL, ",")) != NULL)
{
counter++;
field = auxil;
insertName(ioa, field);
}
}
ano = atoi(field);
incPub(st, ano, counter - 1);
}
fclose(file);
}
}
When i run this in main that has the following lines:
printf("Creating Stat Table");
StatTable st=newStatTable();\\This Line is correct, i checked it,i hope
printf("Creating index");
IndexOfAuts* ioa=newIndexOfAuts();
printf("Loading Modules");
loadModules(filename,ioa,st);
Those prints were for me to see where was the cause of the seg fault, but the last line printed was the "Creating Index".
There are several cases of undefined behavior and one memory leak (and a possible case of undefined behavior too):
You have this initialization ioa[i]->biggestn=""; It make the biggestn member point to a constant array of one character (the '\0' character). You then do strcpy(ioa[index]->biggestn,aux); which will write over a constant character, and then go outside of the array writing into unknown memory.
You have this: char* aux=malloc(sizeof(nome)); That allocates only 4 or 8 bytes, which the size of the pointer and not what the pointer points to. Use strlen to get the length of a string.
For the above allocation you also need to allocate a byte extra, as strlen only returns the length of the string without the terminator.
You have aux=trim(nome); This overwrites the pointer you just allocated, leading to a memory leak.
The above call might also lead to undefined behavior if you return a pointer to a local variable or array.
There are probably other problematic lines, these were just the ones I found on a quick glance.
And a general tip: Learn to use a debugger! The debugger is a programmers best tool next to the compiler. If you run your program in a debugger, the debugger will stop at the location of the crash, and let you examine (and also walk up) the function call stack, as well as let you examine values of variables.
it is realloc problem again. It seems that I could not find any similar problems in a lot of previous realloc statements. I would appreciate your interest.
I am trying to read text input of format:
g:<expression>;0,1,0,1,0.
I have a set of lines of this format in the source text file and a snippet of code (that follows) reading this line in a "for" loop. expression between : and ; is read into propstr 2D char array. Everything after ; determines a vector (of size DIM) of numbers separated by comma ,. This vector is read into upstr (just as a string) and then converted into array of integers upvec by function process_update_vector. At every iteration of the loop realloc is used to adjust the sizes of the mentioned arrays (propstr,upstr and upvec). Number of lines read so far in the loop is NREAC. Here is the code:
/*Before this point, current line in the source is read into `temp'*/
NREAC++;
for(i=0;i<strlen(temp);i++){
if(temp[i]==':') colon=i;//Here we find colon
if(temp[i]==';') semicolon=i;//...and semicolon positions
}
memset(temp1,'\0',STRLEN);
if(NREAC==1)
ptrchar=(char **)malloc(sizeof(char *));
else
ptrchar=realloc(propstr,NREAC*sizeof(char *));
if(ptrchar==NULL){
fprintf(stderr,"Error: could not allocate memory for propstr\n");
if(propstr!=NULL) free(propstr);
return 1345;
}else{propstr=ptrchar;ptrchar=NULL;}
propstr[NREAC-1]=(char *)malloc((semicolon-colon)*sizeof(char));
if(propstr[NREAC-1]==NULL){
fprintf(stderr,"Error: couldn't get memory for propstr[NREAC-1]\n");
return 1344;
}
for(i=colon+1;i<semicolon;i++)/*Copy the propensity part of the line*/
temp1[i-colon-1]=temp[i];
temp1[i-colon-1]='\n';/*Include newline symbol for correct parsing*/
strcpy(propstr[NREAC-1],temp1);
memset(temp1,'\0',STRLEN);
if(NREAC==1)
ptrchar=(char **)malloc(sizeof(char *));
else
ptrchar=realloc(upstr,NREAC*sizeof(char *));
if(ptrchar==NULL){
fprintf(stderr,"Error could not allocate memory for upstr\n");
if(upstr!=NULL) free(upstr);
return 1343;
}else{upstr=ptrchar;ptrchar=NULL;}
upstr[NREAC-1]=(char *)malloc((strlen(temp)-semicolon-1)*sizeof(char));
if(upstr[NREAC-1]==NULL){
fprintf(stderr,"Error: couldn't get memory for upstr[NREAC-1]\n");
return 1342;
}
if(strlen(temp)-semicolon==2){/*No vector is specified*/
fprintf(stderr,"Error: no update vector found:\n");
fprintf(stderr,"`%s'",temp);
return 1;
}
if(NREAC==1)
ptrint=(int **)malloc(sizeof(int *));
else
ptrint=(int **)realloc(upvec,NREAC*(sizeof(int *)));/*!!!!!!!!!!!!!!!!!!!!*/
if(ptrint==NULL){
fprintf(stderr,"Error: could not allocate memory for upvec\n");
if(upvec!=NULL) free(upvec);
return 1341;
}else{upvec=ptrint;ptrint=NULL;}
upvec[NREAC-1]=(int *)malloc(DIM*sizeof(int));
if(upvec[NREAC-1]==NULL){
fprintf(stderr,"Error: couldn't get memory for upvec[NREAC-1]\n");
return 1340;
}
for(i=semicolon+1;i<strlen(temp)-1;i++)
temp1[i-semicolon-1]=temp[i];
temp1[i-semicolon-1]='\n';/*Include newline for more convenient way of parsing*/
strcpy(upstr[NREAC-1],temp1);
/*Get update vector*/
upvec[NREAC-1]=process_update_vector(upstr[NREAC-1],upvec[NREAC-1]);
memset(temp1,'\0',STRLEN);
memset(temp,'\0',STRLEN);
continue;
This snippet appears in the for loop. The "invalid pointer" error appears in the place marked with /*!!!!!!!!!!!!!!!!!!!!*/.
Conditions of the error. For small enough DIM everything works fine and always worked. At some point, I had to increase DIM up to 11 and then the error occured in the middle of the parsing procedure (It is usual error, I guess, *** glibc detected *** dinamica: realloc(): invalid pointer: 0x000000000165d190 ***). The value of NREAC seems to be not affecting the realloc behavior. It is always the same place in the code where the error occurs. Do I wrongly allocate memory for int type variable, since the allocation for char type was never a problem?
The process_update_vector function:
int * process_update_vector(const char *upstr,int *upvec)
{
int i,j,k;
char symbuf[5];/*5 symbols, max 99999 is possible*/
i = 0;
j = 0;
k = 0;
while(upstr[i] != '\n'){
if(upstr[i] == ','){/*',' is the delimiter*/
symbuf[j] = '\0';
j = 0;
upvec[k] = atoi(symbuf);
k++;
i++;
continue;
}
symbuf[j] = upstr[i];
j++;
i++;
}
/*For the last entry*/
upvec[k] = atoi(symbuf);
k++;
return upvec;
}
Ok, I tried to look at your code. My eyes were sore but I managed to get through the code. here my changes for the first part, where you read the expression between the colon and the semicolon. I changed some types but let more or less the same error handling, even if I think it is overkill or better said, it is at the wrong place (I tend to separate the allocation/error work from the business code, makes it easier to debug).
/*Before this point, current line in the source is read into `temp'*/
char **propstr=NULL; /* I hope this variable was initialized to NULL or else you get problems */
NREAC++; /* This is bad naming, all uppercase is by convention reserved for macros */
char *colon = strchr(temp, ':'); /* There a lib function to do the searching, use them */
char *semicolon = strchr(temp, ';');
if(!colon || !semicolon) {
fprintf(stderr,"Error: syntax error\n");
return 2112; /* whatever */
}
ptrchar=realloc(propstr,NREAC*sizeof(char *)); /* realloc called with a NULL pointer is the same as a malloc, typecasts of mallocs/reallocs are not good. */
if(!ptrchar) {
fprintf(stderr,"Error: could not allocate memory for propstr\n");
free(propstr); /* The check against NULL is also done by free, it's therefoe redundant */
return 1345;
}
else
propstr=ptrchar; /* There's no point in NULLing a variable that will be overwritten anyway */
size_t lenexpr = semicolon-colon; /* The length of the expression can be found by subtracting both pointers */
propstr[NREAC-1]=malloc(lenexpr+1); /* +1 for the \n */
if(!propstr[NREAC-1]) {
fprintf(stderr,"Error: couldn't get memory for propstr[NREAC-1]\n");
return 1344;
}
memcpy(propstr[NREAC-1], colon+1, lenexpr); /* We copy directly without a temporary that way */
propstr[NREAC-1][lenexpr] = '\n'; /* add the linefeed */
propstr[NREAC-1][lenexpr+1] = 0; /* terminate the string */
Here I stopped, because there is a fundamental error in your second part that I do not understand. Do you want to store the vector as a string or as an integer array. If the former, then you have to allocate chars and not sizeof (int), if the latter there must be some atoi or strtol somewhere.
There are several other things that would be nice when you submit a question to SO, you should include the declarations of the variables you use, you should show the defines of the macros you use.
EDIT: second part
// Edit3 ptrchar=realloc(upstr, NREAC*sizeof(char *));
// Edit3 if(!ptrchar) {
// Edit3 fprintf(stderr,"Error could not allocate memory for upstr\n");
// Edit3 free(upstr);
// Edit3 return 1343;
// Edit3 }
// Edit3 else
// Edit3 upstr=ptrchar;
// Edit3 upstr[NREAC-1] = malloc(strlen(semicolon)+1); /* +1 for the \n */
// Edit3 if(!upstr[NREAC-1]) {
// Edit3 fprintf(stderr,"Error: couldn't get memory for upstr[NREAC-1]\n");
// Edit3 return 1342;
// Edit3 }
if(strlen(semicolon)<2) {/*No vector is specified*/
fprintf(stderr,"Error: no update vector found:\n'%s'", temp);
return 1;
}
ptrint = realloc(upvec, NREAC*sizeof(int *));/*!!!!!!!!!!!!!!!!!!!!*/
if(!ptrint) {
fprintf(stderr,"Error: could not allocate memory for upvec\n");
free(upvec);
return 1341;
}
else
upvec=ptrint;
upvec[NREAC-1] = malloc(DIM*sizeof(int));
if(!upvec[NREAC-1]) {
fprintf(stderr,"Error: couldn't get memory for upvec[NREAC-1]\n");
return 1340;
}
// Edit3 memcpy(upstr[NREAC-1], semicolon+1, strlen(semicolon+1)+1); /* +1 will include the \0 */
// Edit3 strcat(upstr[NREAC-1], "\n"); /*Include newline for more convenient way of parsing*/
/*Get update vector*/
// Edit3 upvec[NREAC-1] = process_update_vector(upstr[NREAC-1], upvec[NREAC-1]);
// Edit3, let's reuse our initial pointer, it's still valid.
process_update_vector(semicolon+1, upvec[NREAC-1]);
continue;
The signature of that function process_update_vector seems odd, does it realloc upvec[NREAC-1]? If not, there's no point in returning it and reassigning it. So it would be a good idea to show that function too.
Conclusion: The only errors I detected in your code are, the length of the allocation were 1 too short because of the appended \n.
Other point: By replacing the if(first) malloc else realloc by my realloc you have to make sure that the pointer is NULL initially or else you have a problem.
EDIT2: Here an updated version of process_update_vector, that wasn't incorrect per se, but a was bit complicated for what it does. It also had a high buffer overflow risk, with the temporary buffer of only 5 characters!
This version doesn't need a temp buffer.
void process_update_vector(const char *upstr, int *upvec)
{
const char *p = strchr(upstr, ','); /* There are fine library functions for string handling */
int k = 0;
while(p) {
upvec[k++] = atoi(upstr);
upstr = p+1; /* Position upstr to after , */
p = strchr(upstr, ',');
}
upvec[k++] = atoi(upstr);
/* We don't need to return upvec, it doesn't change in the function */
}
Two comments:
- There's no check of the DIM, so on broken input we can have a buffer oveflow.
- There isn't any white space handling, often strings are entered with spaces after commas (it's more readable), this case wouldn't work in that case, but several while(*p==' ') p++; placed at the right places can take care of that.
EDIT3:
The change in the called function also changes the caller, you don't need to copy to the upstr, so that allocation can be removed completely. I added // Edit3 comments in the 2nd listing. Unless of course if you intend to reuse the copied string elsewhere.
PS: On SO, thanking is done by upvoting the answers.
Using Microsoft Visual Studio 2005 I pasted the code into a temp file and used the reformat command to reformat it to the text below.
See this Wikipedia article on Programming style which can help you from getting flamed for stackoverflow submissions.
Also see this sample of a C coding styles document.
EDIT begin
The runtime is complaining about an invalid pointer which indicates that the pointer you are passing to realloc() is not a pointer that was created with a call to malloc() or to calloc(). It knows because whenever you do a malloc() there is a memory management header that is part of the data area and the pointer you are given is a pointer to allocated memory after the header. See this question How does realloc know how much to copy?
Finally, I rewrote this using a state machine approach (see also state machine explanation) and put that source code at the bottom of the reformatted example.
EDIT end
Looking at the source this appears to be part of a loop. It appears that the variable upvec may not be initialized and it is some kind of an array so is it actually malloced or not?
See section with //-------------------- indicated.
Reformatted source follows:
/*Before this point, current line in the source is read into `temp'*/
NREAC++;
for(i=0;i<strlen(temp);i++){
if(temp[i]==':') colon=i;//Here we find colon
if(temp[i]==';') semicolon=i;//...and semicolon positions
}
memset(temp1,'\0',STRLEN);
if(NREAC==1)
ptrchar=(char **)malloc(sizeof(char *));
else
ptrchar=realloc(propstr,NREAC*sizeof(char *));
if(ptrchar==NULL){
fprintf(stderr,"Error: could not allocate memory for propstr\n");
if(propstr!=NULL) free(propstr);
return 1345;
} else {
propstr=ptrchar;
ptrchar=NULL;
}
propstr[NREAC-1]=(char *)malloc((semicolon-colon)*sizeof(char));
if(propstr[NREAC-1] == NULL){
fprintf(stderr,"Error: couldn't get memory for propstr[NREAC-1]\n");
return 1344;
}
for(i=colon+1;i<semicolon;i++)/*Copy the propensity part of the line*/
temp1[i-colon-1]=temp[i];
temp1[i-colon-1]='\n';/*Include newline symbol for correct parsing*/
strcpy(propstr[NREAC-1],temp1);
memset(temp1,'\0',STRLEN);
if(NREAC==1)
ptrchar=(char **)malloc(sizeof(char *));
else
ptrchar=realloc(upstr,NREAC*sizeof(char *));
if(ptrchar==NULL){
fprintf(stderr,"Error could not allocate memory for upstr\n");
if(upstr!=NULL) free(upstr);
return 1343;
} else {
upstr=ptrchar;
ptrchar=NULL;
}
upstr[NREAC-1]=(char *)malloc((strlen(temp)-semicolon-1)*sizeof(char));
if(upstr[NREAC-1]==NULL){
fprintf(stderr,"Error: couldn't get memory for upstr[NREAC-1]\n");
return 1342;
}
if(strlen(temp)-semicolon==2){/*No vector is specified*/
fprintf(stderr,"Error: no update vector found:\n");
fprintf(stderr,"`%s'",temp);
return 1;
}
// -----------------------------------------------------
if(NREAC==1)
ptrint=(int **)malloc(sizeof(int *));
else
ptrint=(int **)realloc(upvec,NREAC*(sizeof(int *)));/*!!!!!!!!!!!!!!!!!!!!*/
if(ptrint==NULL){
fprintf(stderr,"Error: could not allocate memory for upvec\n");
if(upvec!=NULL) free(upvec);
return 1341;
} else {
upvec=ptrint;
ptrint=NULL;
}
upvec[NREAC-1]=(int *)malloc(DIM*sizeof(int));
if(upvec[NREAC-1]==NULL){
fprintf(stderr,"Error: couldn't get memory for upvec[NREAC-1]\n");
return 1340;
}
// ---------------
for(i=semicolon+1;i<strlen(temp)-1;i++)
temp1[i-semicolon-1]=temp[i];
temp1[i-semicolon-1]='\n';/*Include newline for more convenient way of parsing*/
strcpy(upstr[NREAC-1],temp1);
/*Get update vector*/
upvec[NREAC-1]=process_update_vector(upstr[NREAC-1],upvec[NREAC-1]);
memset(temp1,'\0',STRLEN);
memset(temp,'\0',STRLEN);
continue;
EDIT
A suggested approach for this problem using a state machine with a function that will parse each line of text.
#include <malloc.h>
#include <stdlib.h>
// pLine is a line of text containing a zero terminated string of the format of
// g:<expression>;0,1,0,1,0
// This function will process the line and return the expression as a string
// and a list of the integers.
void processExpression (char *pLine, char *pExpression, int **pIntList)
{
int stateMachineIndex = 1;
int integerCount = 0;
char *pLineSave = 0;
int iIntListIndex = 0;
*pIntList = 0;
while (*pLine) {
switch (stateMachineIndex) {
case 1:
// initial state
if (*pLine == ':') {
// colon found so now start getting the expression
stateMachineIndex = 2;
}
pLine++;
break;
case 2:
if (*pLine != ';') {
*pExpression++ = *pLine++;
} else if (*pLine) {
// if we have not reached end of string yet then go to the
// next state of parsing the list of integers.
stateMachineIndex = 3;
pLine++;
pLineSave = pLine;
}
break;
case 3:
// at this point we begin to process the list of integers.
// however we are not sure how many there are so we will count them first
if (*pLine == ',') {
integerCount++;
}
pLine++;
break;
case 4:
// we now have a count of the integers we expect however it
// may be off by one so we will allocate a smidge more space
*pIntList = (int *)calloc ((integerCount + 2), sizeof(int));
stateMachineIndex = 5;
*pExpression = 0; // and while we are at it lets terminate our expression string
break;
case 5:
// now we get an integer value from the list of integers
(*pIntList)[iIntListIndex++] = atoi (pLine);
// eat up characters to the next integer in the list
while (*pLine && *pLine != ',') pLine++;
if (*pLine == ',') pLine++; // if we found a comma, skip it to the next field
break;
default:
break;
}
if (*pLine == 0 && stateMachineIndex < 4) {
// end of the string so now lets do our integer thing
// if we are still in the first phase of processing
if (pLineSave && *pLineSave && integerCount > 0) {
stateMachineIndex = 4;
pLine = pLineSave; // restart our parser back to the integer area
} else {
break;
}
}
}
}
// simple test harness to test the concept.
int main(int argc, char* argv[])
{
char *pLine = "g:expression and stuff;1,2,3,4,5";
char expressionBuffer[128];
int *pIntList = 0;
processExpression (pLine, expressionBuffer, &pIntList);
return 0;
}