I am writing a simple program that takes the command line arguments and stores them into a char **. I am trying to learn more about memory management but cannot get past this simple stumbling block. My program is supposed to copy the command line argumetns into a dynamicly allocated char **. However the first position in my array is always corrupter. Below is the code and what it prints:
if (strcmp(argv[1], "test") ==0)
{
test();
}
else
{
char ** file_names = malloc(10);
for(int i =0; i < argc-1; ++i)
{
file_names[i] = malloc(10);
strcpy(file_names[i], argv[i+1]);
printf("%s, %s\n", argv[i+1], file_names[i]);
}
printf("____________\n");
for(int i =0; i < argc-1; ++i)
{
printf("%s\n", file_names[i]);
}
}
and the out come is:
what, what
test, test
again, again
wow, wow
____________
pK#??
test
again
wow
can someone please explain why this is happening? Thanks
This:
char ** file_names = malloc(10);
is a bug. It attempts to allocate 10 bytes, which has nothing at all to do with how many bytes you need. Under-allocating and then overwriting gives you undefined behavior.
It should be something like:
char **file_names = malloc(argc * sizeof *file_names);
This computes the size of the allocation by multiplying the number of arguments (argc, if you don't want to store argv[0] then this should be (argc - 1), of course) by the size of a character pointer, which is expressed as sizeof *file_names. Since file_names is of type char * *, the type of *file_names is char *, which is what you want. This is a general pattern, it can be applied very often and it lets you stop repeating the type name. It can protect you from errors.
For instance compare:
double *floats = malloc(1024 * sizeof(float)); /* BAD CODE */
and:
double *floats = malloc(1024 * sizeof *floats);
If you imagine that originally it was float *floats (as the naming suggests) then the first variant contains another under-allocation bug, while the second "survived" the change of types without error.
Then you need to check that it succeeded, before assuming it did.
You want to allocate the right amount of memory for file_names, probably more like:
char ** file_names = malloc(sizeof(char*) * (argc - 1));
Related
I am writing a function for use in a small C program. The function is supposed to prompt the user for n 7-digit alphanumeric course code strings, and return those strings as an array. I have written a function that I believe should do that, however I have experienced some errors.
char ** getNCourses(int n) {
char **courses;
courses = malloc(n * sizeof(char));
for (int i=0; i<n; i++) {
printf(INQUIRY_COURSE_CODE"\n", i);
courses[i] = malloc(8);
scanf("%7s", courses[i]);
flush();
}
return courses;
}
I have a few lines of code to print the result of said array:
// prompt the user for course codes
char **pCourses;
pCourses = getNCourses(MAX_COURSES);
for (int i=0; i<MAX_COURSES; i++) {
printf("%s ", pCourses[i]);
}
And here is an output of the program being run. As can be seen, the outputted course codes are "corrupted":
Registering 10 courses.
Please enter the 7-digit course code for course 0:
CST8101
Please enter the 7-digit course code for course 1:
CST8102
[...]
CST8109
Please enter the 7-digit course code for course 9:
CST8110
�#�� CST8102 �#�� �#�� �#�� CST8106 CST8107 CST8108 CST8109 CST8110 %
I am unsure as to why some of the course codes have no problem appearing, yet others are entirely incorrect. I believe it is not an issue with reading the data, but actually allocating the memory and returning the array, but I am at a loss.
char **courses;
courses = malloc(n * sizeof(char));
courses points to char *. Each char * requires sizeof (char *) bytes, not sizeof (char) bytes. n of them require n * sizeof (char *) bytes.
You can avoid errors like this by always writing Pointer = malloc(n * sizeof *Pointer);. Then sizeof *Pointer always produces the size of the type being pointed to; you never have to deduce the type. It also automatically adjusts to declaration changes: If the code is edited to change the declaration of the pointer, the sizeof will still be correct because it uses the pointer to get the type, rather than a hard-coded type.
I'm solving a coding problem for a Data Structures assignment, and one part of my solution keeps giving me a segfault: 11 when reading the last line of a text file using fgets().
I've already searched around StackOverflow for some time now and can't find the same error I'm getting. I've tried many ways to solve the problem but I can't figure out what exactly is wrong.
int main() {
**S = func();
free(S);
return 0;
}
char** func() {
FILE *fStrings = fopen("file.txt", "r");
if (fStrings == NULL) printf("Error opening 'file.txt'\n")
int length = fileLength("file.txt"); // This returns just the number of lines in a file, works as intended.
char **strings = (char **)malloc(200 * length * sizeof(char));
f(length, (char (*)[200])strings, *fStrings);
// some code using the data modified by f()
fclose(fStrings);
return strings;
}
void f(int length, char strings[][200], FILE *fStrings) {
int i;
for (i = 0; i <= length; i++) {
printf("i = %d\n", i); // debug
fgets(strings[i], 200, fStrings); // Here's the problem
printf("string = %s\n", strings[i]); // debug
}
}
The above code has 2 debug lines to see where exactly the error happens. The function is called with the correct parameters, where length is the amount of strings in the array, strings is an array of strings, and fStrings a file with said strings.
The segfault occurs when trying to read the last line of the text file. Any help will be appreciated.
EDIT: Changed the code block to include a better version of my code, in case it makes it easier to understand. The correct libraries are included too.
I think the main problem with your code is this line
for (i = 0; i <= length; i++) {
Due to <= it will loop "length + 1" times but you have only allocated memory for "length" times. Change it to:
for (i = 0; i < length; i++) {
Your allocation is strange. You should allocate a 2D array using a pointer to a 1D array, i.e. like this:
char (*strings)[200] = malloc(length * sizeof *strings)
then you can do the call without any cast.
Also just noticed this line:
f(length, (char (*)[200])strings, *fStrings);
^
notice
I don't think you want * in front of fStrings (it should not even compile with the *)
With the correct allocation (as described above) the call should be:
f(length, strings, fStrings);
I'm fairly new to C; been at it for 3 weeks in a class. I am having a bit of trouble with pointers, and am sure there is probably an easy fix. So basically, this program is supposed to read a word from an input file, store it in an array of pointers with memory allocation, print the word and the normalized form of the word (irrelevant process), and then reallocate the space so that the pointer array will grow as more words are inputted. However, I am having a bit of trouble getting the words to print and the array to reallocate (I currently have it set to a fixed size just to troubleshoot the whole printing aspect). Let me know if there is something wrong with my variable declarations, or if I am just making a stupid mistake please (I am sure it is the probably a combination of the two). Again, I'm very new to C, so I apologize if this is an easy question.
char * word_regular[100];
char * word_norm[100];
int main (int argc, char * argv[])
{
if (argc != 2){
printf("You have not entered a valid number of files.\n");
exit(1);
}
FILE * f_in = fopen(argv[1],"r");
int i = 0;
char word[512];
char norm_word[512];
while(fscanf(f_in, "%s", word) != EOF) {
if (is_valid_entry(word)) {
word_regular[i] = malloc(sizeof(char) * strlen(word) + 1);
strcpy(word_regular[i],word);
printf("%s\n",*word_regular[i]);
word_norm[i] = malloc(sizeof(char) * strlen(norm_word) + 1);
normalize(word, norm_word);
strcpy(word_norm[i],norm_word);
printf("%s\n", *word_norm[i]);
i++;
Some problems that are with your current code (ignoring the dynamic size need as opposed to fixed since you already said you are using that to debug),
printf("%s\n",*word_regular[i]);
%s takes a char * for printing, so it should be
printf("%s\n",word_regular[i]);
For the second printf, since norm_word itself is a char array,
you should simply use
printf("%s\n", &norm_word[i]);
If you want to print string starting from the ith index.
Update:
A quick tip is to pay attention whether you are copying the \0 with strings or not. Because your api calls, such as strlen would go beyond string crashing (or worst silently), unless it is null terminated.
The problem with your printf call is that you pass a char (*word_regular[i], *norm_word[i]) instead of char * (word_regular[i], word_norm[i]) when trying to print a string.
If you want to dynamically grow the array, you need to dynamically allocate it in the first place, so instead of declaring arrays of pointers:
char * word_regular[100];
char * word_norm[100];
You need to declare pointers to pointers:
char ** word_regular;
char ** word_norm;
Allocate an initial buffer for them (in a function, main for example):
word_regular = malloc(sizeof(char *) * INITIAL_AMOUNT);
Then reallocate them as needed.
word_regular = realloc(word_regular, sizeof(char *) * new_amount);
You will need to keep track of the amount of pointers in the arrays, and free them properly of course...
When writing small UNIX utilities in C I sometimes want to take a copy of argv provided to main() so that I can tweak the parameters before calling exec(). The following is based loosely on an implementation from BSD's xargs(1):
void run_script(char *argv[]) {
char **tmp, **new_argv;
int argc;
for (argc=0; argv[argc] != 0; argc++);
new_argv = malloc((argc + 1) * sizeof(char *));
for (tmp=new_argv; *argv != 0; tmp++) {
*tmp = *argv++;
*tmp = strdup(*tmp);
}
/* call execvp(3) using new_argv */
for (i=0; i<=argc; i++)
free(new_argv[i]);
free(new_argv);
}
This feels more complex than it needs to be. Is there a better way to write this in C? (Perhaps filling in a single buffer that was allocated using _POSIX_ARG_MAX.)
My C is a little rusty, however....
On the assumption that argv[] is going to be available for the duration of your script, you don't need to strdup strings if they are not going to be changed. After you allocate the memory (remembering to add more to argc if you want to add extra parameters), you should just be able to memcpy. Your new_argv will point to the same strings as your original argv, so you will need to strdup before you change it (or not, if you want to set it to some other string).
I think you need to have a close look at your loop, for (m=0, tmp.. - for a start, I don't think m is used anywhere else; second, you are testing *argv != 0, but not changing *argv in the loop, so it will run forever or not at all, and third, at the start of this loop, all your new_argv are null pointers, so *tmp = strdump(*tmp); will try to duplicate a string at memory address 0, having nothing to do with argv?
I came up with another process for duplicating argv. The following example isn't shorter, but I think it easier to read:
void run_script(char *argv[]) {
int i;
char **new_argv;
char *p, *arg_buf;
int argc;
for (argc=0; argv[argc]; argc++);
arg_buf = malloc(ARG_MAX);
new_argv = calloc(argc+1, sizeof(char *));
for (i=0, p=arg_buf; i<argc; i++) {
p += strlcpy(p, argv[i], ARG_MAX - (p - arg_buf));
p++;
}
/* call execvp(3) using new_argv */
free(arg_buf);
free(new_argv);
}
On Linux ARG_MAX should be replaced with sysconf(_SC_ARG_MAX)
I have an unsorted dictionary file named "dict.txt".
I have managed to put the words of the file in an array and the qsort() I use also seems to be working just fine (That is, the array is sorted).
The problem arises when I call bsearch(),
the program crashes and my question is:
Why is this happening?
I use gcc to compile and don't use an IDE of any sort so I don't have any debugger nor do I know how to use one (yet).
I am quite aware that the code presented here might contain several problems.
That is because I am quite new to c and my background is mainly Java (which despite the similarities seems to be a drawback, because I am so used to OO and c is obviously not OO).
Any advice would be greatly appreciated.
int strcmp_mod(const void *p1, const void *p2) {
return strcmp(* (char * const *) p1, * (char * const *) p2);
}
int main(void) {
int size, i;
char **words;
char *pItem;
char *key = "fight";
char* buf = load_file("dict.txt"); if (buf == NULL) return 1;
size = count_words(buf);
words = (char**)malloc((size+1) * sizeof(char*));
for (i=0; i<size; i++) {
words[i] = (char*)malloc(80 * sizeof(char));
}
copy_words_to_lower(buf, words, size);
words[size] = '\0';
qsort(words, size, sizeof(char*), strcmp_mod);
for (i=0; i<size; i++) {
printf("%s\n", words[i]);
}
pItem = (char *) bsearch(key, words, size, sizeof(char*), strcmp_mod);
if (pItem!=NULL)
printf ("%s is in the array.\n", pItem);
else
printf ("%s is not in the array.\n", key);
return 0;
}
Try giving bsearch the address of key.
Why is this happening?
You're passing a char* as the key parameter to bsearch, but your comparator expects the result of casting a char** to void*.
Once you've fixed that, the next problem is that the return value from bsearch is a pointer to the matching item in the array. So again a char** not a char*.
Any advice would be greatly appreciated.
Either get a debugger, or else get ready to add lots of logging to your code.
Also the construction of your words array is slightly off. As it is it gets the job done, but it might be an idea to allocate the buffer for each word as you go, rather than all the same size at the start. Who knows if somebody will send you a file with a word in it more than 80 chars long? You terminate the list of words with a nul character, '\0', when you probably mean to terminate it with a null pointer, NULL. '\0' actually works, because it's another way of saying 0, and 0 converts to a null pointer. But it's not what you mean. And the array doesn't need to be null-terminated at all right now, because every time you use it after that you specify its length, size.