First element in two dimensional array being overwritten - C - c

I've been having the same issue for a while now and I can't seem to get my head around it no matter how much research. I have came up with some theories why it may be happening though.
Basically, I'm writing a simple C shell and I'm encountering an annoying error when trying to implement aliases which I am going to store in a two-dimensional array. Whenever I try to assign more than one alias to the array, it overwrites the first element.
I thought it might be down to:
Memory issues when tokenizing the input again
Issues with array "decay" and pointers
My compiler hates me.
Here is my code:
void fillArray(char* tokens[], char* aliasArray[ALIAS_NO][TOKEN_NUM]) {
/* Integer for the for loop */
int i;
/* Counter for attribute addition */
int counter = 2;
/* Onto the search */
for (i = 0; i < ALIAS_NO; i++) {
if (aliasArray[i][0] == NULL) { /* If there is a space here */
aliasArray[i][0] = tokens[counter-1]; /* Assign the alias */
while (tokens[counter] != NULL) { /* While there is still stuff left */
aliasArray[i][counter-1] = tokens[counter]; /* Add it in */
counter++; /* Increment the counter */
}
return;
}
}
return;
}
Where ALIAS_NO and TOKEN_NUM are preprocessor directives of the value 10 and 50 respectively.
The check works to see if the entry is null when I print the status of i and I also initialise every element in the multidimensional array to NULL.
Any assistance will be greatly appreciated. I've been banging my head against the wall for far too long now.
Thanks :)
EDIT: I've also tried to use the strcpy() function. Unfortunately, this throws a segmentation fault.
EDIT: New code
void fillArray(char* tokens[], char* aliasArray[ALIAS_NO][TOKEN_NUM]) {
/* Integer for the for loop */
int i;
/* Counter for attribute addition */
int counter = 2;
/* Buffer */
char buffer[200];
/* Onto the search */
for(i = 0; i < ALIAS_NO; i++) {
if(aliasArray[i][0] == NULL) { /* If there is a space here */
strcpy(buffer, tokens[counter-1]);
aliasArray[i][0] = buffer; /* Assign the alias */
while (tokens[counter] != NULL) { /* While there is still stuff left */
strcpy(buffer, tokens[counter]);
aliasArray[i][counter-1] = buffer; /* Add it in */
counter++; /* Increment the counter */
}
return;
}
}
return;
}

for(i = 0; i < ALIAS_NO; i++)
{
if(aliasArray[i][0] == NULL)
{
aliasArray[i][0] = strdup(tokens[counter-1]);
while (tokens[counter] != NULL)
{
aliasArray[i][counter-1] = strdup(tokens[counter]);
counter++;
}
break;
}
}

Related

Storing several string with struct in C

