Why is this reverse string function giving a seg fault? - c

I want to make a reverse string function and I have done it like this:
void reverse_str(char s[]) {
int i, j;
char ch;
for(i = 0, j = strlen(s) - 1; i < j; i++, j--) {
ch = s[i];
s[i] = s[j];
s[j] = ch;
}
return ;
}
But for some reason when I change i < j to i != j I get a segmentation fault. This also happens when i and j are pointers. Why?

It's almost certainly because i and j pass each other (whether they're indexes or pointers is irrelevant here). For example, any string with an even number of characters will have this problem.
Consider the following sequence for the string drum:
0123 <- indexes
----
s = "drum", i = 0, j = 3, swap d and m.
s = "mrud", i = 1, j = 2, swap r and u.
s = "murd", i = 2, j = 1, swap u and r, oops, we've passed each other.
s = "mrud", i = 3, j = 0, swap m and d.
s = "drum", i = 4, j = -1, swap who knows what, undefined behaviour.
Note that for a string with an odd length, you won't have this problem since i eventually equals j (at the middle character).
The i < j check also fixes this problem since it detects both equality of pointers and the pointers passing each other.

If j starts as odd (when s has an even number of characters), then i and j will never be equal - so the loop will continue outside the bounds of the array s.
For example, if i = 0 and j = 1 when first evaluated, then the next loop will have i = 1 and j = 0 (note still not equal) and the third loop will have i = 2 and j = -1, hence the error.

How are you calling the function? In other words, are you sure that the character array you're passing in is writable?
If the memory is okay, it probably crashes when you use != since there's no guarantee that that happens when you expect it to.

if strlen(s) - 1 is odd then your condition i!=j will always be true.

Related

Why is this C program detecting two '\0' characters in a string when an unconnected line of code gets uncommented?

I am currently learning C and I wrote this program to check if the '\0' char is really at the end of strings, as pointed in "K and R".
I had the strangest result though.
If I comment the "int lista[] = {0, 1, 2, 3, 4};" statement out of the program (this is a statement that has nothing to do with the other statements of this program, it was part of another test I was going to make).
the output of the program comes out how expected, detecting one '\0' char ending the string.
However, if I leave the statement uncommented, the program output detects two '\0' chars at the end of the string.
Why does this happens?
This is the program with the statement uncommented:
#include <stdio.h>
int main(void)
{
int lista[] = {0, 1, 2, 3, 4};
char string[] = "linhas";
for (int i = 0; i <= sizeof(string); i++)
{
if (string[i] != '\0')
{
printf("%c\n", string[i]);
}
else
{
printf("this dawmn null char\n");
}
}
}
This outputs:
l
i
n
h
a
s
this dawmn null char
this dawmn null char
this is the program with the line commented out:
#include <stdio.h>
int main(void)
{
/*int lista[] = {0, 1, 2, 3, 4};*/
char string[] = "linhas";
for (int i = 0; i <= sizeof(string); i++)
{
if (string[i] != '\0')
{
printf("%c\n", string[i]);
}
else
{
printf("this dawmn null char\n");
}
}
}
it outputs:
l
i
n
h
a
s
this dawmn null char
Your loop
for (int i = 0; i <= sizeof(string); i++)
is ever-so-slightly wrong. It should be
for (int i = 0; i < sizeof(string); i++)
By using <=, you make one too many trips through the loop, and you access memory outside of the string array. It looks like, with the lista array in place, the extra byte you mistakenly access (outside of the string array) happens to be a 0, so you get an extra, second printout of your "this dawmn null char" message.
But then, when you comment out the lista array, it must be the case that the extra byte you mistakenly access isn't 0, so it gets printed as itself, instead. It might be an invisible control character, which is why you don't see anything. I suggest changing your code to
if (string[i] != '\0')
printf("string contains %d\n", string[i]);
else printf("this damn null char\n");
to see this more clearly.
The important lesson here is that if you have a loop that's supposed to run N times, there are two ways to write it. In C, the vast majority of the time, you want to write it as
for(i = 0; i < N; i++)
That's a "0-based" loop, that runs from 0 to N-1, for a total of N trips. Once in a while, you want a 1-based loop:
for(i = 1; i <= N; i++)
This runs from 1 to N, again for a total of N trips. But if you write
for(i = 0; i <= N; i++) /* usually WRONG */
your loop runs from 0 to N, for a total of N+1 trips.
Do not confuse strlen(string) which in your case should be 6 and sizeof(string) which is the size of the array including the '\0' byte ! ;-)
In the case of a string declared as an array with "automatic size" the difference is only one but if you had char string[256], sizeof(string) would not be the same has strlen(string) + 1.
With char *string, sizeof(string) would likely be 8 or 4.
#SteveSummit has explained everything in detail. Here is a short answer.
Accessing the element lista[sizeof(lista)] is undefined behavior, so it's "pointless" to discuss what value it should have. I quoted pointless, because it can be a good thing to understand how undefined behavior manifests itself for debugging purposes. But if this code were to go into production, you should NEVER access lista[sizeof(lista)]. It's always out of bound and always a bug.

