Im trying to make the program that extract filenames by inputing some folderpath.
The outcome is fine, but the problem is at the end of outcome, there's some segmentation fault that i cant figure out.
Here's what I wrote in.
#include <stdio.h>
#include <dirent.h>
int main() {
char folderpath;
printf("enter the path : \n");
scanf("%s",&folderpath);
DIR *d;
struct dirent *dir;
d = opendir(&folderpath);
if (d)
{
while((dir= readdir(d)) != NULL)
{
printf("%s\n", dir->d_name);
}
closedir(d);
};
return 0;
}
And, result is like
enter the path : /Users/gui/Desktop/extract/extract
.
..
main
main.c
Segmentation fault: 11
Sorry for asking really simple question like this, which I tried hard to figure out but I cant.
Thanks for reading this question.
Best Regard.
When you call scanf with the %s format specifier, it expects a pointer to an array of characters. What you're passing is the address of a single character. So it writes past the memory location of that variable into whatever happens to be next to it. This invokes undefined behavior.
You need pass a character array to scanf:
char folderpath[256];
printf("enter the path : \n");
scanf("%s",folderpath);
...
d = opendir(folderpath);
you cannot do this
char folderpath;
printf("enter the path : \n");
scanf("%s",&folderpath);
You have reserved space for one character. YOu need
char folderpath[MAX_PATH];
printf("enter the path : \n");
scanf("%s",&folderpath);
When you declare char foldrpath only one byte of memory is allocated that is you can store only one character. When you try to store more than one byte it results in to segmentation fault (access of the memory location out side your process space in this case). So try to use an array like char folderpath[MAXFOLDERLENGTH] else you can get the contiguous block of bytes by calling malloc like
char foldrpath = (char) malloc(MAXFOLDERLENGTH), this malloc assigns the memory in Heap area where as the former declaration will give you memory allocated in stack area. Hope this helps
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
i have been trying c for a while now but i can not handle pointer arrays.
for example
char *word;
char *container[100];
In the below for loop i am appending single characters of in string to temp then i want to add to *container[100] if the delimiter . is appeared.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main()
{
int z = 0;
int k=0;
char *word;
char *container[100];
char *in = " First Word . Second Word";
for(k=0; k<strlen(in); k++)
{
//using . as a delimiter
if(in[k]=='.')
{
container[z] = word;
printf("%s\n", container[z]); //<---- this prints okey inside loop
z++;
memset(word,0,strlen(word));
}
else
{
//appending characters to temp, using some method
snprintf(word + strlen(word), (sizeof word) - strlen(word), "%c", in[k]);
}
}
//doesnt print anything outside the loop
printf("Does it print: %s\n", container[0]);
printf("Doest it print: %s\n", container[1]);
return 0;
}
when i try to print the words in container it doesnt show anything:
printf("%s\n", container[0]);
printf("%s\n", container[1]);
i think i have to do some sort of Dynamic Allocation. But i dont know how.
The pointer word is not initialized before you start using it. This causes undefined behaviour. If you are lucky you get a segmentation fault so you are made aware of the problem and can fix it. If you are unlucky it kinda works but gives weird side effects, like mysteriously overwriting other variables.
Also, sizeof word returns the pointer size and not the size of the (allocated) memory area it points to.
The problems with word can be fixed by making it an array:
char word[100];
Now word contains 100 bytes of memory that we can safely write to, and sizeof word will evaluate to 100.
The next problem is when you assign the container pointers to point to word. This will not make a copy of the string contained in word. Later when you overwrite the contents of word, the contents of container[i] will also be overwritten since it points to the same memory location. You can use strdup to create a dynamically allocated copy:
container[z] = strdup(word);
Note: strdup() is a POSIX function and not part of the C specification. On platforms that don't have strdup() you can use malloc+strcpy to perform the same task.
I'm working my way through a book on operating systems, and some of the book's sample code is giving me a runtime segmentation fault. I'm somewhat new to C from Java, and I'm hoping someone can point me in the right direction.
The little program here is supposed to generate a simple shell, read a command in and fork a process to execute it. The problem is in the book's code itself, at the "scanf" function call; when I input something at the "osh>" prompt, I get a segmentation fault.
Form what I know about C, I think memory might need to be allocated for the args array, but since it's an array declared directly in the main function, I think I might not need to. I figure that if I did, it would be in the book's code.
Anyway, here's the code that generates the fault:
char* args[MAX_LINE/2 + 1]; /* command line (of 80) has max of 40 arguments */
int should_run = 1;
int i, upper;
while (should_run){
printf("osh>");
fflush(stdout);
scanf("%s", args); /* THIS CAUSES SEGFAULT */
char* localArgs[3];
char* pch;
/* ... */
Thanks in advance for the help. Learning memory management in C is quite the journey.
You are passing an array of pointers to scanf(), it expects an array of char.
An example of how to use scanf() correctly to scan a text string would be
char string[100];
if (scanf("%99s", string) == 1)
{
printf("scanned string: %s\n", string);
}
else
{
printf("error: unexepected error in `scanf()'.\n);
}
Read the link throughly to understand why I wrote this code like I did, if you do you will start to understand how scanf() works, and when you do you will start writing more robust programs, and probably stop using scanf() too.
char* args[MAX_LINE/2 + 1];
This is creating an array of size (MAX_LINE/2+1) of char pointers. If you want to use one of these char pointers as string, you must allocate them:
args[which_arg] = malloc(arg_max_length*sizeof(char));
And to read a text into it:
scanf("%s", args[which_arg]);
#include<stdio.h>
int main()
{
char *arg[10],*c;
int count=0;
FILE *fp,*fq;
printf("Name of the file:");
scanf("%s",arg[1]);
fp=fopen(arg[1],"w");
printf("\t\t%s",arg[1]);
printf("Input the text into the file\n");
printf("Press Ctrl+d to the stop\n");
while((*c=getchar())!=EOF)
{
fwrite(c,sizeof(char),1,fp);
count++;
}
return 0;
}
Change this line
char *arg[10],*c;
to
char arg[1000],c;
This line
scanf("%s",arg[1]);
to
scanf("%s",arg);
And this line
while((*c=getchar())!=EOF)
to
while((c=getchar())!=EOF)
Explanation:
char *c; is not a character. It's a pointer to a character. It starts out just pointing to a random bit of memory, which will often be filled with random data - whatever was most recently written there.
char c; is a character.
The same thing applies to char *arg[10]. It's an array of ten pointers. They point into random memory, filled with random data.
Note: my change is not best practice. If someone were to type in a filename 1000 characters or more long, you'd write over the end of the arg buffer. Depending on what you're doing, this can be a security bug.
In
char *arg[10];
you define an array of 10 pointers to char but you do not initialize its elements. arg[0], arg[1], ..., arg[9] will all have undefined values.
Then, you try to enter a string into one of those undefined values. Lucky you, you got a segmentation fault. Had you been unlucky, your program could format your hard disk instead.
char *arg[10] ;
arg is array of char pointers. You need to assign them memory locations using malloc before taking input -
scanf("%s",arg[1]); // arg[1] is not assigned to point to any memory location
// and is what causing the segmentation fault.
So do -
arg[1] = malloc( stringLengthExpectedToEnter + 1 ) ; // +1 for termination character
Should do like that with the rest of array elements too (or) simply change char*arg[10] to char arg[10] and make sure to enter only enter 9 characters.
I think you are confusing between a pointer and a normal variable.
int *ptr;
ptr is variable that can hold the address of an integer variable. Memory is allocated to for ptr variable to hold an integer address. That's it. ptr is in an uninitalized state and is pointing no where (or) might be pointing to garbage. Dereferencing an uninitialized pointer's behavior is undefined and you are lucky enough if it gives a segmentation-fault.
Now, you need to assign it a valid memory location using malloc.
ptr = malloc( sizeof(int) ) ; // Allocates number of bytes required to hold an
// integer and returns it's address.
So, ptr is now pointing to memory location acquired from free store that can hold an integer. Such acquired locations from free stored must be freed using free, else you have classical problem of memory leak. It is good practice to initialize pointer to NULL while declaration.
int *ptr = NULL ;
Hope it helps !
scanf("%d", ptr) ; // Notice that & is not required before ptr. Because ptr
// content is address itself.
A normal variable story is entirely different. When declared -
int var ;
Memory is allocated to var to hold an integer. So, you can directly assign it an integer.
#include<stdio.h>
int main()
{
char arg[10],c;
int count=0;
FILE *fp;
printf("Name of the file:");
scanf("%s",arg);
fp=fopen(arg,"w");
printf("\t\t%s",arg);
printf("Input the text into the file\n");
printf("Press Ctrl+d to the stop\n");
while((c=getchar())!=EOF)
{
fwrite(&c,sizeof(char),1,fp);
count++;
}
if(fp != NULL){
fclose(fp);
fp = NULL;
}
return 0;
}
I'm trying to write a program that reads in entries from a file into a dynamically allocated array of structures using input redirection. My program compiles fine but I'm getting a segmentation fault and I'm having trouble finding the cause.
Here's my Program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct StudentData
{
char* name;
char* major;
double gpa;
} Student;
int main()
{
Student* data = (Student*)malloc(sizeof(Student)*5);
int i;
for(i = 0; i < 5; i++)
{
// allocate memory for name and read input
data[i].name = malloc(50);
*(data+i)->name == scanf("%s", (char*)&data[i].name);
// allocate memory for major and read input
data[i].major = malloc(30);
*(data+i)->major == scanf("%s", (char*)&data[i].major);
// read input for gpa
(data+i)->gpa == scanf("%lf", &data[i].gpa);
//print array
printf("%s\n%s\n%f\n", data[i].name, data[i].major, data[i].gpa);
}
}
Any clues? If it seems obvious it's because I'm relatively new to C!
This line:
*(data+i)->name == scanf("%s", (char*)&data[i].name);
Ignoring the weird and void == for a moment, &data[i].name is wrong since you're taking an address of a pointer. data[i].name would be sufficient here, since the name field is already an address scanf can write into.
And the cast to (char*) is what probably shuts the compiler up about it - did you enter it for this purpose :-) ? Because &data[i].name has the type char**, which scanf wouldn't accept, unless you forcefully casted it to char*.
As a general advice, try to avoid scanf - it leads to very unsafe code (as you've just seen!) Instead, use fgets to read a line (from the standard input too) and then break this line into its constituents. This may initially take a bit more code to implement, but leads to much safer and more predictable code.
*(data+i)->name == scanf("%s", (char*)&data[i].name);
What are you comparing the return value of scanf for? Just remove the first part. Also, data[i].name is already a pointer, so you shouldn't take the address once again. It should just be:
scanf("%s", data[i].name); // no & because name is already a pointer
And similarly:
scanf("%s", data[i].major);
scanf("%lf", &data[i].gpa); // & here because gpa is just a double
There is some unnecessary code being used with scanf, like *(data+i)->name ==. That doesn't do anything useful (and is probably causing the segfault). If it weren't causing access errors, it would compare the return value of scanf with the pointer and then ignore the result of the comparison. (A decent compiler would have warned about this.)
After getting rid of the excess code, it will be technically okay, except there is nothing to prevent buffer overrun. That's done either by controlling the input data, or adding limits to the lengths of the strings, like with scanf("%50s", data[i].name);
&data[i].name and &data[i].major are of type char **, so you cannot safely cast it to char *.
Losing the ampersand will correct your error.
There are also other logical errors with the use of scanf(), but that's probably overwhelming - it'd be nice if you revisited this code once you entered a name of more than 50 characters.
I'm fairly competent in a few scripting languages, but I'm finally forcing myself to learn raw C. I'm just playing around with some basic stuff (I/O right now). How can I allocate heap memory, store a string in the allocated memory, and then spit it back out out? This is what I have right now, how can I make it work correctly?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *toParseStr = (char*)malloc(10);
scanf("Enter a string",&toParseStr);
printf("%s",toParseStr);
return 0;
}
Currently I'm getting weird output like '8'\'.
char *toParseStr = (char*)malloc(10);
printf("Enter string here: ");
scanf("%s",toParseStr);
printf("%s",toParseStr);
free(toParseStr);
Firstly, the string in scanf is specifies the input it's going to receive. In order to display a string before accepting keyboard input, use printf as shown.
Secondly, you don't need to dereference toParseStr since it's pointing to a character array of size 10 as you allocated with malloc. If you were using a function which would point it to another memory location, then &toParseStr is required.
For example, suppose you wanted to write a function to allocate memory. Then you'd need &toParseStr since you're changing the contents of the pointer variable (which is an address in memory --- you can see for yourself by printing its contents).
void AllocateString(char ** ptr_string, const int n)
{
*ptr_string = (char*)malloc(sizeof(char) * n);
}
As you can see, it accepts char ** ptr_string which reads as a pointer which stores the memory location of a pointer which will store the memory address (after the malloc operation) of the first byte of an allocated block of n bytes (right now it has some garbage memory address since it is uninitialized).
int main(int argc, char *argv[])
{
char *toParseStr;
const int n = 10;
printf("Garbage: %p\n",toParseStr);
AllocateString(&toParseStr,n);
printf("Address of the first element of a contiguous array of %d bytes: %p\n",n,toParseStr);
printf("Enter string here: ");
scanf("%s",toParseStr);
printf("%s\n",toParseStr);
free(toParseStr);
return 0;
}
Thirdly, it is recommended to free memory you allocate. Even though this is your whole program, and this memory will be deallocated when the program quits, it's still good practice.
You need to give scanf a conversion format so it knows you want to read a string -- right now, you're just displaying whatever garbage happened to be in the memory you allocated. Rather than try to describe all the problems, here's some code that should at least be close to working:
char *toParseStr = malloc(10);
printf("Enter a string: ");
scanf("%9s", toParseStr);
printf("\n%s\n", toParsestr);
/* Edit, added: */
free(toParseStr);
return 0;
Edit: In this case, freeing the string doesn't make any real difference, but as others have pointed out, it is a good habit to cultivate nonetheless.
Using scanf() (or fscanf() on data you don't control) with a standard "%s" specifier is a near-certain way to get yourself into trouble with buffer overflows.
The classic example is that it I enter the string "This string is way more than 10 characters" into your program, chaos will ensue, cats and dogs will begin sleeping together and a naked singularity may well appear and consume the Earth (most people just state "undefined behaviour" but I think my description is better).
I actively discourage the use of functions that cannot provide protection. I would urge you (especially as a newcomer to C) to use fgets() to read your input since you can control buffer overflows with it a lot easier, and it's more suited to simple line input than scanf().
Once you have a line, you can then call sscanf() on it to your heart's content which, by the way, you don't need to do in this particular case since you're only getting a raw string anyway.
I would use:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFSZ 10
int main(int argc, char *argv[]) {
char *toParseStr = malloc(BUFFSZ+2);
if (toParseStr == NULL) {
printf ("Could not allocate memory!\n");
return 1;
}
printf ("Enter a string: ");
if (fgets (toParseStr, BUFFSZ+2, stdin) == NULL) {
printf ("\nGot end of file!\n");
return 1;
}
printf("Your string was: %s",toParseStr);
if (toParseStr[strlen (toParseStr) - 1] != '\n') {
printf ("\nIn addition, your string was too long!\n");
}
free (toParseStr);
return 0;
}
You don't need an & before toParseStr in scanf as it is already a pointer
also call free(toParseStr) afterwards
First, the errors that was keeping your program from working: scanf(3) takes a format-string, just like printf(3), not a string to print for the user. Second, you were passing the address of the pointer toParseStr, rather than the pointer toParseStr.
I also removed the needless cast from your call to malloc(3).
An improvement that your program still needs is to use scanf(3)'s a option to allocate memory for you -- so that some joker putting ten characters into your string doesn't start stomping on unrelated memory. (Yes, C will let someone overwrite almost the entire address space with this program, as written. Giant security flaw. :)
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *toParseStr = malloc(10);
printf("Enter a short string: ");
scanf("%s",toParseStr);
printf("%s\n",toParseStr);
return 0;
}