Dynamic allocation of char** in C - c

I have a date type defined as
typedef char* DateTime;
the format is "dd/mm/yyyy-hh:mm" e.g. "08/08/2012-12:00"
and I want to allocate n string that are "dates".
What is wrong with the following?
DateTime* dates = (DateTime* ) malloc(sizeof(char*) * n);
for (int i = 0; i <= n; i++) {
dates[i] = malloc(sizeof(char)*16);
if (dates[i] == NULL) {
free(dates);
return NULL;
}
}

for (int i = 0; i <= n; i++) {
^
In C arrays start from 0 so dates[n] cannot be accessed. Drop the =.

Besides responses by #Dan and #cnicutar (both of which are spot on), note that the string literal "08/08/2012-12:00" contains 17 characters (not 16). While it's string length is 16, it contains the 16 characters that you see PLUS the '\0' character at the end that serves as the terminator. Also, sizeof(char) is one by definition. Finally, the idiomatic way to allocate memory using malloc would be -
DateTime *dates = malloc(n * sizeof *dates);

In addition to cnicutar's answer there is also this:
In the event that this condition is true:
if ( dates[i] == NULL )
you are only calling free on the overall array, and not freeing the elements before i in the array. This can lead to a significant memory leak

As been pointed out be both me in a comment, and by others, the loop
for (int i = 0; i <= n; i++) {
is looping once to many.
Another problem is this:
dates[i] = malloc(sizeof(char)*16);
The actual string is 16 characters, but since strings in C needs an extra terminator character ('\0') you need to allocate one character more, which means you should multiply by 17.
And as noted by Dan F you also have a potential memory leak.
The two biggest problems is the looping and allocation, as that will cause so called undefined behavior when overwriting unallocated memory.

Related

Segmentation fault on copying string elements to another string

Why am I getting segmentation fault? I have listed my code below.
Please tell if anyone knows what is my fault here and how do I correct it?
What I am trying to do here
I am trying to take numbers as input and for them I have to output a string of characters.
Problem
link to the problem is here.
The code of my proposed solution
#include <stdio.h>
#include <string.h>
#include <math.h>
int main() {
long long int n, k;
char manku[] = { 'm', 'a', 'n', 'k', 'u' };
char l[10000000];
int t, i = 0, j, p;
scanf("%d", &t);
while (t > 0)
{
scanf("%lld", &n);
while (n > 0)
{
j = n % 5;
if (j == 0)
l[i] = manku[4];
else
l[i] = manku[j - 1];
n = n / 5;
i++;
}
p = strlen(l);
for (i = 0; i < p; i++)
l[i] = l[p - 1 - i];
for (i = 0; i < p; i++)
printf("%c", l[i]);
t--;
}
return 0;
}
char l[10000000];
This huge array is overflowing your stack memory.
The stack memory segment is an area of memory allotted for automatic variables and its size is fairly small. It is not a good idea to have such a huge array in stack.
Try to allocate it dynamically, like this:
char *l;
l = malloc(10000000); //note: size of char is 1
With this, the memory allocated to l in heap segment. Make sure to free it once you done with it.
Alternatively, you can make l a global variable or a static local variable so that it will go in Data Segment.
You are getting a segmentation fault when you start running your binary because you are running out of stack memory due to the big size of your array char l[10000000] (you can check the size of your stack by running
$ ulimit -s
in your shell).
There are at least two solutions to this:
Increase the size of your stack. You can do this by running, e.g.,
$ ulimit -s unlimited
in your shell before running the binary.
Use malloc to allocate the l array, so that it is allocated in the heap rather than in the stack.
Firstly, initialize the variable i after scanning n.
while(t>0) {
scanf("%lld",&n);
i = 0; /* initialize i every time here */
while(n>0) {
/* some code */
}
}
Also instead of creating stack created array like char l[10000000]; create the dynamic array once before while loop and free the dynamically allocated memory once done. for e.g
char *l = malloc(SIZE); /* define the SIZE */
...
...
free(l);
Short Answer: The segmentation fault is caused by char l[10000000];. Decalring char l[26]; is sufficient.
Details
As others said the allocation char l[10000000]; causes the segmentation fault. You do not need this much memory. The question stated that the maximum value for n is 10^18. Thus the maximum length of a word would be 26 characters. Thus, char l[26]; is sufficient.
Explanation: It is given that you have 10^18 options to arrange k characters. Each charater has 5 options and thus the number of options to arrange these characters is 5^k. Now, you just have to find k:
5^k = 10^18 ==> k = log_5(10^18) ~= 25.75218 < 26
Implementation
Regarding the implementation, you have few wrong things going on.
You do not set i = 0; after each input scan.
Your can not use strlen without the terminating null-character. You should add l[i] = '\0'; above p = strlen(l);.
Your second for loop, the one that should revert the string, is not working properly. Each step changes the string and the steps after it use the changed string (instead of working with the original one).
Regarding the algorithm, it does not work properly as well. I can give you a hint: this problem is similar to counting in base-5.
Comments
The things above are just few things that I have noticed. I think you should consider rewriting the code since it may still contaion small flaws.
Another tip: for printing strings (character arrays in c) you can use
printf("%s", str);
Assuming that str is an array of character that ends with the terminating null-character. Some more information here.

C: array of pointers pointing to the same value

I'm writing an IP forwarding program, and I need to splice the following routing table into a char* array
128.15.0.0 255.255.0.0 177.14.23.1
137.34.0.0 255.255.0.0 206.15.7.2
137.34.128.0 255.255.192.0 138.27.4.3
137.34.0.0 255.255.224.0 139.34.12.4
201.17.34.0 255.255.255.0 192.56.4.5
27.19.54.0 255.255.255.0 137.7.5.6
0.0.0.0 0.0.0.0 142.45.9.7
I have initialized an array of pointers to char* like so char *routing[128][128];, then I loop through each line, build a char temp[128] array which then get's assigned to routing as shown below.
In other words, each pointer in the routing array will point to an IP address.
char *routing[128][128];
char line[128], temp[128];
int i = 0, j = 0, token_count = 0, line_count = 0;
while(fgets(line, sizeof(line), routing_table) != NULL){
// printf("%s\n", line);
token_count = 0;
for (i = 0; i < strlen(line); i++){
if (line[i] != ' ' && token_count == 2){
for (j = 0; j < 128; j++){
if (line[i+j] == ' ')
break;
temp[j] = line[i+j];
}
i += j;
routing[line_count][token_count] = temp; //ASSIGNMENT OCCURS HERE
token_count++;
}
else if (line[i] != ' ' && token_count == 1){
for (j = 0; j < 128; j++){
if (line[i+j] == ' ')
break;
temp[j] = line[i+j];
}
i += j;
routing[line_count][token_count] = temp;
token_count++;
}
else if (line[i] != ' ' && token_count == 0){
for (j = 0; j < 128; j++){
if (line[i+j] == ' ')
break;
temp[j] = line[i+j];
}
i += j;
routing[line_count][token_count] = temp;
token_count++;
}
}
line_count++;
}
The problem is that every time an assignment happens, it updates the entire array. So when I print out the array at the end, I get the last element repeated.
142.45.9.7
142.45.9.7
142.45.9.7
...
142.45.9.7
142.45.9.7
I figured I needed to dereference temp but that threw a warning and didn't even fix it.
What do I have wrong syntactically? Why are all pointers pointing to the same char string?
Right near the end, just before where you increment token_count, you've got this line:
routing[line_count][token_count] = temp;
And that's your problem. temp is an array of 128 characters -- what we call a string in C, if there's a null terminator in there somewhere. You're copying each IP address string into it in turn, and then for each one, you assign temp's address to a slot in one of your big two dimensional array of pointers. All those pointers, but they're all pointing to the same actual buffer.
So at the end of the loop, they all point to the last string you copied into temp. That's not what you want, and if temp is a local in a function, then you're in real trouble.
What you want is either a two dimensional array of actual char arrays (16 chars each would suffice for a dotted quad and a null terminator) -- but I'm a little rusty on C and won't risk leading you astray about how to declare that -- or else you need to allocate new memory for each string in your existing two dimensional array. You'd do that like so, in many C implementations:
routing[line_count][token_count] = strdup(temp);
strdup() is a handy function that allocates sufficient memory for the string you give it, copies the string into that memory, and returns a pointer to it. But it's not part of the standard, so can't be counted on in all cases. If you're writing for one compiler and it's there, you're all set (this is often the case). But if you may have any concerns about portability, here's a portable way to do the same thing.
Portable or not, you're allocating memory now, and when you're done with the routing table, you'll need to free the allocated memory by calling free(routing[i][j]) on every one of those pointers that you got back from strdup() (or from some other, more portable function).
To that end, you should call this before allocating anything:
memset(routing, 0, sizeof(char) * 128 * 128);
...where 128 and 128 are the two dimensions of the array (which I would put in #defined constants that I used for the loop and for the declaration, if I really had to do this in C, and didn't allocate the whole mess dynamically). If you first set the whole thing to zeroes, then every pointer in there starts out as NULL. Then when you loop through it to free the memory, you can just loop through each "row" freeing each pointer until you hit a NULL, and then stop.
Thinking about another approach, it is always error-prone to parse ip addresses of command line output, like ifconfig, route, ip etc etc, so why not use the programmatic way to obtain the routing table information? For example, on Linux, RTNETLINK is the standard way to manipulate route table:
http://man7.org/linux/man-pages/man7/rtnetlink.7.html
It gives you all the information in well defined struct.
On windows, you can use Win32 API to do the same:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365953(v=vs.85).aspx
routing[line_count][token_count] = temp; //ASSIGNMENT OCCURS HERE
The contents of the temp array may be different at each iteration.
The address of the temp array is constant throughout the execution of the program.
So you are obviously assigning the same value to every entry in the routing array.

Use of array of arrays of string in C for parsing text file

I would like to read from N text files (having similar structure: a few lines, each line having the same small number of words) and store in a string matrix the words read, in such a way that in each (row, col) position I have one word.
A simple (two lines, three words per line) specimen for the files is the following:
line1word1 line1word2 line1word3
line2word1 line2word2 line2word3
Delimiter for the words is space.
I have attempted this code:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_LENGTH 1000
#define MAX_TOKS 100
#define DELIMITERS " "
// line parsing utility
int parseString(char* line, char*** argv) {
char* buffer;
int argc;
buffer = (char*) malloc(strlen(line) * sizeof(char));
strcpy(buffer,line);
(*argv) = (char**) malloc(MAX_TOKS * sizeof(char**));
argc = 0;
(*argv)[argc++] = strtok(buffer, DELIMITERS);
while ((((*argv)[argc] = strtok(NULL, DELIMITERS)) != NULL) &&
(argc < MAX_TOKS)) ++argc;
return argc;
}
int main() {
char S[MAX_STRING_LENGTH];
char **A;
int n,i,j,l;
FILE *f;
char file[50];
char ***matrix;
matrix = malloc(MAX_TOKS * sizeof(char**));
//memory allocation for matrix
for (i = 0; i < MAX_TOKS; i++)
{
matrix[i] = malloc(MAX_TOKS * sizeof(char *));
for (j = 0; j < MAX_TOKS; j++)
{
matrix[i][j] = malloc(MAX_TOKS * sizeof(char));
}
}
int NFILE = 10; // number of files to be read
for(i=0;i<NFILE;i++)
{
sprintf(file,"file%d.txt",i);
f = fopen(file,"r");
l=0; // line-in-file index
while(fgets(S,sizeof(S),f)!=NULL) {
n = parseString(S,&A);
for(j=0;j<n;j++) {
matrix[i][l]=A[j];
printf("%s\t%s\n",matrix[i][l],A[j]);
}
l++;
}
fclose(f);
}
free(matrix);
free(A);
return(0);
}
The problem I can't solve is that there when checking for correspondance between the arrays (in order to be sure I am storing the single words correctly) using
printf("%s\t%s\n",matrix[i][l],A[j]);
I find that the last word (and only the last one) of each line, regardless of the file number, is not stored in matrix. That is to say, line1word1 and line1words of file0 are correctly stored in matrix[0][0][0] and matrix[0][0][1], but in the field matrix[0][0][2] there isn't line1word3, even if A[2] has it!
What am I doing wront? Any suggestion?
Many thanks in advance,
cheers
char ***matrix doesn't declare a three dimensional array. Your matrix would need to be something like char *matrix[a][b] to hold a two dimensional array of string pointers. In order to calculate addresses within an array, the compiler needs to know the all of dimensions but one. If you think about it, you will probably see why...
If you have two arrays:
1 2 3 1 2 3 4 5 6 7
4 5 6 8 9 10 11 12 13 14
7 8 9 15 16 17 18 19 20 21
You can see that item[1][1] is NOT the same item. Regardless of the dimensions in your array, the elements are typically arranged sequentially in memory, with each row following the previous (or possible column, depending on language, I suppose.) If you have an array of pointers, the actual content may be elsewhere, but the points would be arranged like this. So, in my examples above, you must provide the compiler with the number of columns so that it can find members (the number of rows can be variable.) In a three dimensional array, you must provide the first TWO dimensions so that the compiler may calculate item offsets.
I hope that helps.
EDIT: You can have truly dynamic array dimensions by creating your own function to process all array item accesses. The function would need to know the dynamic dimensions and the item index(s) so that it could calculate the appropriate address.
This looks wrong: buffer = (char*) malloc(strlen(line) * sizeof(char));
Firstly, there is no need to cast malloc in C. If your code doesn't compile without the cast, there are two possible reasons:
There is no prototype for malloc. Obviously this can cause problems, because no prototype means the function returns a default type: int, or an error occurs. This can cause your program to misbehave. To avoid this, #include <stdlib.h>.
You're using a C++ compiler. Stop. Either program in C++ (stop using malloc) or use a C compiler. If you want to use this project in a C++ project, compile your C code with a C compiler and link to it in your C++ compiler.
Secondly, sizeof(char) is always 1. There is no need to multiply by it.
Thirdly, a string is a sequence of characters ending at the first '\0'. This means a string always occupies at least 1 character, even if it is an empty string. What does strlen("") return? What is sizeof("")? You need to add 1 to make room for the '\0': buffer = malloc(strlen(line) + 1);.
This looks slightly wrong: (*argv) = (char**) malloc(MAX_TOKS * sizeof(char**));
malloc returns a pointer to an object. *argv is a char **, which means it points to a char *. However, in this case malloc returns a pointer to char ** objects. The representation isn't required to be identical. To avoid portability issues assosciated with this, follow this pattern variable = malloc(n * sizeof *variable); ... in this case, *argv = malloc(MAX_TOKS * **argv);
It gets more gritty as it goes. Forget everything you think you know about your code; Pretend you're going to come back to this in 24 months. What are you going to think of this?
argc = 0;
(*argv)[argc++] = strtok(buffer, DELIMITERS);
while ((((*argv)[argc] = strtok(NULL, DELIMITERS)) != NULL) &&
(argc < MAX_TOKS)) ++argc;
There's actually an off-by-one here, too. Assuming argc == MAX_TOKS, your loop would attempt to assign to (*argv)[MAX_TOKS]. This loop is where I believe your problem lies, and the solution is to express your intent more clearly rather than attempting to cram as much code into one line as possible. How would you rewrite this? Here's what I'd do, in this situation:
char *arg;
size_t argc = 0;
do {
arg = strtok(buffer, DELIMITERS);
buffer = NULL;
(*argv)[argc] = arg;
argc++;
} while (argc < MAX_TOKS && arg != NULL);
The problem is that your parsing loop doesn't increment when strtok returns NULL. Hence, your function returns the position of the last item. Supposing you had two tokens, your parsing function would return 1. Your display loop displays items up to, but not including this position: for(j=0;j<n;j++). You could use the suggested improvement, or change your loop: for (j = 0; j <= n; j++). Either way, you'll need to fix those off-by-ones.
Out of curiosity, which book are you reading?

Trying to free memory after calling strcpy causes the program to crash

I understand that a lot of people here complain about strcpy, but I haven't found anything using search that addresses the issue I have.
First off, calling strcpy itself doesn't cause any sort of crash/segmentation fault itself. Secondly, the code is contained within a function, and the first time that I call this function it works perfectly. It only crashes on the second time through.
I'm programming with the LPC1788 microcontroller; memory is pretty limited, so I can see why things like malloc may fail, but not free.
The function trimMessage() contains the code, and the purpose of the function is to remove a portion of a large string array if it becomes too large.
void trimMessage()
{
int trimIndex;
// currMessage is a globally declared char array that has already been malloc'd
// and written to.
size_t msgSize = strlen(currMessage);
// Iterate through the array and find the first newline character. Everything
// from the start of the array to this character represents the oldest 'message'
// in the array, to be got rid of.
for(int i=0; i < msgSize; i++)
{
if(currMessage[i] == '\n')
{
trimIndex = i;
break;
}
}
// e.g.: "\fProgram started\r\nHow are you?\r".
char *trimMessage = (char*)malloc((msgSize - trimIndex - 1) * sizeof(char));
trimMessage[0] = '\f';
// trimTimes = the number of times this function has been called and fully executed.
// freeing memory just below is non-sensical, but it works without crashing.
//if(trimTimes == 1) { printf("This was called!\n"); free(trimMessage); }
strcpy(&trimMessage[1], &currMessage[trimIndex+1]);
// The following line will cause the program to crash.
if(trimTimes == 1) free(trimMessage);
printf("trimMessage: >%s<\n", trimMessage);
// Frees up the memory allocated to currMessage from last iteration
// before assigning new memory.
free(currMessage);
currMessage = malloc((msgSize - trimIndex + 1) * sizeof(char));
for(int i=0; i < msgSize - trimIndex; i++)
{
currMessage[i] = trimMessage[i];
}
currMessage[msgSize - trimIndex] = '\0';
free(trimMessage);
trimMessage = NULL;
messageCount--;
trimTimes++;
}
Thank you to everyone that helped. The function works properly now. To those asking why I was trying to print out an array I just freed, that was just there to show that the problem occurred after strcpy and rule out any other code that came after it.
The final code is here, in case it proves useful to anyone who comes across a similar problem:
void trimMessage()
{
int trimIndex;
size_t msgSize = strlen(currMessage);
char *newline = strchr(currMessage, '\n');
if (!newline) return;
trimIndex = newline - currMessage;
// e.g.: "\fProgram started\r\nHow are you?\r".
char *trimMessage = malloc(msgSize - trimIndex + 1);
trimMessage[0] = '\f';
strcpy(&trimMessage[1], &currMessage[trimIndex+1]);
trimMessage[msgSize - trimIndex] = '\0';
// Frees up the memory allocated to currMessage from last iteration
// before assigning new memory.
free(currMessage);
currMessage = malloc(msgSize - trimIndex + 1);
for(int i=0; i < msgSize - trimIndex; i++)
{
currMessage[i] = trimMessage[i];
}
currMessage[msgSize - trimIndex] = '\0';
free(trimMessage);
messageCount--;
}
free can and will crash if the heap is corrupt or if you pass it an invalid pointer.
Looking at that, I think your first malloc is a couple of bytes short. You need to reserve a byte for the null terminator and also you're copying into offset 1, so you need to reserve another byte for that. So what is going to happen is that your copy will overwrite information at the start of the next block of heap (often used for length of next block of heap and an indication as to whether or not it is used, but this depends on your RTL).
When you next do a free, it may well try to coalesce any free blocks. Unfortunately, you've corrupted the next blocks header, at which point it will go a bit insane.
Compare these two lines of your code (I've respaced the second line, of course):
char *trimMessage = (char*)malloc((msgSize - trimIndex - 1) * sizeof(char));
currMessage = malloc((msgSize - trimIndex + 1) * sizeof(char));
Quite apart from the unnecessary difference in casting (consistency is important; which of the two styles you use doesn't matter too much, but don't use both in the same code), you have a difference of 2 bytes in the length. The second is more likely to be correct than the first.
You allocated 2 bytes too few in the first case, and the copy overwrote some control information that malloc() et al depend on, so the free() crashed because you had corrupted the memory it manages.
In this case, the problem was not so much strcpy() as miscalculation.
One of the problems with corrupting memory is that the victim code (the code that finds the trouble) is often quite far removed from the code that caused the trouble.
This loop:
for(int i=0; i < msgSize; i++)
{
if(currMessage[i] == '\n')
{
trimIndex = i;
break;
}
}
could be replaced with:
char *newline = strchr(currMessage, '\n');
if (newline == 0)
...deal with no newline in the current messages...
trimIndex = newline - currMessage;
Add this code just before the malloc() call:
// we need the destination buffer to be large enough for the '\f' character, plus
// the remaining string, plus the null terminator
printf("Allocating: %d Need: %d\n", (msgSize - trimIndex - 1), 1 + strlen(&currMessage[trimIndex+1]) + 1);
And I think it will show you the problem.
It's been demonstrated time and again that hand calculating buffer sizes can be error prone. Sometimes you have to do it, but other times you can let a function handle those error prone aspects:
// e.g.: "\fProgram started\r\nHow are you?\r".
char *trimMessage = strdup( &currMessage[trimIndex]);
if (trimMessage && (trimMessage[0] == '\n')) {
trimMessage[0] = '\f';
}
If your runtime doesn't have strdup(), it's easy enough to implement (http://snipplr.com/view/16919/strdup/).
And as a final edit, here's an alternative, simplified trimMessage() that I believe to be equivalent:
void trimMessage()
{
char *newline = strchr(currMessage, '\n');
if (!newline) return;
memmove( currMessage, newline, strlen(newline) + 1);
currMessage[0] = '\f'; // replace '\n'
messageCount--;
}

accessing array of strings in C

How to declare array of strings in C.
Is it like
char str[100][100] ={"this","that","those"};
If so how to access the values .. can i travers like this?
(It does not give any compilation error ..but shows some additional garbage characters)
int i ,j;
char c[100][100] = {"this","that"};
for(i = 0 ;c[i] != '\0';++i)
for(j = 0; c[i][j] != '\0';++j)
printf("%c",c[i][j]);
Is it necessary to add '\0' at end of eac string..for ex:
char c[100][100]={"this\0","that\0"}
How to declare array of strings in C
It is Ok, but you will have to be extremely careful of buffer-overflow when dealing with these strings
can i travers like this?
Note that the condition in the first for loop: for(i = 0 ;c[i] != '\0';++i) is probably wrong, and will fail since c[i] is an array, whose address is not 0. You should probably iterate the outer array by numbers [until you read all elements], and not until you find some specific character. You can do that by maintaining a different variable n, which will indicate how many elements does the array currently have.
Is it necessary to add '\0' at end of eac string..for ex:
No - the compiler add it to you, it is just fine without adding the '\0' to the string.
Yes, you can declare an array of strings that way.
No, you can't traverse it like that, the condition on your outer loop is bad - a string (char *) will never be equal to a character '\0'. The inner loop is fine.
No, you don't need to add the '\0', that will happen automatically.
c[i] is a pointer, so it has nothing to do with '\0'
so instead you should check c[i][0]
The compiler will add '\0' for you when you input a string like "this"
char str[100][100] ={"this","that","those"};
int main()
{
int i ,j;
char c[100][100] = {"this","that"};
for(i = 0 ;c[i][0] != '\0';++i)
{
for(j = 0; c[i][j] != '\0';++j)
printf("%c",c[i][j]);
}
}

Resources