Going through an allocated array - c

Let's say I wanna print the values of an array of type int.
int *num = malloc(5 * sizeof(int));
How do I do that? I would obviously like to stop after I've gone through all the values I put, which there are 5 of them.
Note that I'm not looking to do something like:
for (int i=0;i<5;i++)
I want to knwo what happens in the examples I gave.
while(*num) {
printf("%d", *num);
num++;
}
OR
while(num != NULL) {
printf("%d", *num);
num++;
}

Arrays in C don't carry their length. You have to pass the length along with the array.
The easiest way is with a variable:
int i;
for (i = 0; i < 5; ++i)
printf("%d ", num[i]);
The trick with the ending NUL is normally used only for strings, the end of the string is marked with a NUL char ('\0'). Naturally, if you are building and consuming the array yourself, nothing prevents you from making up a similar convention. You can, for instance, mark the end of the array with -1:
int *num = malloc(5 * sizeof(int));
num[4] = -1;
int *p;
for (p = num; *p != -1; ++p)
printf("%d ", *p);

When you are using the allocated array in a way you are showing
int *num = malloc(5 * sizeof(int));
Then the only way to know the end is to use the size used to allocate the array. Like
int i = 0;
while(i < 5) // 5 here is the size used wile allocating
{
printf("%d", num[i]);
i++;
}

You need to store the length of the array somewhere. Some other strategies are placing a terminator or sentinel value at the end of the array (though that value will not be valid for actual content):
int *num = calloc(6, sizeof(int));
num[5] = -1;
int i;
for (i = 0; num[i] != -1; i++) {
//...
}
Or embed the length of the array as its first element:
int *num = malloc(6 * sizeof(int));
int len = num[0];
int i;
for (i = 1; i < len; i++) {
// ...
}
(Note, Flexible arrays is a better way to express the second example)
Both the above show how to store the length in the array itself, and make use of an extra element for this purpose.

while(*num) {
printf("%d", *num);
num++;
}
Well, this continues until *num is zero. This works fine if no valid entry can contain a zero and you have set the last entry (or the first invalid entry) to zero. This is called a sentinel value.
while(num != NULL) {
printf("%d", *num);
num++;
}
This won't work. Incrementing num won't make make it NULL. Why would it?
If you have some particular number of values you want to output, you have two basic choices. You can pass the number of values you want to output to the output code and just count as you output that number of values. Or you can use a "sentinel" value to mark the end. If zero is not a valid value you would ever want to print, you can use zero as a sentinel. Don't forget to allocate space for the sentinel.

Related

Valgrind Invalid read of size 4 segfault

For an project assignment, I have this following variable from an prototype function which is not allocated.
int **suff;
This variable will receive a pointer to an array (int *) from a function which will generated an array of (int) from a FILO list (file).
(p is just a content structure, p->suff is a file)
int t = file_size(p->suff);
/* Prototype of file_tabint is
* int * file_tabint(file *p, int * psize)
*/
// Assign the generated array to the *suff)
*suff = file_tabint(p->suff, &t);
Now, when I want to print the array, valgrind raise a "invalid read of size 4"
for (int i = 0; i < t; i++) {
printf("%d -- ", *suff[i]);
}
My question is, what I did wrong in order to access to the int value of the array?
Note : I can't change the int **suff
The problem is *suff[i]. The way operator precedence works, that does suff[i] first and then dereferences whatever it finds there. You want to do it the other way round, so add brackets:
for (int i = 0; i < t; i++) {
printf("%d -- ", (*suff)[i]);
}

Understanding why it does not find duplicates in array