with following code I can store one string only.
Main problem is how to store several. If i want to enter another string after the first one it wont do it.
I didnt write it in code but when I type("KRAJ") it should get out of while loop.
typedef struct{
char Objekat[20+1];
char Mjesto[20+1];
char velicina [20];
int cijena;
char kn[3];
char stanje[20];
}Apartmani;
int main()
{
Apartmani *apartmani=(Apartmani*)malloc(sizeof(Apartmani)*50);
while(scanf("%[^,\n],%[^,],%[^,],%d%[^,],%[^\n]", &apartmani[i].Objekat,&apartmani[i].Mjesto,&apartmani[i].velicina,
&apartmani[i].cijena,&apartmani[i].kn, &apartmani[i].stanje )==6)
{
i++;
}
for(p=0;p<i;p++)
{
printf("%s %s %s %d %s %s",apartmani[p].Objekat,apartmani[p].Mjesto,apartmani[p].velicina,apartmani[p].cijena,
apartmani[p].kn, apartmani[p].stanje);
}
}
For example:
string 1: Apartman, Novalja, 100.00 m2, 750000kn, dobro ocuvano.
string 2: Kuca, Ivanbregovia, 20m2, Imtoski, 21252RH, vrijednost-neprocjenjiva.
You should use fgets() plus sscanf().
You should not cast malloc[Do I cast the result of malloc?][1]. Remember to check the return value of malloc, since it can be failed.
change the line of allocating apartmani to:
Apartmani *apartmani= malloc(sizeof(Apartmani)*50);
if(!apartmani) {return -1;}
Do not use & for the input of string.
Check the value of i because its value is limited to 50.
Your code is missing the declaration of i (should be: int i = 0), and the declaration of p also.
Your while loop can be as below:
int i = 0;
char line[100];
while(i < 50 && fgets(line,sizeof(line),stdin))
{
line[strcspn (line, "\n" )] = '\0'; // trip the enter character at the end of line.
int err = sscanf(line,"%20[^,],%20[^,],%19[^,],%d,%2[^,],%19[^\n]", apartmani[i].Objekat,apartmani[i].Mjesto,apartmani[i].velicina,&apartmani[i].cijena,
apartmani[i].kn, apartmani[i].stanje);
if(err != 6)
break;
i++;
}
If I understand you correctly, you want to store several 'Apartmani' structures.
In this case, you have 2 main possibilites :
Using array of structures (Fastest to write but less efficient)
Use linked-list (More efficient but more complex to use)
Examples
1: Using array of structures
#define MAX_APARTMANI 50
int main(void) {
int i = 0;
/* Create Apartmani array */
Apartmani *apartmani_tab[MAX_APARTMANI];
do {
/* loop by using malloc on a single element */
apartmani_tab[i] = (Apartmani *) malloc(sizeof(Apartmani));
/* While check using scanf */
} while (scanf("%[^,\n],%[^,],%[^,],%d%[^,],%[^\n]", apartmani_tab[i]->Objekat, apartmani_tab[i]->Mjesto, apartmani_tab[i]->velicina,
apartmani_tab[i]->cijena, apartmani_tab[i]->kn, apartmani_tab[i]->stanje) == 6 && ++i < MAX_APARTMANI)
/* good pratice: don't forget to free memory ! */
while (--i > 0) {
free(apartmani_tab[i]);
}
return (0);
}
2: Using linked-list
typedef struct Apartmani {
char Objekat[20+1];
char Mjesto[20+1];
char velicina [20];
int cijena;
char kn[3];
char stanje[20];
struct Apartmani *next;/* add pointer to next item in the list */
} Apartmani_t;
Apartmani_t *new_item(void) {
Apartmani_t *new_element = NULL;
new_element = (Apartmani_t *) malloc(sizeof(Apartmani));
if (!new_element)
return (NULL);
memset(new_element, 0, sizeof(*new_element));
new_element->next = NULL;
return (new_element);
}
int main(void) {
/* Initialize Apartmani list*/
Apartmani *apartmani_list = NULL, *current = NULL;
do {
if (!apartmani_list) { /* if empty list */
apartmani_list = new_item(); /* add first item */
if (!apartmani_list) /* prevent malloc errors */
break;
current = apartmani_list; /* link current pointer to list */
} else {
current->next = new_item();
if (!current->next) /* if malloc fails */
break;
current = current->next; /* update current pointer */
}
} while (scanf("%[^,\n],%[^,],%[^,],%d%[^,],%[^\n]", current->Objekat, current->Mjesto, current->velicina, current->cijena, current->kn, current->stanje) == 6) /* While check using scanf */
/* good pratice: don't forget to free memory ! */
while (apartmani_list) {
current = apartmani_list->next;
free(apartmani_list);
apartmani_list = current;
}
}
NB: I have not tried this code but the final version is probably very close to that.

Creating an array of structs by adding dynamically some struct-elements

