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...
Related
I am trying to write a function to convert a text file into a CSV file.
The input file has 3 lines with space-delimited entries. I have to find a way to read a line into a string and transform the three lines from the input file to three columns in a CSV file.
The files look like this :
Jake Ali Maria
24 23 43
Montreal Johannesburg Sydney
And I have to transform it into something like this:
Jake, 24, Montreal
...etc
I figured I could create a char **line variable that would hold three references to three separate char arrays, one for each of the three lines of the input file. I.e., my goal is to have *(line+i) store the i+1'th line of the file.
I wanted to avoid hardcoding char array sizes, such as
char line1 [999];
fgets(line1, 999, file);
so I wrote a while loop to fgets pieces of a line into a small buffer array of predetermined size, and then strcat and realloc memory as necessary to store the line as a string, with *(line+i) as as pointer to the string, where i is 0 for the first line, 1 for the second, etc.
Here is the problematic code:
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#define CHUNK 10
char** getLines (const char * filename){
FILE *file = fopen(filename, "rt");
char **lines = (char ** ) calloc(3, sizeof(char*));
char buffer[CHUNK];
for(int i = 0; i < 3; i++){
int lineLength = 0;
int bufferLength = 0;
*(lines+i) = NULL;
do{
fgets(buffer, CHUNK, file);
buffLength = strlen(buffer);
lineLength += buffLength;
*(lines+i) = (char*) realloc(*(lines+i), (lineLength +1)*sizeof(char));
strcat(*(lines+i), buffer);
}while(bufferLength ==CHUNK-1);
}
puts(*(lines+0));
puts(*(lines+1));
puts(*(lines+2));
fclose(file);
}
void load_and_convert(const char* filename){
char ** lines = getLines(filename);
}
int main(){
const char* filename = "demo.txt";
load_and_convert(filename);
}
This works as expected only for i=0. However, going through this with GDB, I see that I get a realloc(): invalid pointer error. The buffer loads fine, and it only crashes when I call 'realloc' in the for loop for i=1, when I get to the second line.
I managed to store the strings like I wanted in a small example I did to try to see what was going on, but the inputs were all on the same line. Maybe this has to do with fgets reading from a new line?
I would really appreciate some help with this, I've been stuck all day.
Thanks a lot!
***edit
I tried as suggested to use calloc instead of malloc to initialize the variable **lines, but I still have the same issue.I have added the modifications to the original code I uploaded.
***edit
After deleting the file and recompiling, the above now seems to work. Thank you to everyone for helping me out!
You allocate line (which is a misnomer since it's not a single line), which is a pointer to three char*s. You never initialize the contents of line (that is, you never make any of those three char*s point anywhere). Consequently, when you do realloc(*(line + i), ...), the first argument is uninitialized garbage.
To use realloc to do an initial memory allocation, its first argument must be a null pointer. You should explicitly initialize each element of line to NULL first.
Additionally, *(line+i) = (char *)realloc(*(line+i), ...) is still bad because if realloc fails to allocate memory, it will return a null pointer, clobber *(line + i), and leak the old pointer. You instead should split it into separate steps:
char* p = realloc(line[i], ...);
if (p == null) {
// Handle failure somehow.
exit(1);
}
line[i] = p;
A few more notes:
In C, you should avoid casting the result of malloc/realloc/calloc. It's not necessary since C allows implicit conversion from void* to other pointer types, and the explicit could mask an error where you accidentally omit #include <stdlib.h>.
sizeof(char) is, by definition, 1 byte.
When you're allocating memory, it's safer to get into a habit of using T* p = malloc(n * sizeof *p); instead of T* p = malloc(n * sizeof (T));. That way if the type of p ever changes, you won't silently be allocating the wrong amount of memory if you neglect to update the malloc (or realloc or calloc) call.
Here, you have to zero your array of pointers (for example by using calloc()),
char **line = (char**)malloc(sizeof(char*)*3); //allocate space for three char* pointers
otherwise the reallocs
*(line+i) = (char *)realloc(*(line+i), (inputLength+1)*sizeof(char)); //+1 for the empty character
use an uninitialized pointer, leading to undefined behaviour.
That it works with i=0 is pure coindicence and is a typical pitfall when encountering UB.
Furthermore, when using strcat(), you have to make sure that the first parameter is already a zero-terminated string! This is not the case here, since at the first iteration, realloc(NULL, ...); leaves you with an uninitialized buffer. This can lead to strcpy() writing past the end of your allocated buffer and lead to heap corruption. A possible fix is to use strcpy() instead of strcat() (this should even be more efficient here):
do{
fgets(buffer, CHUNK, file);
buffLength = strlen(buffer);
lines[i] = realloc(lines[i], (lineLength + buffLength + 1));
strcpy(lines[i]+lineLength, buffer);
lineLength += buffLength;
}while(bufferLength ==CHUNK-1);
The check bufferLength == CHUNK-1 will not do what you want if the line (including the newline) is exactly CHUNK-1 bytes long. A better check might be while (buffer[buffLength-1] != '\n').
Btw. line[i] is by far better readable than *(line+i) (which is semantically identical).
I was wondering is it possible to create one endless array which can store endlessly long strings?
So what I exactly mean is, I want to create a function which gets i Strings with n length.I want to input infinite strings in the program which can be infinite characters long!
void endless(int i){
//store user input on char array i times
}
To achieve that I need malloc, which I would normally use like this:
string = malloc(sizeof(char));
But how would that work for lets say 5 or 10 arrays or even a endless stream of arrays? Or is this not possible?
Edit:
I do know memory is not endless, what I mean is if it where infinite how would you try to achieve it? Or maybe just allocate memory until all memory is used?
Edit 2:
So I played around a little and this came out:
void endless (char* array[], int numbersOfArrays){
int j;
//allocate memory
for (j = 0; j < numbersOfArrays; j++){
array[j] = (char *) malloc(1024*1024*1024);
}
//scan strings
for (j = 0; j < numbersOfArrays; j++){
scanf("%s",array[j]);
array[j] = realloc(array[j],strlen(array[j]+1));
}
//print stringd
for (j = 0; j < numbersOfArrays; j++){
printf("%s\n",array[j]);
}
}
However this isn't working maybe I got the realloc part terrible wrong?
The memory is not infinite, thus you cannot.
I mean the physical memory in a computer has its limits.
malloc() will fail and allocate no memory when your program requestes too much memory:
If the function failed to allocate the requested block of memory, a null pointer is returned.
Assuming that memory is infinite, then I would create an SxN 2D array, where S is the number of strings and N the longest length of the strings you got, but obviously there are many ways to do this! ;)
Another way would be to have a simple linked list (I have one in List (C) if you need one), where every node would have a char pointer and that pointer would eventually host a string.
You can define a max length you will assume it will be the max lenght of your strings. Otherwise, you could allocate a huge 1d char array which you hole the new string, use strlen() to find the actual length of the string, and then allocate dynamically an array that would exactly the size that is needed, equal of that length + 1 for the null-string-terminator.
Here is a toy example program that asks the user to enter some strings. Memory is allocated for the strings in the get_string() function, then pointers to the strings are added to an array in the add_string() function, which also allocates memory for array storage. You can add as many strings of arbitrary length as you want, until your computer runs out of memory, at which point you will probably segfault because there are no checks on whether the memory allocations are successful. But that would take an awful lot of typing.
I guess the important point here is that there are two allocation steps: one for the strings and one for the array that stores the pointers to the strings. If you add a string literal to the storage array, you don't need to allocate for it. But if you add a string that is unknown at compile time (like user input), then you have to dynamically allocate memory for it.
Edit:
If anyone tried to run the original code listed below, they might have encountered some bizarre behavior for long strings. Specifically, they could be truncated and terminated with a mystery character. This was a result of the fact that the original code did not handle the input of an empty line properly. I did test it for a very long string, and it seemed to work. I think that I just got "lucky." Also, there was a tiny (1 byte) memory leak. It turned out that I forgot to free the memory pointed to from newstring, which held a single '\0' character upon exit. Thanks, Valgrind!
This all could have been avoided from the start if I had passed a NULL back from the get_string() function instead of an empty string to indicate an empty line of input. Lesson learned? The source code below has been fixed, NULL now indicates an empty line of input, and all is well.
#include <stdio.h>
#include <stdlib.h>
char * get_string(void);
char ** add_string(char *str, char **arr, int num_strings);
int main(void)
{
char *newstring;
char **string_storage;
int i, num = 0;
string_storage = NULL;
puts("Enter some strings (empty line to quit):");
while ((newstring = get_string()) != NULL) {
string_storage = add_string(newstring, string_storage, num);
++num;
}
puts("You entered:");
for (i = 0; i < num; i++)
puts(string_storage[i]);
/* Free allocated memory */
for (i = 0; i < num; i++)
free(string_storage[i]);
free(string_storage);
return 0;
}
char * get_string(void)
{
char ch;
int num = 0;
char *newstring;
newstring = NULL;
while ((ch = getchar()) != '\n') {
++num;
newstring = realloc(newstring, (num + 1) * sizeof(char));
newstring[num - 1] = ch;
}
if (num > 0)
newstring[num] = '\0';
return newstring;
}
char ** add_string(char *str, char **arr, int num_strings)
{
++num_strings;
arr = realloc(arr, num_strings * (sizeof(char *)));
arr[num_strings - 1] = str;
return arr;
}
I was wondering is it possible to create one endless array which can store endlessly long strings?
The memory can't be infinite. So, the answer is NO. Even if you have every large memory, you will need a processor that could address that huge memory space. There is a limit on amount of dynamic memory that can be allocated by malloc and the amount of static memory(allocated at compile time) that can be allocated. malloc function call will return a NULL if there is no suitable memory block requested by you in the heap memory.
Assuming that you have very large memory space available to you relative to space required by your input strings and you will never run out of memory. You can store your input strings using 2 dimensional array.
C does not really have multi-dimensional arrays, but there are several ways to simulate them. You can use a (dynamically allocated) array of pointers to (dynamically allocated) arrays. This is used mostly when the array bounds are not known until runtime. OR
You can also allocate a global two dimensional array of sufficient length and width. The static allocation for storing random size input strings is not a good idea. Most of the memory space will be unused.
Also, C programming language doesn't have string data type. You can simulate a string using a null terminated array of characters. So, to dynamically allocate a character array in C, we should use malloc like shown below:
char *cstr = malloc((MAX_CHARACTERS + 1)*sizeof(char));
Here, MAX_CHARACTERS represents the maximum number of characters that can be stored in your cstr array. The +1 is added to allocate a space for null character if MAX_CHARACTERS are stored in your string.
I'm currently trying to make a program in c which will return a pointer to an array of 2 strings. The first is the characters of the string s that are in the odd position and the second are the characters in the even position. I'm not experienced in C so I need a bit of help with this program. I've been trying to code using what I know from python and java but it doesn't seem to follow the same principles with pointers. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **parity_strings(const char *s){
char dest[malloc((char)sizeof(s)/2 + 1)][malloc((char)sizeof(s)/2 + 1)]; //trying to allocate memory to an array of size 2 which will hold 2 strings.
int i;
for(i = 0; i < sizeof(s); i+= 2){ //iterating through odd strings
s[0] += dest[i];
}
for(i= 2; i< sizeof(s); i += 2){ //iterating through even strings (I suppose i could have just appended using 1 for loop but oh well
s[1] += dest[i];
}
return dest;
}
int main(int argc, char **argv) {
char **r = parity_strings(argv[1]);
printf("%s %s %s\n", r[0], r[1], argv[1]);
return 0;
}
memory allocation is just a pain too...I have no clue if it's doing what I intend on it doing. I'm trying to allocate the size of the string in bytes + 1 byte into each index of the array Dest.
any ideas on how to fix this? Thanks.
This line will not do anything good:
char dest[malloc((char)sizeof(s)/2 + 1)][malloc((char)sizeof(s)/2 + 1)];
malloc returns a pointer to the newly allocated memory. In your line above, the square brackets in dest[][] need unsigned integers. Pointers can be casted to integers, but that isn’t what you want there at all. It might compile, but it probably won’t run, and certainly won’t do what you want.
Also, sizeof(s) returns the size of the pointer to s, not the length of the string. Strings in C are really just null-terminated arrays of chars, and arrays are passed to functions with a pointer, not their entire contents. To get the length of a string, use strlen(s) instead.
You could do something like this:
char *destodd = malloc((strlen(s)/2 + 2));
char *desteven = malloc((strlen(s)/2 + 2));
char **dest = malloc(sizeof(char *) * 2);
dest[0] = desteven;
dest[1] = destodd;
I changed your + 1 above to +2. A string of length 3 needs 3 characters in destodd: one for character 1, one for character 3, and one for the NUL terminator.
It’s tricky to malloc a multi-dimensional array in C. A one-dimensional array, on the other hand, is easy. Just treat destodd and desteven like they’re arrays, even though they’re really pointers:
for (i = 0; i < strlen(s); i += 2){
desteven[i] = 'a'; // Fix this
destodd[i] = 'b';
}
The code in your for loops didn’t look like it would work. It looks like you may have been trying to use += to concatenate strings, but it only does addition of numbers. I couldn’t quickly figure out what you should set in the for loop, so 'a' and 'b' are just placeholders.
You have a few issues. As your compiler should tell you, char dest[malloc()] requires a pointer-to-unsigned cast, which is legal but is not what you want. More importantly, returning a pointer to an array allocated on the stack results in undefined behavior if you dereference the pointer, because the compiler may have already deallocated the memory. I'm not exactly sure what the intended output of the function is, but in terms of filling two char arrays, in my opinion the easiest way to do it is this:
char **parity_strings(char* buf) //Please avoid single letter variable names for anything but loop control
{
size_t buflen = strlen(buf);
if (NULL == char** dest = malloc(2 * sizeof(*dest)))
;//handle memory allocation error
if (NULL == dest[0] = malloc(buflen * sizeof(*buf)))
;//handle memory allocation error
if (NULL == dest[1] = malloc(buflen * sizeof(*buf)))
;//handle memory allocation error
//Note that you would do the above two lines in a loop for a variable sized multidimensional array
strncpy(dest[0], buf, 500);
strncpy(dest[1], buf, 500); //If you need strings larger than 500 change as necessary, mostly only needed if you are taking input from someone else but it's good practice to use strncpy over strcpy)
return dest;
}
In my application, we take in char values one at a time and we need to be able to but them into a string. We are assembling these strings one by one by putting the char values into a char array, then clearing the array. However the strings are each different lengths and we are unable to determine the size of the string. How can we change the sizes of the array to add more space as we need it?
Also, how can we print out the array?
If the array was dynamically allocated with malloc, you can resize it with realloc:
int array_size = 1024;
char *array = (char *) malloc(array_size);
int n = 0;
char c;
while ((c = getchar()) != EOF) {
array[n++] = c;
if (n >= array_size) {
array_size += 1024;
array = (char *) realloc(array_size);
}
}
array[n] = '\0';
For printing out the contents of the array, you can simply pass it to printf or puts:
printf("%s\n", array);
puts(array);
if you don'y know the size you are going to need and are adding one character at a time you can consider using a linked list. It can grow as much as you need it to. The disadvntages would be lookup is kind of slow, and if you need to free the memory, or clear it you would have to do this for each element, one at a time.
You can also take the dynamic array approach: allocate a certain size which you consider large enough and when that is 80% full, allocate a new buffer, twice as large and copy the contents of the old one in the new, larger one.
I have an assignment I've been working on for a few hours now, and I can't seem to get it quite right. The assignment is to take a random number of names (from stdin), sort them, and then output them in alphabetical order. I can't find any sites online that handle this kind of sorting specifically, and have had no luck trying to implement qsort() into my code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int stringcmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return strcmp(*ia, *ib);
}
void main(int argc, char *argv[])
{
char *input[] = {" "};
char temp[20][20];
int i = 0;
int num = 0;
int place = 0;
int stringlen = sizeof(temp) / sizeof(char);
printf("How many names would you like to enter? ");
scanf("%d", &num);
while (place < num)
{
printf("Please input a name(first only): ");
scanf("%s", input[place]);
printf("The name you entered is: ");
printf("%s\n", input[place]);
place++;
}
//qsort(temp, stringlen, sizeof(char *), stringcmp); <-- just an idea I was messing with
qsort(input, stringlen, sizeof(char *), stringcmp);
printf("Names:\n");
for(i=0; i<place; i++)
printf("%s\n", input[i]);
system("PAUSE");
return(EXIT_SUCCESS);
}
The main problem is, when I go to output my code, I cannot use the char *input variable because of how its declared. The temp[] will display, but will not be sorted by qsort because it is not declared as a pointer. Any ideas?
You can't declare your input array like that. Since you know how many the user requires, you can dynamically allocate the array:
char **input = malloc(num * sizeof(char*));
Likewise, when you read your strings in, they need somewhere to go. Simply passing an uninitialized pointer to scanf is not okay. I suggest you define the maximum length of a name and have a temporary buffer for reading it:
const size_t MAX_NAME = 50;
char name[MAX_NAME];
...
for( i = 0; i < num; i++ )
{
printf("Please input a name(first only): ");
scanf("%s", name);
input[i] = strdup(name);
}
[Note this does not prevent the user from overflowing the 'name' buffer. I used scanf for illustrative purposes only]
You seem to be passing the wrong array length to qsort. Try this:
qsort(input, num, sizeof(char *), stringcmp);
When you are finished, you need to release memory for all the names and the array.
for( i = 0; i < num; i++ ) free(input[i]);
free(input);
could you explain
the ** declarations throughout the code? I'm not sure what they're
used for, although I know the function for stringcmp is a widely used
algorithm, I have no idea how it works; I'm thrown off by the double
de-reference markers.
Yep, in the case where I used it, I am telling C that to get a single character, I have to dereference a pointer twice. When you index a pointer, it's dereferencing. So I allocated an array by requesting a block of memory containing num * sizeof(char*) bytes. Because I assigned that pointer to a char**, the compiler knows that I am pointing to a chunk of memory that contains char* values.
If I ask for input[0] (this is the same as *input) it should look at the very start of that memory and pull out enough bytes to form a char*. When I ask for input[1], it skips past those bytes and pulls out the next bunch of bytes that form a char*. Etc... Likewise, when I index a char*, I am pulling out single characters.
In your stringcmp function, you have the following situation. You passed a void* pointer to qsort so it doesn't actually know the size of the data values stored in your array. That's why you have to pass both the array length AND the size of a single element. So qsort just blindly rips through this arbitrary-length array of arbitrary-sized values and fires off memory addresses that ought to contain your data for comparison. Because qsort doesn't know anything else about your array elements except where they are located, it just uses void*.
But YOU know that those pointers are going to be the memory addresses of two of your array elements, and that your array elements are char*. So you need the address of a char* (hence you cast the pointers to char**). Now you need to dereference these pointers when you call strcmp() because that function requires a char* (ie a value that points directly to the memory containing your string characters). That is why you use the * in strcmp(*ia, *ib).
One quick way to fix your program is to declare input as an array of pointers, like this:
char *input[20];
When you read names in, use tmp[place] for your buffer, and store the pointer into input, like this:
scanf("%19s", tmp[place]);
input[place] = tmp[place];
Now sorting the input should work fine.
This has a limitation of being limited to 20 lines of 20 characters max. If you learned about malloc in the class, you should be able to fix that by allocating your strings and the string array dynamically.