I wrote the following function in C:
int last(long arr[], int length) {
for (int i = 0; i < length-1; i++)
if (*(arr+i) == *(arr + length - 1))
return 1;
return 0;
}
it checks if the last value of the array was used more than once. In the main:
int *arr = malloc(length*sizeof(int));
for (int i = 0; i < length; i++)
scanf("%d", ++arr);
printf(last((long *) arr, length);
For some reason for the array [1,2,2,3] it returns that the last element was used multiple times and I'm not sure why. I think that is because of scanf("%d", ++arr); but I don't know how to fix it.
My goal is that it will return 1 for [1,3,2,3] and 0 for [1,2,2,3]. What could be the problem?
You should use scanf("%d", &arr[i]);. Using ++arr causes the array to be incremented before you pass it to last, and also reads into data beyond arr, which is undefined behavior.
Another one of the issues in this is the cast to long *.
You should use %ld in scanf and long *arr = malloc(length*sizeof(*arr));.
Also make sure to check for NULL. You never know when malloc is going to fail or someone's going to pass bad data.
Full example:
#include <stdio.h>
#include <stdlib.h>
int last(long arr[], int length) {
if(!arr) return -1;
for (int i = 0; i < length-1; i++)
{
if (arr[i] == arr[length-1])
return 1;
}
return 0;
}
int main(void)
{
long *arr = malloc(4*sizeof(*arr));
if(!arr) return 1;
for (int i = 0; i < 4; i++)
scanf("%ld", &arr[i]);
printf("%d\n", last(arr, 4));
}
Several problems in your code:
Look at this statement:
scanf("%d", ++arr);
^^^^^
In the last iteration of loop, the pointer arr will be pointing to one element past end of array arr (due to pre-increment) and it is is passed to scanf(). The scanf() will access the memory location pointed by the pointer which is an invalid memory because your program does not own it. This is undefined behavior. Note that a pointer may point to one element past the end of array, this is as per standard but dereferencing such pointer will lead to undefined behavior.
Once the main() function for loop finishes the arr pointer pointing to location past the end of memory allocated to arr and just after this you are passing arr to last() function. So, you are passing an invalid memory reference to last() function and then accessing that memory in last() function - one more undefined behavior in your program.
Probably you should take another pointer and point it to arr, so that arr keep pointing to allcoated memory reference returned by malloc().
Note that if you want to read the input the way you are doing then use the post-increment operator in scanf(), like this:
int *arr = malloc(length*sizeof(int));
if (arr == NULL)
exit(EXIT_FAILURE);
int *ptr = arr;
for (int i = 0; i < length; i++)
scanf("%d", ptr++);
but the more appropriate and readable way is - scanf("%d", &arr[i]).
Another big problem in your code is accessing the int values as long type.
The last() function parameter arr type is long and you are passing it int pointer typecasted to long *.
Note that the size of long and int may be different based on the platform. You cannot assume them to be of same size on all platforms.
Assume the case where int size is 4 bytes and long size is 8 bytes.
In this case, when accessing an int pointer using long type pointer then every object will be considered as 8 byte long and when you do arr+1 in last(), the pointer will be advance by 8 bytes and you will never get correct result.
Compiler must be throwing warning message on this statement:
printf(last((long *) arr, length);
because the printf() expects first argument as const char * and you are passing it int (return type of last()). You should give the first argument to printf() a string which contains appropriate format specifier('s).
Putting these altogether:
#include <stdio.h>
#include <stdlib.h>
int last(int arr[], int length) {
if (arr == NULL) {
return 1;
}
for (int i = 0; i < length - 1; i++) {
if (arr[i] == arr[length - 1]) {
return 1;
}
}
return 0;
}
int main(void) {
int length = 4;
int *arr = malloc (length * sizeof (*arr));
if (arr == NULL) {
exit(EXIT_FAILURE);
}
printf ("Enter %d numbers:\n", length);
for (int i = 0; i < length; i++) {
scanf ("%d", &arr[i]);
}
printf ("Duplicate found: %s\n", last (arr, length) == 1 ? "Yes" : "No");
return 0;
}

Accessing string that was passed as argument causes stack buffer overflow

I'm studying C at uni and am trying to access the string (the string representation of a binary-number) that was passed into a function to convert it into the integer-representation of that string.
Eg. "011" should return 3.
The string is the first 3 bits in a bitstream that's inputted in reverse.
char * temp_holder = (char *)malloc(sizeof(char) * 4);
int index_of_holder = 0;
for(int i = 2; i >= 0; i--){
printf("%c", buffer[i]);
temp_holder[index_of_holder] = buffer[i];
}
printf("\n");
int decimalValue = fromBinaryToInt(&temp_holder, 3);
printf("DECIMAL_VALUE: %d\n", decimalValue);
The fromBinaryToInt function is:
int fromBinaryToInt(char *string[], int length){
for(int i = 0; i < length; i++){
printf("%c", *string[i]);
}
int int_rep = strtol(*string, (char **)NULL, 2);
printf("REP: %d\n", int_rep);
return int_rep;
}
The subsequent error I get is:
==21==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffda9f47a08 at pc 0x000000500cdf bp 0x7ffda9f47980 sp 0x7ffda9f47978
- READ of size 8 at 0x7ffda9f47a08 thread T0
I thought this could be due to the null-terminating character so I played around with modifying the length variable (+/- 1) in the for-loop within fromBinaryToInt but that hasn't changed anything.
I also considered the for-loop only accessing the first element and nothing more - but my understanding is I've sent through the memory address and the length of the block so the for-loop should have access to the indexes.
Any help would be greatly appreciated,
Cheers :)
In this code:
int index_of_holder = 0;
for(int i = 2; i >= 0; i--){
printf("%c", buffer[i]);
temp_holder[index_of_holder] = buffer[i];
}
index_of_holder is never changed, so all the characters are put in temp_holder[0]. The rest of temp_holder remains uninitialized.
This:
int fromBinaryToInt(char *string[], int length)
declares string to be an array of pointers to char. It is indeed passed &temp_holder, which may be considered to be a pointer to the first element of an array of one pointer to char. However, a more normal usage is to declare a simple pointer to char
int fromBinaryToInt(char *string, int length)
and pass it temp_holder, as in fromBinaryToInt(temp_holder, 3).
As it is, where it is used here:
printf("%c", *string[i]);
This takes element i of the array. When i is 0 in the loop, that is fine, it takes the first element, which exists and is a pointer to char, and then deferences it with * and prints that. However, when i is 1, it attempts to take the second element of the array. That element does not exist, and the resulting behavior is undefined.
If the parameter were merely char *string, then this printf could be:
printf("%c", string[i]);
and, in calling strtol, you would simply pass string rather than *string:
int int_rep = strtol(string, (char **)NULL, 2);
Firstly, bug in below line, index_of_holder remains same all the time, please increment it.
temp_holder[index_of_holder] = buffer[i];
Secondly, in fromBinaryToInt() string is single pointer only so you can't do *string[i]); in the next printf statement.
Here is the working code
int fromBinaryToInt(char *string, int length){
for(int i = 0; i < length; i++){
printf("%c", string[i] ); /*since string is single pointer now you can do like before you did */
}
int int_rep = strtol(string, (char **)NULL, 2);
printf("REP: %d\n", int_rep);
return int_rep;
}
int main() {
char * temp_holder = (char *)malloc(sizeof(char) * 4);
char buffer[4] ="011";
int index_of_holder = 0;
for(int i = 2; i >= 0; i--){
printf("%c", buffer[i]);
temp_holder[index_of_holder] = buffer[i];
index_of_holder++;
}
printf("\n");
int decimalValue = fromBinaryToInt(temp_holder, 3);/* no need to pass address of temp_holder */
printf("DECIMAL_VALUE: %d\n", decimalValue);
return 0;
}

how to manually concat a char **args to char *args

so I'm trying to write a function that concats a char**args to a char*args
What I have so far is":
char *concat(char **array)
{
int size = 0;
int i=0;
int j=0;
int z=0;
while (array[i]!=NULL)
{
printf(" %s \n", array[i]);
size = size + sizeof(array[i])-sizeof(char); //get the total size, minus the
//size of the null pointer
printf("%d \n",size);
i++;
}
size = size+1; //add 1 to include 1 null termination at the end
char *newCommand = (char*) malloc(size);
i=0;
while(i<sizeof(newCommand))
{
j=0;
z=0;
while (array[j][z]!='\0')
{
newCommand[i] = array[j][z];
i++;
z++;
}
j++;
}
newCommand[sizeof(newCommand)-1]='\0';
return newCommand;
}
this doesn't seem to work. Anyone know what's wrong?
I'd do it like this (untested):
int size = 0;
int count = 0;
while (array[count]) {
size += strlen(array[i]);
count++;
}
char *newCommand = malloc(size + 1);
char *p = newCommand;
newCommand[0] = 0; // Null-terminate for the case where count == 0
for (int i = 0; i < count; i++) {
strcpy(p, array[i]);
p += strlen(array[i]);
}
First, your size calculation was wrong. You wanted the size of the strings, but sizeof(array[i]) gives you the size of a single element in your array which is a pointer and thus 4 (32-bit) or 8 (64-bit). You need to use strlen instead.
Next, your manual copying was also off. It's easier to do it with a moving pointer and strcpy (which is to be avoided normally but we've calculated the sizes with strlen already so it's OK here). The use of strcpy here also takes care of null termination.
Main issue is that you keep using sizeof() with a pointer argument, whereas I think you are trying to get the size of the corresponding array.
sizeof() can only give you information that's available at compile time, such as the sizes of raw types like char and int, and the sizes of arrays with a fixed length such as a char[10]. The sizes of the strings pointed to by a char* is only computable at run time, because it depends on the exact values passed to your function.
For sizeof(newCommand) you probably need size, and for sizeof(array[i]), you probably need strlen(array[i]).

How to cycle through array without indexes in C?

I need to allocate an N sized array and assign it values, how can I do it without int indexes?
Here is the code I have so far but it doesn't do what I need:
#include <stdlib.h>
#include <stdio.h>
int main() {
int *array;
int n;
printf("Size of array: ");
scanf("%d", &n);
array = (int*) malloc(n*sizeof(int));
if (array == NULL) printf("Memory Fail");
for(; *array; array++)
{
printf("Store:\n");
scanf("%d", &n);
*array = n;
}
for(; *array; array++)
{
printf("Print: %d\n",*array);
}
free(array);
return 0;
}
thanks
for(; *array; array++); you should remove ; at the end
Number of iterations for this loop is undefined and you are going to lose a pointer
You should do something like this:
int *cur;
for(cur = array; cur < array+n; ++cur)
{
*cur = ...;
}
When you allocate the memory, you have no way to determine, in the memory, where it ends (unless you decide a convention and set a value somewhere, but anyway you would use n) .
In your case you have to use n to limit the array coverage (otherwise it is only limited by your computer capacity, and until it reaches an area where it does not have access: program crash). For instance (be careful not to overwrite n !)
int v;
int x = n;
int *ptr = array;
while (x--)
{
printf("Store:\n");
scanf("%d", &v);
*ptr++ = v;
}
x = n;
ptr = array;
while (x--)
{
printf("Print: %d\n",*ptr++);
}
You are using *array as your condition, which means the for loop should continue unless *array evaluates to false, which is only if *array == 0. You are actually invoking undefined behavior because you allocate array with malloc and are trying to dereference the pointer when the underlying data could be anything, since the data block has been uninitialized.
You still need some type of counter to loop with, in this case you allocated n items.
/* I'm using a C99 construct by declaring variables in the for initializer */
for (int i = 0; i < n; ++i)
{
/* In your original code you re-assign your counter 'n', don't do that otherwise you lost the size of your array! */
int temp;
printf("Store: \n");
scanf("%d", &temp)
array[i] = temp;
}
/* This is your second loop which prints the items */
for (int i = 0; i < n; ++i)
{
printf("%d\n", array[i]);
}
Also, do not manipulate the array pointer without keeping a copy of it. You can only do free on the pointer returned by malloc.
Using indexes is the same as manipulating the pointer, your professor is being ridiculous otherwise.
If you have an array int *a; then:
a[0] is equal to *a
a[1] is equal to *(a+1)
a[2] is equal to *(a+2)
So you can go through the array by doing arithmetic on the pointer.

Resources