I'm trying to get input from the user while allocating it dynamically and then "split" it using strtok.
Main Questions:
Im getting an infinite loop of "a{\300_\377" and ",".
Why do i get a warning of "Implicitly declaring library function "malloc"/"realoc" with type void"
Other less important questions:
3.i want to break, if the input includes "-1", how do i check it? As you can see it breaks now if its 1.
4.In the getsWordsArray() i want to return a pointer to an array of strings. Since i dont know how many strings there are do i also need to dynamically allocate it like in the getInput(). (I dont know how many chars are there in each string)
int main(int argc, const char * argv[])
{
char input = getInput();
getWordsArray(&input);
}
char getInput()
{
char *data,*temp;
data=malloc(sizeof(char));
char c; /* c is the current character */
int i; /* i is the counter */
printf ("\n Enter chars and to finish push new line:\n");
for (i=0;;i++) {
c=getchar(); /* put input character into c */
if (c== '1') // need to find a way to change it to -1
break;
data[i]=c; /* put the character into the data array */
temp=realloc(data,(i+1)*sizeof(char)); /* give the pointer some memory */
if ( temp != NULL ) {
data=temp;
} else {
free(data);
printf("Error allocating memory!\n");
return 0 ;
}
}
printf("list is: %s\n",data); // for checking
return *data;
}
void getWordsArray(char *input)
{
char *token;
char *search = " ,";
token = strtok (input,search);
while (token != NULL ) {
printf("%s\n",token);
token = strtok(NULL,search);
}
}
EDIT:
i noticed i forgot to "strtok" command so i changed it to token = strtok(NULL,search);
I still get wierd output on the printf:
\327{\300_\377
Change:
int main(int argc, const char * argv[])
{
char input = getInput();
getWordsArray(&input);
}
to:
int main(int argc, const char * argv[])
{
char *input = getInput();
getWordsArray(input);
}
with a similar to the return value of getInput():
char *getInput()
{
// ...
return data;
}
In your code, you were only saving the first character of the input string, and then passing mostly garbage to getWordsArray().
For your malloc() question, man malloc starts with:
SYNOPSIS
#include <stdlib.h>
For your getchar() question, perhaps see I'm trying to understand getchar() != EOF, etc.
Joseph answered Q1.
Q2: malloc and realoc returns type void *. You need to explicitly convert that to char *. Try this:
data = (char *) malloc(sizeof(char));
Q3: 1 can be interpreted as one character. -1, while converting to characters, is equivalent to string "-1" which has character '-' and '1'. In order to check against -1, you need to use strcmp or strncmp to compare against the string "-1".
Q4: If you are going to return a different copy, yes, dynamically allocate memory is a good idea. Alternatively, you can put all pointers to each token into a data structure like a linked list for future reference. This way, you avoid making copies and just allow access to each token in the string.
Things that are wrong:
Strings in C are null-terminated. The %s argument to printf means "just keep printing characters until you hit a '\0'". Since you don't null-terminate data before printing it, printf is running off the end of data and just printing your heap (which happens to not contain any null bytes to stop it).
What headers did you #include? Missing <stdlib.h> is the most obvious reason for an implicit declaration of malloc.
getInput returns the first char of data by value. This is not what you want. (getWordsArray will never work. Also see 1.)
Suggestions:
Here's one idea for breaking on -1: if ((c == '1') && (data[i-1] == '-'))
To get an array of the strings you would indeed need a dynamic array of char *. You could either malloc a new string to copy each token that strtok returns, or just save each token directly as a pointer into input.
Related
So I'm doing a few practice questions for a final exam coming up. and I'm having a lot of trouble with dynamic memory.
So the question wants to basically parse through 2 different sources and compare them to find the similar words. (one from a csv file and one from a cgi input)
so I figured I'd use malloc/calloc to put a string in each array slot and then compare each slot. but I'm having some issues with my code:
char buffer[100],buffer2[100],tmp[100],line[100];
char *token,*tok,*input;
int main()
{
char s[100]="search=cat+or+dog+store";
char *search=(char*)calloc(10,sizeof(char));
strcpy(buffer,s);
sscanf(buffer,"search=%s",buffer);
int k=0;
tok=strtok(buffer,"+");
while(tok!=NULL)
{
strcpy(&search[k],tok);
k++;
tok=strtok(NULL,"+");
}
printf("%d\n",k);
strcpy(&search[k],"\0");
***printf("%s",&search[0]);
printf("%s",&search[1]);
printf("%s",&search[2]);
printf("%s",&search[3]);***
char* csv=(char*)calloc(10,sizeof(char));
char tmp2[100];
FILE *fp;
fp=fopen("web.csv","r");
while(fgets(line,sizeof(line),fp)!=NULL)
{
strcpy(buffer2,line);
token=strtok(buffer2,",");
while(token!=NULL)
{
strcpy(csv,token);
csv++;
token=strtok(NULL,",");
}
strcpy(csv,"\0");
free(csv);
free(search);
return(0);
}
the part i put between * * i put in order to test if the strings were put inside the calloc. but nothing prints out or smt weird prints out. the same code was used for the latter bottom part and they are both either empty or only printing out weird fragmented part of the code.
when i put the free(csv) and free(search), it says that "pointer being freed was not allocated". i looked it up but I can't seem to find a answer to why it does this?
thank you!
You seem to be trying to create an array of pointers. So let me show you what that looks like
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXT 10
int main( void )
{
char s[100]="search=cat+or+dog+store";
char buffer[100];
char **search = calloc( MAXT, sizeof(char *) );
if ( sscanf( s, "search=%s", buffer ) != 1 )
return 1;
int t = 0;
char *token = strtok( buffer, "+" );
while ( token != NULL && t < MAXT )
{
search[t++] = token;
token = strtok( NULL, "+" );
}
for ( int i = 0; i < t; i++ )
printf( "%s\n", search[i] );
free( search );
}
Things to look for
search is declared as a char ** meaning pointer to a char pointer, which can be used like an array of char pointers
in the calloc, the allocation is for 10 items of type char *, i.e. an array of 10 pointers
in the sscanf, the input and output strings must not be the same string. I changed the arguments so that s is the input, and buffer is the output. Also, you should always check that the return value from sscanf is equal to the number of items requested.
in the while loop, I've added a check t < MAXT to avoid running past the end of the pointer array
search is an array of pointers, and strtok returns a pointer, so the line search[t++]=token; stores the pointer in the array. The string itself is still in the buffer.
This line here:
strcpy(&search[k],"\0");
What you are doing is adding the string literal "\0" to the k'th position in memory (which works... but gross). I believe you are trying to do this:
search[k] = '\0'
Notice the single quotes ('') that is a character rather than a string literal.
You should also not be casting a malloc: char *search = (char *)malloc(...)
MAINLY:
You should also consider that printf("%s", string) only prints up until the nearest terminator ('\0') in 'string'. Reference here.
So check what you are buffering, and see if you can build any new conclusions...
And, when you print your string, you only need to printf("%s", search)
I highly suggest you use malloc(), especially for strings. Because calloc() initiates all values to zero. And '\0' == 0, so you could be making it more difficult for yourself to diagnose.
I'm getting a core dump that I have no clue how to solve. I have searched other questions and googled my problem but I just can't figure out how to solve this...
Here is the code:
const char checkExtension(const char *filename)
{
const char *point = filename;
const char *newName = malloc(sizeof(filename-5));
if((point = strrchr(filename,'.palz')) != NULL )
{
if(strstr(point,".palz") == 0)
{
strncpy(newName, filename, strlen(filename)-5);
printf("%s\n",newName ); // the name shows correctly
return newName; // Segmentation fault (core dumped)
}
}
return point;
}
The function was called char checkExtensions(const char *filename). I added the const due the solutions that I have found online but so far I haven't been able to make it work...
Thank you in advance for the help!
You have many problems with your code. Here are some of them:
Your function returns char which is a single character. You need to return a pointer to an array of characters, a C string.
You don't allocate the right amount of memory. You use sizeof() on a pointer which yields the size of a pointer.
You make it impossible for the caller to know whether or not to deallocate memory. Sometimes you heap allocate, sometimes not. Your approach will leak.
You pass '.palz', which is a character literal, to strrchr which expects a single char. What you mean to pass is '.'.
A better approach is to let the caller allocate the memory. Here is a complete program that shows how:
#include <string.h>
#include <stdio.h>
void GetNewFileName(const char *fileName, char *newFileName)
{
const char *dot = strrchr(fileName, '.');
if (dot)
{
if (strcmp(dot, ".palz") == 0)
{
size_t len = dot - fileName;
memcpy(newFileName, fileName, len);
newFileName[len] = 0;
return;
}
}
size_t len = strlen(fileName);
memcpy(newFileName, fileName, len);
newFileName[len] = 0;
return;
}
int main(void)
{
char fileName[256];
char newFileName[256];
strcpy(fileName, "foo.bar");
GetNewFileName(fileName, newFileName);
printf("%s %s\n", fileName, newFileName);
strcpy(fileName, "foo.bar.palz");
GetNewFileName(fileName, newFileName);
printf("%s %s\n", fileName, newFileName);
strcpy(fileName, "foo.bar.palz.txt");
GetNewFileName(fileName, newFileName);
printf("%s %s\n", fileName, newFileName);
return 0;
}
Output
foo.bar foo.bar
foo.bar.palz foo.bar
foo.bar.palz.txt foo.bar.palz.txt
Note that strcmp compares sensitive to letter case. On Windows file names are insensitive to case. I will leave that issue for you to deal with.
By letting the caller allocate memory you allow them to chose where the memory is allocated. They can use a local stack allocated buffer if they like. And it's easy for the caller to allocate the memory because the new file name is never longer than the original file name.
This is most probably your problem:
const char *newName = malloc(sizeof(filename-5));
First, filename is of type const char *, which means that (filename - 5) is also of this type. Thus, sizeof(filename - 5) will always return the size of the pointer datatype of your architecture (4 for x32, 8 for x64).
So, depending on your architecture, you are calling either malloc(4) or malloc(8).
The rest of the code doesn't even compile and it has serious string manipulation issues, so it's hard to tell what you were aiming at. I suppose the strncpy() was copying too much data into newName buffer, which caused buffer overflow.
If your goal was to extract the filename from a path, then you should probably just use char *basename(char *path) for that.
Several pretty major problems with your code. Making it up as I type, so it may not fix everything first time right away. Bear with me.
You need to return a char *, not a char.
const char checkExtension(const char *filename)
{
const char *point = filename;
You malloc memory but the instruction flow does not guarantee it will be freed or returned.
sizeof(filename) should be strlen(filename), minus 5 (sans extension) but +1 (with terminating 0).
const char *newName = malloc(sizeof(filename-5));
strrchr searches for a single character. Some compilers allow "multibyte character constants", but they expect something like 2 -- not five. Since you know the length and start of the string, use strcmp. (First ensure there are at least 5 characters. If not, no use in testing anyway.)
if((point = strrchr(filename,'.palz')) != NULL ) {
Uh, strstr searches for a string inside a string and returns 0 if not found (actually NULL). This contradicts your earlier test. Remove it.
if(strstr(point,".palz") == 0)
{
strncpy copies n characters, but famously (and documented) does not add the terminating 0 if it did not get copied. You will have to this yourself.
.. This is actually where the malloc line should appear, right before using and returning it.
strncpy(newName, filename, strlen(filename)-5);
printf("%s\n",newName ); // the name shows correctly
return newName; // Segmentation fault (core dumped)
}
}
You return the original string here. How do you know you need to free it, then? If you overwrote a previous char * its memory will be lost. Better to return a duplicate of the original string (so it can always be freed), or, as I'd prefer, return NULL to indicate "no further action needed" to the calling routine.
return point;
}
Hope I did not forget anything.
There are several problems with your code:
Wrong return type:
const char checkExtension(const char *filename){
You need to return a pointer (const char *), not a single character.
Not enough memory:
const char checkExtension(const char *filename){
const char *newName = malloc(sizeof(filename-5));
You are allocating the size of a pointer (char *), which is typically 4 or 8. You need to call strlen() to find out the size of the string:
Multibyte character:
if((point = strrchr(filename,'.palz')) != NULL ) {
'.palz' is a multibyte character literal. While this is allowed in C, its value is implementation-defined and might not do what you expect. String literals use double quotes (".palz").
No terminating zero:
strncpy(newName, filename, strlen(filename)-5);
Note that strncpy() doesn't necessarily null-terminate the target string. It write at most strlen(filename)-5 characters. If the source string contains more characters (as in your case), it will not write a terminating zero.
I'm not sure what exactly you're trying to do. Perhaps something like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
const char *checkExtension(const char *filename)
{
int len = strlen (filename)-5;
char *newName = NULL; /* return NULL on allocation failure. */
if (len > 0 && !strcmp (filename+len, ".palz")) {
newName = malloc (len+1);
if (newName) {
memcpy (newName, filename, len);
newName[len] = 0;
}
}
return newName;
}
int main (int ac, char **av)
{
if (ac > 1) {
const char *p = checkExtension (av[1]);
puts (p ? p : "NULL");
} else {
puts ("?");
}
return 0;
}
Multiple errors here. You have not said what you are trying to achieve, that has to be implied from the code. You have declared point and newName as const, yet reassigned with a value. You have tested strstr() == 0 when it should be strstr() == NULL. You have called strrchr(filename,'.palz') but sent a string instead of a char. Then you have returned the local variable point which goes out of scope before you get a chance to use it, because it was not declared as static. So it's irrelevant whether you returned a char or a char pointer.
char *checkExtension(const char *filename) {
// if filename has extension .palz return a pointer to
// the filename stripped of extension or return NULL
char *point;
static char newName[512];
strncpy(newName, filename, 512);
if ((point = strstr(newName, ".palz")) != NULL ) {
if (strlen (point) == 5) {
*point = 0; // string terminator
// printf("%s\n",newName ); // use only for debugging
return newName;
}
}
return NULL;
}
Alternatively provide a string the function can modify -
char *checkExtension(const char *filename, char *newName) { ... }
Alternatively provide a filename the function can modify -
char *checkExtension(char *filename) {
char *point;
if ((point = strstr(filename, ".palz")) != NULL ) {
if (strlen (point) == 5) {
*point = 0; // string terminator
return filename;
}
}
return NULL;
}
So I'm new to C and the whole string manipulation thing, but I can't seem to get strtok() to work. It seems everywhere everyone has the same template for strtok being:
char* tok = strtok(source,delim);
do
{
{code}
tok=strtok(NULL,delim);
}while(tok!=NULL);
So I try to do this with the delimiter being the space key, and it seems that strtok() no only reads NULL after the first run (the first entry into the while/do-while) no matter how big the string, but it also seems to wreck the source, turning the source string into the same thing as tok.
Here is a snippet of my code:
char* str;
scanf("%ms",&str);
char* copy = malloc(sizeof(str));
strcpy(copy,str);
char* tok = strtok(copy," ");
if(strcasecmp(tok,"insert"))
{
printf(str);
printf(copy);
printf(tok);
}
Then, here is some output for the input "insert a b c d e f g"
aaabbbcccdddeeefffggg
"Insert" seems to disappear completely, which I think is the fault of strcasecmp(). Also, I would like to note that I realize strcasecmp() seems to all-lower-case my source string, and I do not mind. Anyhoo, input "insert insert insert" yields absolutely nothing in output. It's as if those functions just eat up the word "insert" no matter how many times it is present. I may* end up just using some of the C functions that read the string char by char but I would like to avoid this if possible. Thanks a million guys, i appreciate the help.
With the second snippet of code you have five problems: The first is that your format for the scanf function is non-standard, what's the 'm' supposed to do? (See e.g. here for a good reference of the standard function.)
The second problem is that you use the address-of operator on a pointer, which means that you pass a pointer to a pointer to a char (e.g. char**) to the scanf function. As you know, the scanf function want its arguments as pointers, but since strings (either in pointer to character form, or array form) already are pointer you don't have to use the address-of operator for string arguments.
The third problem, once you fix the previous problem, is that the pointer str is uninitialized. You have to remember that uninitialized local variables are truly uninitialized, and their values are indeterminate. In reality, it means that their values will be seemingly random. So str will point to some "random" memory.
The fourth problem is with the malloc call, where you use the sizeof operator on a pointer. This will return the size of the pointer and not what it points to.
The fifth problem, is that when you do strtok on the pointer copy the contents of the memory pointed to by copy is uninitialized. You allocate memory for it (typically 4 or 8 bytes depending on you're on a 32 or 64 bit platform, see the fourth problem) but you never initialize it.
So, five problems in only four lines of code. That's pretty good! ;)
It looks like you're trying to print space delimited tokens following the word "insert" 3 times. Does this do what you want?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char str[BUFSIZ] = {0};
char *copy;
char *tok;
int i;
// safely read a string and chop off any trailing newline
if(fgets(str, sizeof(str), stdin)) {
int n = strlen(str);
if(n && str[n-1] == '\n')
str[n-1] = '\0';
}
// copy the string so we can trash it with strtok
copy = strdup(str);
// look for the first space-delimited token
tok = strtok(copy, " ");
// check that we found a token and that it is equal to "insert"
if(tok && strcasecmp(tok, "insert") == 0) {
// iterate over all remaining space-delimited tokens
while((tok = strtok(NULL, " "))) {
// print the token 3 times
for(i = 0; i < 3; i++) {
fputs(tok, stdout);
}
}
putchar('\n');
}
free(copy);
return 0;
}
I need a function/method that will take in a char array and set it to a string read from stdin. It needs to return the last character read as its return type, so I can determine if it reached the end of a line or the end of file marker.
here is what I have so far, and I kind of based it off of code from here
UPDATE: I changed it, but now it just crashes upon hitting enter after text. I know this way is inefficient, and char is not the best for EOF check, but for now I am just trying to get it to return the string. I need it to do it in this fashion and no other fashion. I need the string to be the exact length of the line, and to return a value that is either the newline or EOF int which I believe can still be used in a char value.
This program is in C not C++
char getLine(char **line);
int main(int argc, char *argv[])
{
char *line;
char returnVal = 0;
returnVal = getLine(&line);
printf("%s", line);
free(line);
system("pause");
return 0;
}
char getLine(char **line) {
unsigned int lengthAdder = 1, counter = 0, size = 0;
char charRead = 0;
*line = malloc(lengthAdder);
while((charRead = getc(stdin)) != EOF && charRead != '\n')
{
*line[counter++] = charRead;
*line = realloc(*line, counter);
}
*line[counter] = '\0';
return charRead;
}
Thank you for any help in advance!
You're assigning the result of malloc() to a local copy of line, so after the getLine() function returns it's not modified (albeit you think it is). What you have to do is either return it (as opposed to use an output parameter) or pass its address (pass it 'by reference'):
void getLine(char **line)
{
*line = malloc(length);
// etc.
}
and call it like this:
char *line;
getLine(&line);
Your key problem is that line pointer value does not propagate out of the getLine() function. The solution is to pass pointer to the line pointer to the function as a parameter instead - calling it like getLine(&line); while the function would be defined as taking parameter char **line. In the function, on all places where you now work with line, you would work with *line instead, i.e. dereferencing the pointer to a pointer and working with the value of the variable in main() where the pointer leads. Hope this is not too confusing. :-) Try to draw it on a piece of paper.
(A tricky part - you must change line[counter] to (*line)[counter] because you first need to dereference the pointer to the string, and only then to access a specific character in the string.)
There is a couple of other problems with your code:
You use char as the type for charRead. However, the EOF constant cannot be represented using char, you need to use int - both as the type of charRead and return value of getLine(), so that you can actually distringuish between a newline and end of file.
You forgot to return the last char read from your getLine() function. :-)
You are reallocating the buffer after each character addition. This is not terribly efficient and therefore is a rather ugly programming practice. It is not too difficult to use another variable to track the amount of space allocated and then (i) start with allocating a reasonable chunk of memory, e.g. 64 bytes, so that ideally you will never reallocate (ii) enlarge the allocation only if you need to based on comparing the counter and your allocation size tracker. Two reallocation strategies are common - either doubling the size of the allocation or increasing the allocation by a fixed step.
The way you use realloc is not correct. If it returns NULL then the memory block will be lost.
It is better to use realloc in this way:
char *tmp;
...
tmp = realloc(line, counter);
if(tmp == NULL)
ERROR, TRY TO SOLVE IT
line = tmp;
I'm creating a char* which essentially will be treated as an string. The string is suppose to be used over and over again. Everytime I'm attempting to check with the while loop and see if its correct to the "quit"...
*I keep getting a segmentation fault...What am I doing wrong -- Pretty idiotic mistake - possibly?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[])
{
char* input = (char*)malloc(sizeof(char));
input = "CONTINUE";
while(strcmp(input, "quit") != 0)
{
printf("%s", "System: ");
scanf("%s", input);
}
return 0;
}
Two problems I see in first look:
char* input = (char*)malloc(sizeof(char));
You are assigning your pointer a memory of just one character. It should have enough memory to hold your string not just one character.
You should copy the string in to the allocated buffer using strcpy. Not aassign a string literal to your pointer. Note that modifying such a string literal results in Undefined Behavior.
input = "CONTINUE";
Correct way of doing the above 2 are:
char* input = (char*)malloc(sizeof(MAX_LENGTH));
strcpy(input, "YOURSTRING");
Where MAX_LENGTH is sufficient to hold your input strings.
You are trying to change a literal which is illegal.
Try:
char* input = (char*)malloc(sizeof(char)); /* You need more than one char. */
char* input = (char*)malloc(LENGTH); /* Allocate `LENGTH` chars. */
input = "CONTINUE"; /* You can't write (scanf) over a string literal. */
strcpy(input, "CONTINUE"); /* Now it's legal to write over `input`. */
Other points to watch out for:
Using scanf with a bare "%s" is unsafe. You should use something like "%10s" to make sure a potentially malicious user doesn't enter more than 10 characters
Did you know sizeof(char) isn't needed since it's guaranteed to be 1 ?