Understanding two dimensional arrays

Here's the code and wondering if you can help me understand it.
/* Two dimensional array */
#include <stdio.h>
void main() {
int i, j, sum[2], mean[2];
int mark[3][2] = { { 34, 56}, { 48, 65}, { 53, 59} };
for (j = 0; j < 2; j++)
sum[j] = 0;
for (i = 0; i < 3; i++) {
for (j = 0; j < 2; j++) {
sum[j] = sum[j] + mark[i][j];
}
}
for (j = 0; j < 2; j++)
mean[j] = sum[j] / 3;
printf("Average mark in Mathematics is %d\n", mean[0]);
printf("Average mark in Chemistry is %d\n", mean[1]);
}
My understanding of it so far....
Define data types i, j, sum[2], mean[2] as integers.
Initialising the array....mark is data type int, the array should have 3 rows and 2 columns.
First for loop, j initialised at 0, condition: j has to be less than 2, update: add one onto the value of j. Sum of j = 0.
Also for 2nd loop, i initialised at 0, condition: i has to be less than 3, update: add one onto the value of i.
Similar for the next line that uses the for loop and value j.
I'm a bit confused about the syntax:
sum[j] = sum[j] + mark[i] [j]; does this mean, work out the sum of j and add it to the marks contained in the array displayed as [i] and [j].
After this is completed then similar j loop though not sure how this interacts with the previous loops.
Mean calculated and values printed to the screen.
When I've looked at the worked example...
sum[0] = 0 and sum[1] = 0, I don't really understand why sum[1] is also 0.
Firstly, i=0 and j=0,
sum[0] = sum[0] + mark [0,0]
then j=1
sum[1]=sum[1]+mark[0,1]
then
i=1, j=0
sum[0] = sum[0] + mark [1,0]
then
sum[1] = sum[1]+mark[1,1]
then i = 2, j=0
sum [0] = sum[0]+ mark[2,0]
then
sum[1] = sum[1]+ mark[2,1]
What is confusing me a bit is how the loops are interacting with each other and the values of i and j throughout.
I know that the 2d array would be in a table (that I can't seem to format here).
Would appreciate if anyone could shed some light on this.
sum[j] = sum[j] + mark[i][j]; can be simplified as sum[j] += mark[i][j];. It adds the contents of the cell at row i, column j of the 2D matrix mark to the jth element of array sum.
Accessing an element of a 2D array is written mark[i][j] in C, not mark[i, j].
Note that mark[i, j] is not a syntax error: the expression i, j is a comma expression, evaluating i, then discarding it and evaluating j. It is therefore the same as mark[j] which is not a matrix cell but a reference to the jth row of the 2D matrix.
Nope, an array is in fact a pointer (aka an address). When you define int sum[2], sum is the address of the first element of your array of two integer.
So sum is an int* or int[] (same).
Mark is an 2d array. Mark is in fact an array of array. So Mark contain addresses, and thoses addresses are the beggining of some arrays.
(In fact it can be different in the memory, but the compiler do the work).
Mark is a int**, or an address of address of int.
When you do:
for (i = 0; i < 3; i++) {
for (j = 0; j < 2; j++) {
sum[j] = sum[j] + mark[i][j];
}
}
It's like if you were saying
for each line i in the array, I want to do:
for each value j in the line, I want to do:
...;
Like this, you work on every "line" (or column, visualize the way you want), and for every "line", you work on every value.

Store N^(n*n) matrix in C

Every time I find a pretty good solution to a problem at my work, always start coding in C to ruin that feeling... :D
So here I am, noobing with some easy C code and wonder why it's not working o.O
I want to represent a matrix with a 2D array (array of arrays) and fill it from a text file. The code is bad, the code ugly... I'm interested any tip/trick what I can fetch from you, Mr. senior :)
What wrong with my logic? What is under the hood? Am I using the [] operator not as expected? Am I just simply don't know how to iterate through a 2D array? I complie this source on windows with cl, using declaration in for() and god know what else what is not strictly C-like.
Input is a text file containing the size of the matrix and the elements of it separated by white space(s). The syntax of this: file := {n, A | n :-N, A := N^(n*n)}
For example:
3
1 3 2
4 5 2
7 0 1
So here it is... take cover!
#include <stdio.h>
int main(int argc, char **argv) {
Opening the file, no error checking for the minimal code :)
FILE *fp = fopen("mat_mul.test", "r");
Now, allocating the arrays based on the first integer in the file... Is this correct? Are there any better approach for allocating array of arrays?
int n = fgetc(fp) - '0';
int **A = (int**) malloc(sizeof(int*) * n);
for (int i = 0; i < n; i++)
A[i] = (int*) malloc(sizeof(int) * n);
Aaand, here is the magic, the spell what has turned against its master :D
char act;
int i = 0, j = 0;
while (EOF != (act = fgetc(fp)))
if ('0' <= act && '9' >= act)
A[j == n - 1 ? i++ : i][j == n - 1 ? j = 0 : j++] = act - '0';
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
printf("A[%i][%i]=%i\n", i, j, A[i][j]);
}
}
Cleaning without exhaustive!
if (fclose(fp)) {
return 0;
}
You invoke undefined behaviour when you try to do the row and column assignment and advancement at once here:
A[j == n - 1 ? i++ : i][j == n - 1 ? j = 0 : j++] = act - '0';
You assign to j in the second pair of brackets and also access its value in the first pair. (My compiler warns me that the "operation on 'j' may be undefined".) There is a sequence point between the parts of the ternary operatoy, but not between the two index operators [].
Besides the undefined behaviour, the expression is also needlessly complicated in my opinion. Separate assignmemt and advancing the row and columns counter:
if ('0' <= act && '9' >= act) {
A[i][j] = act - '0';
j++;
if (j == n) {
j = 0;
i++;
if (i == n) break; // end outer while
}
}
You should also include <stdlib.h> for the declaration of malloc. (That's also something my compiler tells me when warnings are enabled.)

How to get the arithmetic squence of a array(C)

so my requirements are
REQUIRES: n >= 1. Elements a[0] ... a[n-1] exist.
PROMISES
The return value is 1 if n == 1.
If n > 1, the return value is 1 if a[0] ... a[n-1] form
an arithmetic sequence.
PROMISES
Otherwise, the return value is 0.
my function so far is
int is_arith_seq(const int *a, int n)
{
assert(n >= 1);
if (n == 1)
return 1;
int i;
int initaldif = a[1]-a[0];
int currentdif,result;
for (i=0;i<n;i++)
{
currentdif = a[i+1]-a[i];
if(initaldif!=currentdif)
return 0;
}
return 1;
}
My code does not work,as I am completely stuck now, what can I do to correct it.
If array has n elements your for loop will cause a segmentation fault. It goes all the way to n-1 but you are accessing a[i+1]. a[n] is out of bounds. Modify like this :
for (i = 0; i < n - 1; i++)
{
currentdif = a[i+1]-a[i];
if (initaldif != currentdif)
return 0;
}
Problem is here
currentdif = a[i+1]-a[i];
What do you think will happen to this code during n-1 th iteration?
i = n-1 + 1 = n
Therefore the function either returns 1 if n=1 or returns 0 due to the error!
Off-by-one errors are one of the most common programming mistakes. A good way to quickly track many of these down is to look at the very first and last iterations of your loops.
Your intent is that your loop computes the differences
a[1]-a[0] a[2]-a[1] ... a[n-1]-a[n-2]
The first iteration has i=0 and computes a[1]-a[0], and the last iteration has i=n-1 and computes a[n]-a[n-1]. Whoops, that's wrong! Need to adjust the loop.
Your arithmetic sequence test should set the initialdif as you have done, but then predict what the next element is throughout the sequence. If any term fails, the string of numbers is not an arithmetic sequence:
int initaldif = a[1]-a[0];
for (i = 2; i < n; i++)
if (a[i] != a[i-1] + initaldif)
return 0;
return 1;

Counting sort algorithm doesn't work in C

My task is to make a counting sort algorithm in C. The compiler doesn't make any reasons to not make a program, but it doesn't work. While debugging debugger shows the second for contain as an error so I am asking where is an error because I can't see it.
const int k = 77;
const int n = 1000;
int T[n];
int Tp[n];
int TPom[k];
int i;
for(i = 0 ; i < k ; i++)
TPom[i] = 0;
for(i = 0 ; i < k ; i++)
TPom[T[i]]= TPom[T[i]]+1;
for(i = 1 ; i < k ; ++i)
TPom[i] += TPom[i-1];
for(i = n-1 ; i >= 0 ; --i)
Tp[--TPom[T[i]]] = T[i];
There are a few problems, so I'll give you some hints:
The second loop is wrong. Hint: how many elements does T contain?
The third loop is not wrong, but is unnecessary. I personally find it easier to think about the algorithm without this loop (you might disagree).
The final loop is wrong. You want to iterate over the values 0 through k-1, populating Tp. The loop shouldn't even reference T.

Resources