Language is C. I have an array of char* types (char *array[] / char** array) as function argument, and I want to print them all to separate lines like this:
while (*array) {
printf("%s\n", *array);
printf("after last print");
array++;
}
Now for some reason, with a certain input, it manages to print all the values, but immediately crashes after the last *array is printed. So after the last printf, it doesn't print the "after last print" anymore. Unfortunately, I'm on Windows 7 with netbeans C support, without gdb. There were some problems when I tried to install it to netbeans, but that's another story.
First of all, what could be causing this? Secondly, how could I without gdb try to debug this behaviour best? If one provides an answer that helps me to debug the problem and that way solve it, I will grant points from that alone too. Some background information related to the function argument that causes the crash: I used strtok to generate char** arr from char* string, where a space was used as the delimeter.
EDIT:
Some more information: If I inside that same function try to printf the last *array, it works fine, and the program continues normally. So this works:
printf("%s\n", array[4]);
The last index before NULL happens to be 4 in my test case. But then when that same thing is done inside the loop like seen before, it does manage to printf it, but crashes right away after, not printing the second line anymore.
If you don't explicitly initialize the last element of your string array to be null, it's going to be an uninitialized (i.e. wild pointer), so when you dereference it in printf it will crash.
Things to do:
Explicitly initialize the last element of your string array to be NULL so that the loop will actually know to stop at the end.
Instead of incrementing the pointer, increment the offset at which you dereference it with a loop counter variable.
This code works just fine for me and doesn't crash:
#include <stdio.h>
char *array[] = { "Hello", "World", "My", "Name", "Is", "Govind", "Parmar", NULL } ;
int main()
{
int i;
for(i = 0; *(array+i); i++)
{
printf("%s\n", *(array+i));
}
printf("after last print\n");
return 0;
}
I commented out code that comes after the use of this function. This resulted into fully successful run of the code. So apparently, the execution order of the code wasn't linear in a way that it would execute line after line. But after the last *array print it tried to execute code that was coming after the function. Now when I commented out that code, the function works like a charm.
Those who are interested, the code I commented out related to freeing memory from the *arrays.
Related
ı am trying to take text from a file and store it into 2d array every line will be different row and every word will be different column i was thinking to store lines first then seperate words but this doesn't work quite right in the while loop its prints correctly but outside of the loop array only has last line any help?
char **arr;
arr=malloc(sizeof(int)*line);
int a ;
for(a=0;a<line;a++){
arr[a]=(char*)malloc(sizeof(int)*maxword);
}
int i=0;
rewind(fp);
while(fgets(command,count, fp)!=NULL) {
arr[i]=command;
printf("%s",arr[i]);
i++;
}
The problem here is the way you are trying to copy the input command string into your arr array of strings. The line you have:
arr[i]=command;
is assigning to the string pointer at arr[i] the value of the string pointer command, which is the start of the command string. When you then print this out inside the loop, it shows correctly, because you've just read in that string.
However, in each iteration of the loop, you are giving the 'next' arr[i] the same pointer (the start of the command string). So, when you then print out each arr[i] string when the looping has finished, each will point to the same string, which will have whatever value the last-read command was.
Instead, inside your loop, you should replace the above line with this:
strcpy(arr[i], command);
This will copy the contents of command to the string indexed by arr[i].
Try it and see! And feel free to ask for further clarification and/or explanation.
EDIT: Also, as pointed out by user3121023 in the comments, you need to release the memory you have allocated for arr but only when you are completey done using it! You can do this using calls to the free function, corresponding to each of your malloc calls:
for(a=0;a<line;a++){
free(arr[a]); // First, run through a loop freeing each row ...
}
free(arr); // ... and only then free the "array of row pointers!"
EDIT2: Oh, and I forgot! As pointed out by Bodo (thanks for the reminder) you must never assume that a pointer has any given size. You have:
arr=malloc(sizeof(int)*line);
which assumes that a pointer-to-char has the size of an int. It may do on some platforms, but don't ever rely on this. Use this instead:
arr=malloc(sizeof(char*)*line);
I need a function that receives an array of pointers to strings and it's size.
Then it should seek for those strings which occur in the array more than once - then I have to delete them and realloc the array.
Function should return new size of the array.
I'm trying to solve this, and not sure what`s wrong.
I want to move each string, that I want to delete, to the end of the array and then delete it, but not sure when the "realloc" should happen.
#include<stdio.h>
#include<stdlib.h>
int DeleteString(char** tab, int n){
char* check=malloc(sizeof(char)*100);
int deleted;
int i,j,g,h;
for(i=0;i<n;i++){
strcpy(check, tab[i]);
for(j=0;j<n;j++){
if(strcmp(check, tab[j]) == 0){
deleted++;
char* temp = malloc(sizeof(char)*100);
for(h=j;h<n-1;h++){
strcpy(temp, tab[h+1]);
strcpy(tab[h+1], check);
strcpy(tab[h], temp);
}
}
if(deleted>0){
realloc(tab, sizeof(char*)*(n-deleted));
}
}
}
return n-deleted;
}
For now there is "Segmentation fault" error
Oops, your code contains numerous problems, because you failed to observe some major rules of C language:
every non static variable shall be initialized (what about deleted?)
any object that was malloced shall be freed (what about check and temp.)
never change something that was passed as an input parameter to a function, or do not expect the change to be visible on return (tab has to be considered here because of next line).
allways assign the result of realloc because it can be different from the input pointer (realloc(tab, sizeof(char*)*(n-deleted));).
The first one is probably the cause of the segmentation fault because as deleted is unitialized its value is just undeterminated. But all problems should be fixed.
The reason for the SEGMENTATION FAULT is tab[0] store the address of the variable which stores the actual string.
Here tab[i] is in for loop,hence when it tries to fetch tab[1] itself memory error.
for(i=0;i<n;i++){
strcpy(check, tab[i]);...}
FOR EXAMPLE:
char *foo = "something";
char **ptr2;
ptr2 = &foo;
printf("check = %s", *ptr2);
for(int i=0;i<9;i++){
printf(" check = %c", ptr2[i]);
}
Output
check = something check = 4check = �check = pcheck =
Actally it is an error.
First of all, don't forget to initialise variables like deleted, as it has been said in other answers.
Next, you are supposed to free memory (as you are deleting items) and you only call malloc(3)). That seems a little counter-common sense, doesn't it?
Third, you make a lot of string copying in the loops, while it should be more efficient just to move pointers up, so you don't need to realloc the string elements and copy the cell contents (by the way, are you sure those strings will be feed to the function as malloc()d strings? I will assume that as you do)
Fourth, consider sorting the array first, so all the similar strings will be adjacent in the array. This has a cost O(n*log(n)) that, appended to the delete next string if equal (with cost O(n)) makes total cost O(n*(log(n)+1)) or O(n*log(n)) and not O(n^2) which is your actual cost)
Once sorted, only the strings deleted should be free(3)d, the pointers moved back to the start of the array as holes get appearing, and finally(when all is finished) you can just realloc(3) the array of pointers (only once, not at every pass through the loop)
Remaking the example is out of the scope of this answer, as it looks actually some school exercise. Sorry for that. I'm sure that the other hints will help you to retry the exercise with more success.
And think: thinking before writing is how one succeeds in this job.
Good evening everybody, I am learning C++ on Dev C++ 5.9.2, I am really novice at it. I intentionnally make my programs crash to get a better understanding of bugs. I've just learned that we can pass a char string to a function by initializing a pointer with the address of the array and that was the only way to do it. Therefore we should always pass to the function the size of that string to handle it properly. It also means that any procedure can run with a wrong size passed in the argument line hence I supposed we could read farther than the allocated memory assigned to the string.
But how far can we do it? I've tested several integers and apparently it works fine below 300 bytes but it doesn't for above 1000 (the program displays characters but end up to crash). So my questions are :
How far can we read or write on the string out of its memory range?
Is it called an overflow?
How does the program detect that the procedure is doing something unlegit?
Is it, the console or the code behind 'cout', that conditions the shutting down of the program?
What is the condition for the program to stop?
Does the limit depend on the console or the OS?
I hope my questions don't sound too trivial. Thank you for any answer. Good day.
#include <iostream>
using namespace std;
void change(char str[])
{
str[0] = 'C';
}
void display(char str[], int lim)
{
for(int i = 0; i < lim; i++) cout << str[i];
}
int main ()
{
char mystr[] = "Hello.";
change(mystr);
display(mystr, 300);
system("PAUSE");
return 0;
}
The behavior when you read past the end of an array is undefined. The compiler is free to implement the read operation in whatever way works correctly when you don't read beyond the end of the buffer, and then if you do read too far - well, whatever happens is what happens.
So there are no definite answers to most of your questions. The program could crash as soon as you read 1 byte too far, or you could get random data as you read several megabytes and never crash. If you crash, it could be for any number of reasons - though it likely will have something to do with how memory is managed by the OS.
As an aside, the normal way to let a function know where a string ends is to end it with a null character rather than passing a separate length value.
This question already has answers here:
Returning an array using C
(8 answers)
Closed 8 years ago.
I have an idea on dangling pointer. I know that the following program will produce a dangling pointer.But I couldnt understand the output of the program
char *getString()
{
char str[] = "Stack Overflow ";
return str;
}
int main()
{
char *s=getString();
printf("%c\n",s[1]);
printf("%s",s); // Statement -1
printf("%s\n",s); // Statement -2
return 0;
}
The output of the following program is
t
if only Statement-1 is there then output is some grabage values
if only Statement-2 is there then output is new line
Your code shows undefined behaviour, as you're returning the address of a local variable.
There is no existence of str once the getString() function has finished execution and returned.
As for the question,
if only Statement-1 is there then output is some grabage values if only Statement-2 is there then output is new line
No explanations. Once your program exhibits undefined behaviour, the output cannot be predicted, that's all. [who knows, it might print your cell phone number, too, or a daemon may fly out of my nose]
For simple logical part, adding a \n in printf() will cause the output buffer to be flushed to the output immediately. [Hint: stdout is line buffered.]
Solution:
You can do your job either of the two ways stated below
Take a pointer, allocate memory dynamically inside getString() and return the pointer. (I'd recommend this). Also, free() it later in main() once you're done.
make the char str[] static so that the scope is not limited to the lifetime of the function. (not so good, but still will do the job)
your str in getString is a local variable, which is allocate on stack, and when the function returns, it doesn't exist anymore.
I suggest you rewrite getString() like this
char *getString()
{
char str[] = "Stack Overflow ";
char *tmp = (char*)malloc(sizeof(char)*strlen(str));
memcpy(tmp, str, strlen(str));
return tmp;
}
and you need to add
free(s);
before return 0;
In my case, pointer tmp points to a block memory on heap, which will exist till your program ends
you need to know more about stack and heap
Besides, there is still another way, use static variable instead
char *getString()
{
static char str[] = "Stack Overflow ";
return str;
}
PS: You get the correct answer for the following statement printf("%c\n",s[1]); is just a coincidence. Opera System didn't have time to do some clean work when you return from function. But it will
Array is returned as a pointer yet the array itself is the garbage after return from function. Just use static modifier.
What's concerning s[1] is OK. The point is, it's the first printf after getting the dangling pointer. So, the stack at this point is still (probably) intact. You should recall that stack is used for function calls and local variables only (in DOS it could be used by system interrupts, but now it's not the case). So, before the first printf (when s[1] is calc'ed), s[] is OK, but after - it's not (printf' code had messed it up). I hope, now it's clear.
I'm creating a program to open .txt files in a given directory, I have an array with all the absolute paths of the files inside the directory in question and I'm creating a function to extract and return the name of the files, the function is written as follows:
char *name(char *string) {
int i = strlen(string);
char *aux;
while(string[i-1] != '/'){
i--;
}
strcpy(aux, &string[i]);
return aux;
}
The above function is giving a Segmentation Fault error, but if I add the following line " int j = 0;" before the declaration of aux the mistake is gone, the new and working code is
char *name(char *string) {
int i = strlen(string);
int j = 0;
char *aux;
while(string[i-1] != '/'){
i--;
}
strcpy(aux, &string[i]);
return aux;
}
input: C:\test\a.txt
output: a.txt
Why the addition of "int j = 0;" solves the problem? I'm stuck with that and can't continue because I don't know if this inconsistency might lead to bigger problems later, I'm thinking about writing my own function to copy the strings, but before that I really want to understand that error.
You never allocate aux. aux needs to point to a valid memory location before you attempt to copy anything to it.
Instead of char *aux, you need something like char *aux = malloc(i+1);. Note that i+1 is overkill because in your case aux will always be at least 3 characters shorter than string (it won't contain C:\), but you probably don't care for such small strings. Remember to free() the pointer once you're done with it.
Also, the reason you found it works by switching orders of declarations and/or adding a declaration is probably that you got lucky and somehow the location to which aux points to is valid (if you do just char *aux;, aux points to a random location). This is pure luck however, and is still invalid code even though it seems to work.
In the future, you might want to use a tool like Valgrind to help you diagnose memory problems. You should also read a tutorial on basic memory management and pointers in C.
Since it sounds like you are only interested in utilizing the filename portion of the string as parameter, another option is to use the portion of the string you already have.
Try: aux = &string[i]; instead of the strcpy.
This gives you a pointer into the part of the string you are interested in (namely, the last part after the final '/').
Secondly, ensure you have a '/' in all of your input strings, otherwise bad things will happen (i.e. your loop will go past the beginning of the string, likely encountering a segmentation fault at some point). It would be best to put a condition on the loop so that it doesn't continue beyond i = 1.
You don't allocate any memory to aux. You are trying to write to memory through an uninitialized pointer.