I've been struggling with C pointers for hours now. I'm trying to create a C program which manages flights. A flight contains the following:
flight-number, from, to, date, price
OS772,Vienna,New York,15.12.2018,638.00
Therefore, I'm reading a textfile of this given structure. On every line read, I need to create another struct and add it to my array or "list" of structs.
The struct looks like:
typedef struct flights {
char *flnum;
char *from;
char *to;
char *date;
float price;
struct person *fPerson;
}flights;
My problem: Inside the function, the array of structs is created properly. But back in the main-function, the pointer to the array called 'flights **flight_list' is still NULL.
Here is the code (only the necessary parts):
int main(void) {
flights **flight_list = NULL;
int numFlights = 0;
if (!(numFlights = load_flights(flight_list)))
return EXIT_FAILURE;
/* value of flight_list = 0x0000 -> unchanged! */
/* ... */
Function short load_flights(flights **flight_list):
short load_flights(flights **flight_list) {
FILE *fp = NULL;
char file_buffer[256] = {};
int i = 0;
if (fp = fopen("flights.txt", "r")) {
/* create array of structs */
flight_list = (flights **)calloc(1, sizeof(int));
while (!feof(fp)) {
/* read current line of flight from textfile */
fgets(file_buffer, sizeof(file_buffer), fp);
/* create a new struct and add it to the array */
if ((flight_list[i] = (flights *)calloc(1, sizeof(flights))) != NULL) {
/* create every variable of the struct */
flight_list[i]->flnum = (char *)calloc(1, strlen(ptr)+1);
/* ... */
}
i++;
}
}
else return 0;
/* values of the struct-array are properly set; look in attached picture */
return i;
}
This image was taken while debugging the array-creation process before return i;:
And here outside the function; inside main:
So, why is my array of structs gone in the main-function?
You need to pass the address of a pointer variable to load_flights. Then load_flights needs to indirect through the variable to modify the caller's variable.
To handle the dynamic size of the input, you need to use realloc() each time through the loop to grow the array.
int main(void) {
flights **flight_list = NULL;
int numFlights = 0;
if (!(numFlights = load_flights(&flight_list)))
return EXIT_FAILURE;
/* ... */
}
short load_flights(flights ***flight_list) {
FILE *fp = NULL;
char file_buffer[256] = {};
int i = 0;
if (fp = fopen("flights.txt", "r")) {
/* create array of structs */
flight_list **temp_flight_list = NULL;
/* read current line of flight from textfile */
while (fgets(file_buffer, sizeof(file_buffer), fp)) {
// Grow the flight list array
flights **new_flight_list = realloc(*flight_list, (i+1) * sizeof(flight_list *));
if (new_flight_list == NULL) { // allocation failed, throw everything away
for (int j = 0; j < i-1; j++) {
free(temp_flight_list[i]->flnum);
free(temp_flight_list[i]->from);
/* ... */
free(temp_flight_list[i]);
}
free(temp_flight_list);
return 0;
}
temp_flight_list = new_flight_list;
/* create a new struct and add it to the array */
if ((temp_flight_list[i] = calloc(1, sizeof(flights))) != NULL) {
// Parse the buffer ...
/* create every variable of the struct */
temp_flight_list[i]->flnum = calloc(1, strlen(ptr)+1);
/* ... */
} else { // allocation failed, throw everything away
for (int j = 0; j < i-1; j++) {
free(temp_flight_list[i]->flnum);
free(temp_flight_list[i]->from);
/* ... */
free(temp_flight_list[i]);
}
free(temp_flight_list);
return 0;
}
i++;
}
// Store new flight list in caller's variable
*flight_list = temp_flight_list;
return i;
}
else return 0;
}
See also
Do I cast the result of malloc?
and
Why is “while (!feof(file))” always wrong?

C: dictionary implemented from a txt file with linked lists and a hash table can't find words that exist in the file

Please excuse any mistakes made in this post, as this is my first post here, but do point them out.
I'm still quite new to C, but I'm trying to implement a dictionary from a txt file that has one word in each line through a hash table but whenever I try to search for a word it's never found, though it exists in the file.
Can you please help me figure out what I'm doing wrong?
Both following files:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define tab_size 29 /* table size */
#define word_len 24 /* max length of word */
.h file:
/* structure to be used for each word */
typedef struct list {
char *word;
struct list *next;
} WORD;
.c file:
/* create table */
WORD **create_tab(int size) {
int i = 0;
WORD **hash_tab;
hash_tab = malloc(sizeof(*hash_tab) * size); /*allocate memory */
for (; i<size; i++) /* initialize elements */
hash_tab[i]=NULL;
return hash_tab;
}
/* search for word in table; returns 1 if found, 0 otherwise */
int search(WORD **tb, char *w) {
WORD *htmp/*, *hprv*/;
unsigned long hash = (hash_f(w) % tab_size); /* hash_f is Dan Bernstein's hash function; modulo by tab_size to make sure it fits */
for (htmp = tb[hash]; (htmp != NULL) && (strcmp(htmp->word, w) != 0); / htmp = htmp->next) /* follow chained array of respective cell until word is found or until the end */
{
;
}
if (htmp == NULL) return 0;
return 1;
}
/* insert new WORD with word w at the beginning of the chained array of the respective cell */
void insert(WORD **ht, char *w) {
WORD *htmp;
unsigned long hash = (hash_f(w) % tab_size); /* hash_f is Dan Bernstein's hash function; modulo by tab_size to make sure it fits */
htmp = malloc( sizeof(*htmp) ); /* allocate memory for new WORD */
htmp->word = calloc(word_len+1,sizeof(char)); /* allocate memory for new word with max word length plus one character to make sure there's no buffer overflow in the next line*/
strncpy(htmp->word, w, word_len); /* copy w to word */
htmp->next = ht[hash]; /* new WORD now points to content of the respective table cell */
ht[hash] = htmp; /* table cell now points to new WORD */
}
/* receive empty table and create the whole dictionary in memory word by word */
WORD **make(WORD **dic;) {
char w[word_len];
FILE *dictionary;
dictionary = fopen("dictionary.txt","r");
while ((fgets( w, word_len, dictionary )) != NULL)
insert(dic, w);
fclose(dictionary);
return dic;
}
int main() {
WORD **dic;
char w[word_len];
dic = create_tab(tab_size); /* create the table */
dic = make(dic); /* insert all entrys of dictionary in table */
printf("Insert a word in lowercase: \n");
if ((scanf("%s",w)) == 0) return 0; /* if I didn't somehow verify the scanf it would return an error */
else if (search(dic, w) == 1) printf("The word %s exists in the dictionary \n",w);
else printf("The word %s does not exist in the dictionary",w);
return 0;
}
I've tried several aproaches, some based on the following links, but this always happens. This version is based on the last one.
Quick Way to Implement Dictionary in C
http://www.sparknotes.com/cs/searching/hashtables/section3.rhtml
http://www.seg.rmit.edu.au/code/zwh-ipl/hashtable.c
Problem 1
This is not right.
hash_tab = malloc(sizeof(WORD) * size); /*allocate memory */
It should be
hash_tab = malloc(sizeof(WORD*) * size); /*allocate memory */
To avoid errors like this, you should get in the habit of using
hash_tab = malloc(sizeof(*hash_tab) * size); /*allocate memory */
Problem 2
for (; i<tab_size; i++) /* initialize elements */
hash_tab[i]=NULL;
should be
for (; i<size; i++) /* initialize elements */
hash_tab[i]=NULL;
This is a potential problem. It may not be a real problem in your case if size and tab_size happens to be equal. But as a matter of style, you should use the second block of code.

realloc (again)

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;
}

