I'm trying to write a piece of code in C which takes an input(as string) from the file and adds it at the end of another string and prints it.
The program compiles perfectly in Visual Studio 2013 but crashes during run.
Can anyone please help me identify the problem with the code.
Here is the code:
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>
int main()
{
char input[255];
char str1 = "caingb";
char str2 = " ";
FILE *f;
f = fopen("rockyou.txt", "rt");
while (fgets(input, sizeof(input), f))
{
str2 = str1 + input;
printf("%s", str2);
}
fclose(f);
return(0);
}
These are the three warning messages I'm getting:
Line 8: warning C4047: 'initializing' : 'char' differs in levels of indirection from 'char [7]
Line 9: warning C4047: 'initializing' : 'char' differs in levels of indirection from 'char [2]
Line 14: warning C4047: '=' : 'char' differs in levels of indirection from 'char *
The easiest way to concatenate strings is with asprintf (for allocating sprintf, if you have it):
char *result;
char *a = "foo";
char *b = "barco";
asprintf(&result, "%s%s", a, b);
Note how easily this can deal with three or more strings, or interspersing stuff like in
asprintf(&result, "C:/%s/%s.exe", a, b);
Yours crashes because of the misdeclarations of str1 and str2 as char instead of pointers to char (that's what the warning messages tell you in some hard to understand way). Furthermore, C is not Java, and string concatenation is not done with +.
A good programmer would test result being non-NULL and probably free(result) once no longer needed.
If you like to concatenate strings in C you have to use strcat .
If you like to copy one string to another you have to use strcpy ...
In a few words for string assignments in C you have to use a built in function (strcpy, strcat, memcpy, snprintf etc). You can't just simply use the = operator as you do!
So your code would be something like this:
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>
int main()
{
char input[255];
char *str1 = (char*)malloc(sizeof(char)*10);
strcpy(str1,"caingb");
char *str2=(char)0; //point to null..for initilization!
FILE *f;
f = fopen("rockyou.txt", "rt");
while (fgets(input, sizeof(input), f))
{
str2=(char*)malloc(sizeof(char)*(strlen(str1)+strlen(input))+1);
strcpy(str2,str1);
strcat(str2,input);
printf("%s", str2);
free(str2);
}
fclose(f);
free(str1);
return(0);
}
At the 2 lines of the code above that malloc function appears, you are basically allocating space on the memory, to store the variables that malloc gets called from. In your for the second malloc you need the size of each character (sizeof(char)) multiplied times the amount of the length of string 1 (strlen(str1)) plus the length of string 2 ('strlen(input)). That will give you the required memory in HEAP of your program to storestr2. For the first malloc i am just multiplying it by 10, since"caingb"` i 6 chars (so i am reserving a few more bytes...not a good strategy if you want to be a good coder ;-) ). Later by calling free you are de-allocating the space you reserved with malloc, because if you don't it will stick like that into memory even after program is done executing!
A more abstract idea of malloc (for example purposes) would be
char* string=malloc(15);
...and like that you allocated 15 bytes of memory for the pointer char *string. So in whatever this pointer points to, must not exceeds 15 bytes, or you will have memory leaks (aka segmantation faults in C).
For further reading, search yourself about stack and heap of a program in C.
Also always try out the man pages through the terminal of yours ( in Linux) . An example of this would be:
man malloc
..and voilla you will get a manual page for what malloc does. It might seems a little bit harsh to read those man pages at first, but give time to yourself! There is also an online version of them at http://man.he.net/
P.S. I haven't run the above code, but thats the general idea.
Related
I expected to get errors in following code, but I did not. I did not use & sign. Also I am editing array of chars.
#include <stdio.h>
int main()
{
char name[10] ="yasser";
printf("%s\n",name);
// there is no error ,
// trying to edit array of chars,
// also did not use & sign.
scanf("%s",name);
// did not use strcpy function also.
printf("%s\n",name);
return 0;
}
I expected to get errors in following code, but I did not.I did not use & sign.
scanf("%s",name);
That's totally ok as name is already the address of the character array.
It sounds like you have several questions:
calling scanf("%s", name) should have given an error, since %s expects a pointer and name is an array? But as others have explained, when you use an array in an expression like this, what you always get (automatically) is a pointer to the array's first element, just as if you had written scanf("%s", &name[0]).
Having scanf write into name should have given an error, since name was initialized with a string constant? Well, that's how it was initialized, but name really is an array, so you're free to write to it (as long as you don't write more than 10 characters into it, of course). See more on this below.
Characters got copied around, even though you didn't call strcpy? No real surprise, there. Again, scanf just wrote into your array.
Let's take a slightly closer look at what you did write, and what you didn't write.
When you declare and initialize an array of char, it's completely different than when you declare and initialize a pointer to char. When you wrote
char name[10] = "yasser";
what the compiler did for you was sort of as if you had written
char name[10];
strcpy(name, "yasser");
That is, the compiler arranges to initialize the contents of the array with the characters from the string constant, but what you get is an ordinary, writable array (not an unwritable, constant string constant).
If, on the other hand, you had written
char *namep = "yasser";
scanf("%s", namep);
you would have gotten the problems you expected. In this case, namep is a pointer, not an array. It's initialized to point to the string constant "yasser", which is not writable. When scanf tried to write to this memory, you probably would have gotten an error.
When you pass arrays to functions in C, they decay to pointers to the first item.
Therefore for:
char name[] ="yasser";
scanf("%s", name) is the same as scanf("%s", &name[0]) and either of those invocations should send shivers down your spine, because unless you control what's on your stdin (which you usually don't), you're reading a potentially very long string into a limited buffer, which is a segmentation fault waiting to happen (or worse, undefined behavior).
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp) {
char *myName = (char *) calloc(10, sizeof(char));
*(myName)='K'; *(myName+1)='h'; *(myName+2)='a'; *(myName+3)='l'; *(myName+4)='i'; *(myName+5)='d';
printf("%s\n",myName);
scanf("%s",myName);
printf("%s\n",myName);
return (EXIT_SUCCESS);
}
#include <stdio.h>
#include <string.h>
int main()//fonction principale
{
char name[10] ="yasser";
int longeur=0;
printf("%s\n",name);
scanf("%s",name);
longeur = strlen(name);
for (int i=0;i<longeur;i++) {
printf("%c",*(name+i));
}
return 0;}
I am a beginner with c, and I am having a problem with scanf and strings.
here is an example I wrote of my problem.
#include <stdio.h>
#include <string.h>
int main(void)
{
char* string;
scanf("%s", &string);
if (strcmp(string, "Foo") == 0) //segmentation fault here
printf("Bar");
}
basically, this code compiles, but when I run it I get a segmentation fault in strcmp()
if I replace the "string" in that line with "&string" it works, but I get this error from the compiler
/usr/include/stdio.h:362:12: note: expected 'const char * __restrict__' but argument is of type 'char **'
which makes me think that this solution is not really ideal.
also If I declare string like this:
char string[100];
that works without any warnings, but that is also not ideal because I am not sure how large the string is going to be.
Is there a better solution I'm missing here, or are these my only options?
thank you.
char* string;
scanf("%s", &string);
string is not pointing to any valid memory location. Allocate memory using malloc to an array of characters and copy input to it. Make sure allocated memory has space for null termination character. Remember to free the memory to avoid leaks.
Just try that code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char* string;
string=(char *)malloc(3); /*allocate the memory to string cahr pointer(default pointer point to single byte and if you print pointer variable don't used & character)*/
scanf("%s", string);
if (strcmp(string, "Foo") == 0)
printf("Bar\n");
}
While declaring a char *. it will not having any memory location. so you have to allocate a
memory location before you use that variable.
char *p;
p=malloc(sieof(char) * size of string);
then you use scanf() function. it will work properly.
when we are accessing a unknown memory(ie unallocated memory). then it will through the segmentation fault
Below is my code
#import <stdio.h>
#import <string.h>
int main(int argc, const char *argv[])
{
char *str = "First string";
char *str2 = "Second string";
strcpy(str, str2);
return 0;
}
It compiles just fine without any warning or errors, but when I run the code I get the error below
Bus error: 10
What did I miss ?
For one, you can't modify string literals. It's undefined behavior.
To fix that you can make str a local array:
char str[] = "First string";
Now, you will have a second problem, is that str isn't large enough to hold str2. So you will need to increase the length of it. Otherwise, you will overrun str - which is also undefined behavior.
To get around this second problem, you either need to make str at least as long as str2. Or allocate it dynamically:
char *str2 = "Second string";
char *str = malloc(strlen(str2) + 1); // Allocate memory
// Maybe check for NULL.
strcpy(str, str2);
// Always remember to free it.
free(str);
There are other more elegant ways to do this involving VLAs (in C99) and stack allocation, but I won't go into those as their use is somewhat questionable.
As #SangeethSaravanaraj pointed out in the comments, everyone missed the #import. It should be #include:
#include <stdio.h>
#include <string.h>
There is no space allocated for the strings. use array (or) pointers with malloc() and free()
Other than that
#import <stdio.h>
#import <string.h>
should be
#include <stdio.h>
#include <string.h>
NOTE:
anything that is malloc()ed must be free()'ed
you need to allocate n + 1 bytes for a string which is of length n (the last byte is for \0)
Please you the following code as a reference
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
//char *str1 = "First string";
char *str1 = "First string is a big string";
char *str2 = NULL;
if ((str2 = (char *) malloc(sizeof(char) * strlen(str1) + 1)) == NULL) {
printf("unable to allocate memory \n");
return -1;
}
strcpy(str2, str1);
printf("str1 : %s \n", str1);
printf("str2 : %s \n", str2);
free(str2);
return 0;
}
str2 is pointing to a statically allocated constant character array. You can't write to it/over it. You need to dynamically allocate space via the *alloc family of functions.
string literals are non-modifiable in C
Your code attempts to overwrite a string literal. This is undefined behaviour.
There are several ways to fix this:
use malloc() then strcpy() then free();
turn str into an array and use strcpy();
use strdup().
this is because str is pointing to a string literal means a constant string ...but you are trying to modify it by copying .
Note : if it would have been an error due to memory allocation it would have been given segmentation fault at the run time .But this error is coming due to constant string modification or you can go through the below for more details abt bus error :
Bus errors are rare nowadays on x86 and occur when your processor cannot even attempt the memory access requested, typically:
using a processor instruction with an address that does not satisfy
its alignment requirements.
Segmentation faults occur when accessing memory which does not belong to your process, they are very common and are typically the result of:
using a pointer to something that was deallocated.
using an uninitialized hence bogus pointer.
using a null pointer.
overflowing a buffer.
To be more precise this is not manipulating the pointer itself that will cause issues, it's accessing the memory it points to (dereferencing).
Let me explain why you do you got this error "Bus error: 10"
char *str1 = "First string";
// for this statement the memory will be allocated into the CODE/TEXT segment which is READ-ONLY
char *str2 = "Second string";
// for this statement the memory will be allocated into the CODE/TEXT segment which is READ-ONLY
strcpy(str1, str2);
// This function will copy the content from str2 into str1, this is not possible because you are try to perform READ WRITE operation inside the READ-ONLY segment.Which was the root cause
If you want to perform string manipulation use automatic variables(STACK segment) or dynamic variables(HEAP segment)
Vasanth
Whenever you are using pointer variables ( the asterix ) such as
char *str = "First string";
you need to asign memory to it
str = malloc(strlen(*str))
None of the mentioned solution, worked for me as I couldn't find where the error was coming from. So, I simply deleted my node_modules and re-installed it. And the error disappeared; my code started working again
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num = 1;
char* test[8];
sprintf(test[0],"%d",num);
printf("%s\n",test[0]);
}
char *test[8] is an array of 8 char *, or pointers to strings, and since you don't specify, they're all set to garbage values. So sprintf is trying to write data to who-knows-where.
You should use char test[8] instead, which allocates an array of 8 char, and then sprintf(test, "%d", num);.
UPDATE: If you want to use char * pointers, you should allocate space:
char *test = malloc(8 /* see note below */);
sprintf(test, "%d", num);
If you want to use an array of char * pointers, it works the same:
char *test[8]; // 8 pointers to strings
test[0] = malloc(8); // allocate memory for the first pointer
sprintf(test[0], "%d", num);
Keep in mind you would have to call malloc for each of test[0] through test[7] individually.
Also, as mentioned in the comments, if your compiler supports it you should use snprintf(). It's like sprintf but it takes an extra parameter which is the size of the buffer:
snprintf(test, 8, "%d", num);
and guarantees not to use more space than you allow it. It's safer, and if you need to, snprintf returns the amount of space it actually wanted, so if you gave it too little room you can realloc and try again.
Note: some will say this should be malloc(8 * sizeof(char)) (or sizeof *test). They are wrong (in my objectively-correct opinion; note the sarcasm)! sizeof(char) is guaranteed to be 1, so this multiplication is unnecessary.
Some advocate the usage of TYPE *p = malloc(x * sizeof *p) so that if TYPE changes, you'll only need to change it in one place, and sizeof *p will adapt. I am one of these people, but in my opinion you will rarely need to upgrade a char * to another type. Since so many functions use char * and would need to be changed in such an upgrade, I'm not worried about making malloc lines more flexible.
sprintf() does not allocate space for the string; you must do that yourself beforehand.
Look at your warnings:
test.c: In function ‘main’:
test.c:8: warning: ‘test[0]’ is used uninitialized in this function
You allocate an array of 8 pointers, but use one without initializing it. You must call malloc and store the result in test[0] before you can write to the memory pointed to by test[0]. You free it at the end.
A useful function, present in GNU and BSD, is asprintf, which will call malloc for you to allocate enough memory for the formatted string:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int num = 1;
char* test[8];
asprintf(&test[0],"%d",num);
printf("%s\n",test[0]);
free(test[0]);
return 0;
}
(Note that you pass the address of your pointer to asprintf — since your pointer is test[0], its address is &test[0].)
You did allocate space but you you are passing the wrong thing. Try this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num = 1;
char test[8];
sprintf(test,"%d",num);
printf("%s\n",test);
}
int main()
{
char *str[5];
sprintf(str[0], "%d",55);
printf("%s\n",str[0]);
return 0;
}
This will be work. But, if you specify variable instead of integer constant value show the segmentation fault will be occur. This error will be happened at the time of sprintf function execution. Because user space memory access.
I am trying to read a large list of English words from a text file to array of strings. The number of words is 2016415, and maximum length of a word is 69 characters.
If I define array like "char data[2016415][70]; " then I get stack overflow when I run the program.
So I am trying to use calloc() instead, however I can't understand how should I type-cast it so that it becomes equivalent to "char data[2016415][70];".
The following program returns "passing arg 1 of `fgets' makes pointer from integer without a cast" warning during compiling. And when I execute it, it gets "Exception: STATUS_ACCESS_VIOLATION" problem.
Can you help me?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
char *data; //data[2016415][70];
int i;
FILE *fsol;
fsol = fopen("C:\\Downloads\\abc\\sol2.txt","r");
data = (char*) calloc(2016415,70);
for(i=0;i<2016415;i++){
fgets(data[i] , 70 , fsol);
}
fclose(fsol);
return 0;
}
calloc just allocates a big swath of memory - not an array of pointers to other arrays.
fgets expects a pointer to the memory location it should dump it's stuff at.
So instead of giving it the contents of data[i], you want to give it the address of data[i] so it can put its stuff there.
fgets(&data[i], 70, fsol);
You'll probably also need to adjust your loop so that it goes up by 70-odd characters at a time rather than one.
Okay, sorry about the previous suggestion. I forgot how horrible arrays can be. This one is tested with a small data set of 10 words, but it should scale to your word count. Note that fgets() seems to pull in the line endings as part of the preceding word.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_WORD_CNT 2016415
#define MAX_WORD_LEN 70
int main(void)
{
char *data; //data[2016415][70];
int i;
FILE *fsol;
fsol = fopen("C:\\Downloads\\abc\\sol2.txt","r");
data = (char*) calloc(MAX_WORD_CNT, MAX_WORD_LEN);
// check for valid allocation
if (data == NULL)
{
return 1;
}
for(i=0; i<MAX_WORD_CNT; i++)
{
fgets(&data[i * MAX_WORD_LEN], MAX_WORD_LEN, fsol);
}
fclose(fsol);
return 0;
}
Here's how I would allocate the array
char **data = malloc(MAX_WORD_CNT * sizeof(char *));
for(int i = 0; i < MAX_WORD_CNT; i++)
data[i] = malloc(MAX_WORD_LEN);
you might want to add some error checking for malloc though.
data is a pointer to char (also addressable as an array of char), so data[i] is a single char. fgets expects a pointer to char but you're passing it a single char; that's why you're getting the warning, you're trying to use a char (integer) as a pointer.
When you run the program, it then takes that single char argument and interprets it as a pointer to char, hence the access violation because the value of that char is not a valid address.
So, in your loop you should pass fgets a pointer into data and increment that by 70 with each iteration. You can use the "pointer to an array element" form &data[i] and increment i, or the simple pointer form, with another pointer variable initially set to data, and itself incremented.
The answer is simple: you DON'T cast it. Casting the results of malloc/calloc/etc. has no purpose but can have the side-effect of hiding a major bug if you forgot to include stdlib.h. The return type of these allocation functions, which is void *, will automatically be cast to whatever you need.
If you really want to know the type, it's (char (*)[70]). But please don't actually obfuscate your program by writing that. (Unless you're actually writing C++, in which case you should have tagged your question C++ and not C, or better yet used new.)