C: array of pointers pointing to the same value - c

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.

Related

reading strings to a char array and then getting the size of the strings

Im working on a project and I am stumped on this part.
I need to read words from stdin and place them in a char array and use an array of pointers to point to each word since they will be jagged. where numwords is an int read in representing the number of words.
char words[10000];
char *wordp[2000];
the problem is that I can only use the pointers to add the words.I can no longer use the [] to help.
*wordp = words; //set the first pointer to the beginning of the char array.
while (t < numwords){
scanf("%s", *(wordp + t)) //this is the part I dont know
wordp = words + charcounter; //charcounter is the num of chars in the prev word
t++;
}
for(int i = 0;words+i != '\n';i++){
charcounter++;
}
any help would be great I am so confused when it comes to pointers and arrays.
Your code will be much more manageable if you use an additional pointer
reference and increment that directly. In this way you won't have to do any
mental math. Additionally you need to be incrementing the reference before
reading in the next string, scanf doesn't move the pointer for you.
char buffer[10000];
char* words[200];
int number_of_words = 200;
int current_words_index = 0;
// This is what we are going to use to write to the buffer
char* current_buffer_prt = buffer;
// quick memset (as I don't remember if c does this for us)
for (int i = 0; i < 10000; i++)
buffer[i] = '\0';
while (current_words_index < number_of_words) {
// Store a pointer to the current word before doing anything to it
words[current_word_index] = current_buffer_ptr;
// Read the word into the buffer
scanf("%s", current_buffer_ptr);
// NOTE: The above line could also be written
// scanf("%s", words[current_word_index]);
// this is how we move the buffer to it's next empty position.
while (current_buffer_ptr != '\n')
current_buffer_ptr++;
// this ensures we don't overwrite the previous \n char
current_buffer_ptr++;
current_words_index += 1;
}
What you want to do is relatively straightforward. You've got an array of 10,000 chars for storage, and 2000 pointers. So to start with you'll want to assign the first pointer to the start of the array:
wordp[0] = &words[0];
In pointer form this is:
*(wordp + 0) = words + 0;
I've used the zeros to show how it relates to the arrays. In general, to set each pointer to each element:
*(wordp + i) == wordp[i]
words + i == &words[i]
So all you need to do is keep track of where you are in the pointer array, and as long as you've assigned correctly, the pointer array will keep track of the position in your char array.

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--;
}

Dynamic allocation of char** in 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.

Counting the number of elements in an array - C

I am trying to count the number of elements in an array using C. I tried out the following code. But it just returns 83 every time I run the program. What I mean by to count the number of elements is that I need to know the number of elements that we have entered and not the size of the array.
#include<stdio.h>
#include<stdlib.h>
main(){
int a[100], j = 0, i;
a[0] = '0';
a[1] = '1';
a[2] = '2';
a[3] = '3';
a[4] = '4';
a[5] = '5';
for(i=0; i<100; i++){
if(a[i] == '\0'){
}
else
j = j + 1;
}
printf("%d", j);
system("pause");
}
Arrays in C are a fixed size. They do not expand. Your array has two entries; writing to array[2], array[3], etc. invokes undefined behaviour. In other words, it's invalid code.
If you want to be able to insert an arbitrary number of elements, you will need to use dynamically-allocated memory, manually track how many elements you've inserted, and use realloc when you need to resize.
Since the OP amended his code, here is a more correct reply:
This code works 'by chance', since you didn't initialize the array previously.
It's just 'luck', that somewhere in there, the value 0 comes up.
The declaration of an array does NOT zero it.
Use:
memset(a, 0, 100);
For that. That way, the first 'not overwritten' byte will return '0'.
Reference: http://www.cplusplus.com/reference/clibrary/cstring/memset/
Alternatively, you have to set the 'delimited' manually by adding a[x] = 0;
Now, I know you specifically asked for a 'C' solution, but if you would like to consider using a C++-Compiler, I suggest looking at the stl of C++.
Here's a link to get you started: http://www.cplusplus.com/reference/stl/list/
It's initialized as:
list<char>List;
List.push_back(1);
List.push_back(2);
List.push_back('a');
int j = List.size(); //Returns '3'
do this instead:
main(){
int a[100] = {0};
int j = 0;
int i = 0;
// other stuff
Update based on new code:
In general, you will need a way to identify the end of your array in order to do a correct count. For strings the '\0' is used generally. For other data types you have to come up with your own value to check.
For your specific code example above:
You need to insert a \0 yourself into your array in the last position so that your count will work. (When you create a string like "hello", the '\0' gets automatically put in for you at the end of the string, but not if you create a string character by character).
Alternatively, check for the character '5' to find the end of your current array of characters.
Also, you should break out of the loop once you found the last character, otherwise you are going past the end of the array and will most likely crash (again, if you don't it's sheer luck). I.e., something like:
if(a[i] == '\0'){
break;
}
will work if you do:
a[6] = '\0';
before.
Since C doesn't check array bounds, it might appear that with your current code you seemingly get away with this, but it's sheer luck that the program doesn't crash and may change from run to run. In other words, this is undefined behavior.
Finally, you can of course also use strlen() if you are dealing with strings.

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