comparing array of strings

#include<reg51.h>
#include<string.h>
#include"_LCD_R8C.c"
unsigned char c[12];
unsigned char chr[11];
void serial_int (void) interrupt 4
{
if (RI==1)
{
chr[11] = SBUF;
RI = 0;
TI = 0;
}
}
int main()
{
unsigned char a[2][11]={"$0016221826","$0123456789"};
int i,j;
lcd_init();
lcd_clear();
SCON = 0x50;
TMOD = 0x20;
TH1 = 0xFD;
ET0 = 0;
TR1 = 1;
RI = 1;
ES = 1;
EA = 1;
for(j=0;j<1;j++)
{
for(i=0;i<=10;i++)
{
c[i]=chr[i];
}
c[11]='\0';
}
for(i=0;i<=1;i++)
{
j=strcmp(a[i],c); /* !!! Here is the problem !!! */
if(j==0)
{
lcd_printxy(1,1,"yes");
}
else
{
lcd_printxy(1,6,"no");
}
}
}
I am getting the display as "no", please let me know what is the problem?
the problem might be
1) the received array of characters are not converted to string, or
2) the received array of characters are converted to string but not able to compare with the available string..
please go through the program
One obvious bug for starters - change:
unsigned char a[2][11]={"$0016221826","$0123456789"};
to:
unsigned char a[2][12]={"$0016221826","$0123456789"};
(You need to allow room for the terminating '\0' in each string - I'm surprised your compiler didn't complain about this ?)
Also, this line in your interrupt handler is wrong:
chr[11] = SBUF;
Several problems with this - char only has storage for 11 chars, not 12, and you probably want to be accumulating characters from index 0 and then bumping the index, otherwise you're just overwriting the same character each time.
Looking at the rest of the code there are so many other problems that I think you may need to take a step back here and start with a simpler program - get that working first and then add to it in stages.
You might also want to get a decent introductory book on C and study it as there are lots of very basic mistakes in the code, so you might benefit from a better understanding of the language itself.
You only assign a value to chr[11], the rest of the array is uninitialized and will contain random data. You then copy this array containing random data to c (you could use e.g. memcpy here instead of looping yourself), and finally you compare the complete contents of c (which is random data) with one of the entries in a. So it's kind of natural that the result of that comparison will be that the strings are not equal.
Edit: A redesign of the program in the question
Your program has too many problems to be easily fixed, so I decided to try and rewrite it:
#include <reg51.h>
#include <string.h>
#include "_LCD_R8C.c"
#define INPUT_LENGTH 11
#define ACCEPTABLE_INPUT_COUNT 2
char input[INPUT_LENGTH]; /* The input from the serial port */
int input_pos = 0; /* Current position to write in the input buffer */
int input_done = 0; /* 0 = not done yet, 1 = all input read */
void serial_int (void) interrupt 4
{
if (!input_done && RI == 1)
{
/* Put the input at next position in the input buffer */
/* Then increase the position */
input[input_pos++] = SBUF;
RI = 0;
TI = 0;
/* Check if we have received all input yet */
if (input_pos >= INPUT_LENGTH)
input_done = 1;
}
}
int main()
{
/* Array of data that this programs thinks is acceptable */
/* +1 to the input length, to fit the terminating '\0' character */
char acceptable_inputs[ACCEPTABLE_INPUT_COUNT][INPUT_LENGTH + 1] = {
"$0016221826", "$0123456789"
};
iny acceptable_found = 0; /* Acceptable input found? */
/* Initialization */
lcd_init();
lcd_clear();
SCON = 0x50;
TMOD = 0x20;
TH1 = 0xFD;
ET0 = 0;
TR1 = 1;
RI = 1;
ES = 1;
EA = 1;
/* Wait until we have received all input */
while (!input_done)
; /* Do nothing */
/* Check the received input for something we accept */
for (int i = 0; i < ACCEPTABLE_INPUT_COUNT; i++)
{
if (memcmp(acceptable_inputs[i], input, INPUT_LENGTH) == 0)
{
/* Yes, the data received is acceptable */
acceptable_found = 1;
break; /* Don't have to check any more */
}
}
if (acceptable_found)
lcd_printxy(1, 1, "Yes");
else
lcd_printxy(1, 1, "No");
return 0;
}

Resources