I am trying to write a program to count letters in every word of a given string and append the count to the word.
Example - I/p: The cake O/p: The3 cake4
In my logic, I want to reset a counter variable named icnt of type integer(which is done) & and an array named temp of type character(which is not working).
I did some research on StackOverflow and implemented memset to reset but looks like it didn't work for me!
Kindly correct my program if there are mistakes.
#include<stdio.h>
#include<string.h>
void fun(char*,char*);
char ch[50];
char temp[10]={0};
int main()
{
printf("Enter string :");
scanf("%[^'\n']s",&ch);
fun(ch,temp);
}
void fun(char *ptr,char *tptr)
{
int icnt = 0;
while(*ptr!='\0')
{
if(*ptr!=' ')
{
*tptr = *ptr;
tptr++;
icnt++;
}
else if(*ptr==' ')
{
printf("In IF bcoz of space\n");
printf("%s %d\n",temp,icnt);
icnt = 0;
//temp[10] = {0}; //*
memset(temp,0,10); //*
//Tried reseting in both the above ways *
}
ptr++;
}
if(*ptr=='\0')
{
printf("%s%d\n",temp,icnt);
}
}
Output of the above program: The34
Looks like nothing is getting stored the 2nd time in the temp variable
Excepted output: The3 cake4
printf("%s %d\n",temp,icnt);
temp[10] = {0};
Your function takes temp as argument and accesses that global variable directly. This is not a bug up to here but it makes no sense: The function will only work if the tptr argument has a certain value. So why using an argument at all?
temp[10] = {0};
memset(temp,0,10);
Because your function overwrites the content of that array with the line *tptr = *ptr it is not neccessary to initialize the temp array at all!
Instead you only have to ensure that the last value in the array is a zero. You do this the following way:
*tptr = 0;
printf(...,temp,...);
Theoretically you could also use memset but this is not neccessary and will take more computation time.
Output of the above program: The34
Your program increments tptr (tptr++) but it never re-sets it!
Therefore the temp array has the following content:
/* Before the first printf: */ "The\0\0\0\0\0\0\0"
/* After memset: */ "\0\0\0\0\0\0\0\0\0\0"
/* Before the second printf: */ "\0\0\0cake\0\0\0"
If your input is longer than 10 characters your program may even crash because it writes to memory it is not allowed to write to.
printf will write an empty string the second time because the first character of the temp array is NUL...
Kindly correct my program if there are mistakes.
I would do the following changes:
I would use two different variables for tptr:
void fun(char *ptr,char *output)
{
char *tptr = output; /* here */
Instead of referencing temp in the function I would reference the argument which I would never modify. Before printf I would write the NUL byte to the end of the array and after printf I would reset the write pointer (tptr):
*tptr = *ptr; /* This remains tptr; does not become output */
*tptr++; /* This also */
...
*tptr = 0; /* This is new: Ensure the last byte is NUL */
printf(...,output,...); /* Not test, but output */
tptr = output; /* This is new: Reset the write pointer */
/* memset(...) - No longer needed */
#include<stdio.h>
#include<string.h>
void fun(char*,char*);
char ch[50];
char temp[10]={0};
int main()
{
printf("Enter string :");
scanf("%[^'\n']s",ch);
fun(ch,temp);
}
void fun(char *ptr,char *tptr)
{
int icnt = 0;
while(*ptr!='\0')
{
if(*ptr!=' ')
{
*tptr = *ptr;
tptr++;
icnt++;
}
else if(*ptr==' ')
{
printf("In IF bcoz of space\n");
printf("%s %d\n",temp,icnt);
icnt = 0;
//temp[10] = {0}; //*
memset(temp,0,10);
tptr = temp; /* The tptr was not reinitialised to point to base address */
//Tried reinitialization in both the above ways *
}
ptr++;
}
if(*ptr=='\0')
{
printf("%s%d\n",temp,icnt); /* Here you are printing from the base address.*/
}
}
The print was done from the base address of the array and the after reinitialisation the tptr was not set to point to the base address of the array. Code attached should work fine.
You have to add after "inct = 0;" the instruction : " tptr = temp;" because if you don't add it you will go out from the memory space of the table "temp". And you have also to add "*tptr='\0' " just before "printf("%s %d\n",temp,icnt);".
Related
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.
I've been trying to work out exactly what this function's purpose is I've come across..
The code intentionally has bad code practices, so I am trying to figure out if this is one of them.
Here is the function:
void clear_mem(char *memblock, int siz) {
register int i;
for (i=0; i<=siz;i++)
*(memblock+i) = 0;
}
The function is called within the following function:
char *get_argument(char line[], int argno){
char *argument = malloc(512);
char clone[512];
strncpy(clone, line, strlen(line)+1);
int current_arg = 0;
char *splitted = strtok(clone, " ");
while (splitted != NULL){
if (splitted[0] != ':'){
current_arg++;
}
if (current_arg == argno+1){
clear_mem(argument, 512); //Here
strncpy(argument, splitted, strlen(splitted)+1);
return argument;
free(argument);
}
splitted = strtok(NULL, " ");
}
if (current_arg != argno){
argument[0] = '\0';
}
free(argument);
return argument;
}
Thanks in advance!
In this code:
for (i=0; i<=siz;i++)
*(memblock+i) = 0;
memblock+i adds the integer i to the pointer memblock. The result points i elements beyond where memblock points. Since memblock is a pointer to char, the result points i characters beyond where memblock points.
Then *(memblock+i) refers to the character at that address. *(memblock+i) is equivalent to memblock[i]. *(memblock+i) = 0 sets the character to zero.
So the effect of this code is to set all characters indexed by i during the loop to zero. It clears a block of memory.
The for (i=0; i<=siz;i++) causes the loop to iterate with i taking all values from zero up to and including siz. Thus, siz+1 characters will be set to zero.
We can see this is an error because get_argument allocates 512 bytes for argument and then later calls clear_mem(argument, 512), which clears 513 bytes. The resulting behavior is not defined by the C code.
I need to create program that takes input from stdin in this format:
abcde //number of characters in word = number of words => square shape
fghij
klmno
pqrst
uvwxy
// \n separates first half from second
word1word //any amount of characters, any amount of words
word
word2
sdf
// \n to end input
My code works, but only about 50% of the time. I have couple of example inputs, that I use for testing, but for some of them my readwords function fails.
Here is my function, that reads words. Since I have no idea how many words or how long they are going to be, I use dynamic arrays and getchar() function.
void readWords(char **p,int *n,int w) /* before calling: n = 50; w = 20; p = 50x20 char array */
{
int i = 0,j = 0,x;
char tmp,prevtmp;
while (1)
{
prevtmp = tmp;
tmp = getchar();
if ((prevtmp == '\n' && tmp == '\n') || feof(stdin))
break; /* no more words to read */
if (tmp == '\n') /* end of word */
{
p[i][j] = '\0'; /* add \0 to create string format */
i++;
j = 0;
if (i == *n) /* if there is more words than there is space for them, double the size */
if (realloc(p,*n*2) != NULL)
*n*=2;
continue;
}
p[i][j] = tmp;
j++;
if (j == w) /* if width of word is larger than allocated space, double it */
{
for (x = 0; x < *n;x++);
if(realloc (p[x],w*2) != NULL);
w=w*2;
}
}
*n = i;
}
This is example of input for which this works (note:this function only reads second half after line with only \n):
dsjellivhsanxrr
riemjudhgdffcfz
<skipping>
atnaltapsllcelo
ryedunuhyxhedfy
atlanta
saltlakecity
<skipping 15 words>
hartford
jeffersoncity
And this is input that my function doesn't read properly:
<skipping>
...oywdz.ykasm.pkfwb.zazqy...
....ynu...ftk...zlb...akn....
missouri
delaware
<skipping>
minnesota
southdakota
What my function reads from this input:
e
yoming
xas
florida
lvania
ana
ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
There is no difference between those two inputs (except different words and different amount and length of words), the first half gets read properly no matter what, but only the second half bugs out. How do I fix this?
P.S. sorry for long post, in case you want to see full input without skipped bytes, here is pastebin: http://pastebin.com/hBGn2tej
realloc() returns the address of the newly allocated memory, it does not update the argument passed into it. So this (and the other use of realloc()) is incorrect:
if (realloc(p,*n*2) != NULL)
and will results in the code accessing memory incorrectly, causing undefined behaviour. Store the result of realloc() to a temporary variable and check for non-NULL before updating p. The argument to realloc() also indicates the number of bytes, not the number of elements so the size argument calculation is incorrect as p is an array of char* so it should be realloc(p, sizeof(char*) * (*n * 2));. However, the change to p would not be visible to the caller. Also note that the only legal arguments to realloc() are pointers obtained from a previous call to malloc(), realloc() or calloc(). The comment p = 50x20 char array in the code suggests this is not the case.
Here is a small example that allocates an array of char* which should be helpful:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void f(char*** p)
{
/* Allocate space for two 'char*' elements.
Add a NULL pointer element as sentinel value
so caller knows where to find end of list. */
*p = malloc(sizeof(**p) * 3);
/* Allocate space for the two strings
and populate. */
(*p)[0] = malloc(10);
(*p)[1] = malloc(10);
strcpy((*p)[0], "hello");
strcpy((*p)[1], "world");
(*p)[2] = NULL;
/* Add a third string. */
char** tmp = realloc(*p, sizeof(**p) * 4);
if (tmp)
{
*p = tmp;
(*p)[2] = malloc(10);
strcpy((*p)[2], "again");
(*p)[3] = NULL;
}
}
int main()
{
char** word_list = 0;
f(&word_list);
if (word_list)
{
for (int i = 0; word_list[i]; i++)
{
printf("%s\n", word_list[i]);
free(word_list[i]);
}
}
free(word_list);
return 0;
}
Additionally:
prevtmp has an unknown value upon its first use.
getchar() actually returns an int and not a char.
The following program stores every word and then prints them with a number of occurrences.
Global typedef declaration:
typedef struct {
char * word;
int occ;
}
words;
words *data=NULL;
I have a problem with the search function. I've created a function returning int that looks like this: (max is the constantly updated size of an array of structures, that's why I call search function after EOF is reached.)
int search(char *word,int max)
{
int i;
for(i=0; i<max; i++)
{
if(!strcmp(data[i].word,word)) return i;
}
return -1;
}
But I noticed I'm supposed to write a search function having that prototype:
struct abc *find(char *word)
So I've created the following code:
struct words *findword(char *word)
{
struct words *ptr;
for (ptr = data; ptr != NULL; ptr++) { /* IS THE STOP CONDITION OK? */
if (strcmp(word, ptr->word) == 0)
return ptr;
}
return NULL;
}
And I receive many errors during compilation:
reverse.c: In function ‘findword’:
reverse.c:73: warning: assignment from incompatible pointer type
reverse.c:73: error: increment of pointer to unknown structure
reverse.c:73: error: arithmetic on pointer to an incomplete type
reverse.c:74: error: dereferencing pointer to incomplete type
reverse.c: In function ‘main’:
reverse.c:171: error: ‘which’ undeclared (first use in this function)
reverse.c:171: error: (Each undeclared identifier is reported only once
reverse.c:171: error: for each function it appears in.)
make: * [reverse.o] Error 1
which is an int variable assigned to the return of my firstly written search function.
The error with which is easily fixed, but I don't know how to replace that (solution working with my base search function):
data[which].occ++;
How to fix it so that it'll work with my new approach to search?
EDIT
main() added:
int main(int argc, char **argv)
{
char *word;
words *temp;
int c,i,num;
/*int which;*/
FILE *infile;
if(argc!=2) {}
if((infile=fopen(argv[1],"r"))==NULL) {}
num=0;
while(1)
{
c=fgetc(infile);
if(c==EOF) break;
if(!isalpha(c)) continue;
else ungetc(c,infile);
word=getword(infile);
word=convert(word);
/*which=search(word,num);*/
if(findword(word))
{
if(!(temp=realloc(data,sizeof(words)*(num+1))))
{}
else
data=temp;
data[num].word=strdup(word);
data[num].occ=1;
num++;
}
else
data[which].occ++;
free(word);
}
sort(num-1);
for(i=0;i<num;i++)
{}
free(data);
if(fclose(infile))
{}
return 0;
}
I've left {} for the irrelevant pieces of code eg. error handling.
EDIT2
The things I'm asking for above, are fixed. However, I get a seg fault now.
I'll give a link to the whole code, I don't want to put it in an edited post since it'd create a big mess. Seg fault is caused by lines 73 and 152 (strcmp is not working somehow). Hope that full code will be easier to understand.
FULL CODE
The problems are with your findword function, lets go through all the lines
struct words *ptr;
This is not what you ment to do. The typedef you used in defining the structure allows you to not need to write struct anymore. This is why you're getting the error: reverse.c:73: error: increment of pointer to unknown structure. What you want is just:
words *ptr;
Next, the loop:
for(ptr=data; //This is fine, you're assigning your local ptr to the global data. I assume that's something valid
ptr != NULL; //That could OK too... we can loop while ptr is not NULL
ptr++) //This line makes no sense...
You may want to look up how for loops work again, the point is you're incrementing something until it hits a condition. ptr++ will move where you're pointing too, so you'll no longer be pointing to your structure.
I need to see your main() function to understand what you're trying to accomplish, but based on the prototype you have to follow, I think the easiest solution would be something like:
void main()
{
// init your vars
bool more_words_to_add = true;
words *ptr = NULL;
int i;
// populate your array of words
while(more_words_to_add) {
for(i = 0; i<max; i++) {
if(ptr = findword("word")) //if we find the word
ptr->occ++; //increment the number of times we found it
else {
//I don't know what you want to do here, it's not clear what your goal is.
//Add the new word to your array of words and set occ to 1,
//then increment max because there's one more word in your array?
}
}
//get the next word to fine, or else set more_words_to_add = false to break
}
}
If this type of solution is what you're looking to do, then you can adjust your findwords function to be very simple:
struct words *findword(char *word)
{
words *ptr = data;
if (strcmp(word, ptr->word) == 0)
return ptr;
return NULL;
}
EDIT: For your new error I suspect the problem is with your memory allocation, see this short example of using your structure:
words *findword(char *word)
{
words *ptr = data;
if(strcmp(word, ptr->word) == 0)
return ptr;
return NULL;
}
int main(){
words *ptr;
data = realloc(data, sizeof(words));
data->word = "hello"; //DO NOT SKIP THESE LINES
data->occ = 0; //DO NOT SKIP THESE LINES
if(ptr = findword("hello")) {
ptr->occ++;
printf("I found %d %s's\n",ptr->occ, ptr->word);
}
}
mike#linux-4puc:~> ./a.out
I found 1 hello's
You can see here that you need to alloc some memory for the global structure then you can store data in it and pass pointers to it.
EDIT 2:
Your main() code does this:
if((ptr = findword(word)))
{
//do stuff
}
else
ptr->occ++;
That's not going to work because if findword() fails it returns NULL, so in the if check ptr is set to NULL, then in the else you're trying to deference NULL. If (and keep in mind I'm not really reading your logic so this is up to you) you really want to increment ptr->occ if a word is not found then you want this instead:
if(findword(word))
{
ptr = findword(word);
//do stuff
}
else
ptr->occ++; //increments the current ptr's occ, no new ptr was assigned.
for (ptr = data; ptr != NULL; ptr++) {
/* IS THE STOP CONDITION OK? */
No. Your pointer just keeps getting incremented. The only thing that would make it NULL in that code is integer overflow. You could look at what it points to, and see if that is NULL, IF you preset the data area to 0's:
#define NUM_WORDS 100
data = calloc(NUM_WORDS,sizeof(words));
Or
#define NUM_WORDS 100
int bytes = NUM_WORDS * sizeof(words);
data = malloc(bytes);
memset(data,0,bytes);
....
for (ptr = data; ptr->word != NULL; ptr++) {
If you don't want to preset the data area to 0 then you will have to pass the current amount of structs currently held in the data area to your function in order to know how much to loop.
There's no such thing as struct words in your program; there's an unnamed struct type, and a typedef words to that type. Either use struct words or words consistently.
You'll then need to replace
data[which].occ++;
with
result->occ++;
where result is the return value from your new search function.
I want to pass the contents of an array to another method and have that method print out the entire array - how would i do this?
Currently:
I'm returning an array from a function.
char* search_value(struct PDB *llist)
{
int realID = -7;
int x = 0;
int task = 0;
char *received;
char theMessage[100];
theMessage[0] = '\0';
printf("Your choice: `Search'\n");
printf("Enter the value you want to find: ");
scanf("%d", &task);
while(llist->data1 != NULL)
{
if(task == llist->taskID)
{
realID = llist->taskID;
strcpy(theMessage, llist->data1);
break;
}
}
return theMessage;
}
i'm getting the return value:
void getMessage(const int GET_MESSAGE)
{
char * received = NULL;
int x = 0;
received = search_value(llist);
printf("%s", received);
}
I want to somehow print the entire value (rather than just the first value to which the pointer is pointing at - how would i do this?
A few corrections and it should work:
// - struct contents shouldn't be changed by the function, make its pointer const.
// - pass a pointer to an allocated array as parameter
char* search_value(const struct PDB *llist, char* theMessage)
{
int realID = -7;
int x = 0;
int task = 0;
char *received;
theMessage[0] = '\0';
printf("Your choice: `Search'\n");
printf("Enter the value you want to find: ");
scanf("%d", &task);
while(llist->data1 != NULL)
{
if(task == llist->taskID)
{
realID = llist->taskID;
strcpy(theMessage, llist->data1);
break;
}
}
return theMessage;
}
void getMessage(const int GET_MESSAGE)
{
char received[100]; // allocate the array outside the function
int x = 0;
search_value(llist, received); // pass a pointer to the first element
printf("%s", received);
}
You have an issue with variable scope here: theMessage is local to the function search_value, so you're returning a pointer to an array which no longer exists once the function completes.
Instead you should use malloc() to allocate the space for theMessage and then subsequently free() it later on outside of the function when you're finished with it — however this can often lead to memory leaks if you're not diligent about cleaning up after yourself.
You can allocate the memory like so:
char * message = malloc(100);
One alternative would be to allocate the buffer in getMessage() and pass a pointer to the buffer into search_value which could then write into it:
void getMessage(const int GET_MESSAGE)
{
char received[100];
int x = 0;
search_value(llist, received);
printf("%s", received);
}
void search_value(struct PDB *llist, char * buffer)
{
// write to buffer
}
Another option is to declare a char * pointer inside getMessage(), pass a pointer to a pointer into search_value() and again use malloc() to allocate space for the buffer.
Finally, this is a minor style criticism, but you'd do well to learn to stick to one convention for naming your functions, search_value and getMessage are not consistent names, and this will irk many a coder that you work with.
You have several problems with your code. I'm guessing that you want to search a list for some value, then return that value.
The first problem is that you do not actually iterate over the list, but only check the same item over and over again. The other problem is that you return a pointer to a local variable. This is undefined behavior, because as soon as the function returns the memory the pointer points to can be used for something else.
I suggest you change your code as follows:
char *search_value(struct PDB *llist, char *theMessage, size_t theMessageMaxLength)
{
int realID = -7;
int task = 0;
printf("Your choice: `Search'\n");
printf("Enter the value you want to find: ");
scanf("%d", &task);
while(llist != NULL && llist->data1 != NULL)
{
if(task == llist->taskID)
{
realID = llist->taskID;
strncpy(theMessage, llist->data1, theMessageMaxLength);
theMessage[theMessageMaxLength] = '\0';
break;
}
llist = llist->next; /* Assuming the field is named "next" */
}
return theMessage;
}
void getMessage(const int GET_MESSAGE)
{
char *received = NULL;
char theMessage[100];
/* Subtract 1 from the size, for the terminating '\0' */
received = search_value(llist, theMessage, sizeof(theMessage) - 1);
printf("%s", received);
}
the array you are returning is local to that function. Either the calle function shall provide the array in which it expects the values or use static array.