Array copying C programming - c

I have the code as:
mid = 3;
for(i=0;i<9;i++)
{
if(i == 9-mid)
num[i] = mid;
else
num[i] = 0;
printf("%d", num[i]);
}
which gives the result of "000000300".
What I try to do is to store "000000300" as an element of another array, i.e.
unsigned int array[0] = 000000300;
Any ideas of how to do this in C? Thanks~

If you want to copy the calculated string "000000300" you will need to allocate some memory and store it in a char * array:
// num is a char array containing "000000300".
char *stored = (char *)malloc(strlen(num) + 1);
if (stored == NULL) {
// This means that there is no memory available.
// Unlikely to happen on modern machines.
}
strcpy(stored, num);

Related

Bubble sort on string array not doing anything in C with strcmp

I am trying to sort a string array in C (char**), the string array is an array of all the names of files in a directory.
Here are all the parts of the code, I expect the code to sort the array alphabetically, but it doesn't work.
Here is the code to get the files from the directory
typedef struct
{
char** names;
int32_t count;
} Files;
void swap(char* a, char* b)
{
char* temp = a;
a = b;
b = temp;
}
void bubbleSort(char** strs, uint32_t length)
{
uint32_t i = 0, j = 0;
for (i = 0; i < length; i++)
{
for (j = 0; j < length - i - 1; j++)
{
if (strcmp(strs[j], strs[j + 1]) < 0)
{
swap(strs[j], strs[j + 1]);
}
}
}
}
Files* getScannableFilesInDir(char* dirname)
{
Files* files = (Files*)malloc(sizeof(Files));
files->names = NULL; //clearing garbage values
files->count = 0; //clearing garbage values
uint32_t dirnameLength = strlen(dirname);
uint32_t count = 0;
uint32_t countIterations = 0;
DIR* d = opendir(dirname);
struct dirent* dir = NULL;
while ((dir = readdir(d)) != NULL)
{
if (files->names == NULL) //first file, if START_AMOUNT is set to 0 we want to allocate enough space for the first path, once we know there is at least 1 file
{
files->names = (char**)malloc(1 * sizeof(char*));
count++; // there is enough space allocated for 1 string
}
if (strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..") && dir->d_type != DT_DIR)
{
++countIterations;
if (count < countIterations)
{
files->names = (char**)realloc(files->names, countIterations * sizeof(char*)); //adding 1 more space
}
files->names[countIterations - 1] = (char*)malloc(sizeof(char) * (strlen(dir->d_name) + dirnameLength) + 2); //-1 because we are incrementing at the start of the loop and not the end
//+ 2 at the end because a. the \0 at the end, b. 1 space for adding the slash
strcpy(files->names[countIterations - 1], dirname);
files->names[countIterations - 1][dirnameLength] = '/'; //changing the \0 to /
strcpy(files->names[countIterations - 1] + (dirnameLength + 1), dir->d_name); //adding the name after the /, now we have the full name
}
}
closedir(d);
files->count = countIterations;
bubbleSort(files->names, files->count);
return files;
}
I checked the rest of the code, I am not changing the value of the files->names at any other point of the code, just reading it.
You swap, and the way it is invoked from bubblesort, are both wrong. First let me educate you on a simple fundamental.
Arguments in C are pass-by-value. The only way to change caller-side data from an argument passed to a function as a parameter is to change the fundamentals of the parameter. You'll still pass by-value, you just need to make the "value" something you can use to access the caller's variable data. In C, you do that by declaring the formal parameter to be a pointer-to-type, pass the address of the thing you want changed caller-side, and within the function use the pointer via dereference to instigate the change.
void foo(int *a)
{
*a = 42; // stores 42 in whatever 'a' points to
}
Now, lets take a look at your swap:
void swap(char* a, char* b)
{
char* temp = a;
a = b;
b = temp;
}
Well, we have two pointers. But nowhere in this code do we actually dereference anything. All we're doing is swapping the values of the two pointers locally. The caller is completely unaffected by any of this.
What your swap is supposed to be doing is swapping two pointers. We have two char* caller side values we want to swap. The way to do that is exactly as we discussed before. Declare the formal parameters to be pointer-to-type (our type is char*, so our parameters are char**), then use dereferencing to modify the caller-side data.
void swap(char **ppA, char **ppB)
{
char *pp = *ppA;
*ppA = *ppB;
*ppB = pp;
}
That will swap two pointers, but only if the caller passes us the addresses of the two pointers. Note the vernacular here. I did not say "passes us the addresses in the two pointers" (e.g. their values), I said "passes us the addresses of the two pointers" (e.g. where the pointers themselves reside in memory). That means bubblesort needs changing too:
void bubbleSort(char** strs, uint32_t length)
{
uint32_t i = 0, j = 0;
for (i = 0; i < length; i++)
{
for (j = 0; j < length - i - 1; j++)
{
if (strcmp(strs[j], strs[j + 1]) < 0)
{
swap(strs+j, strs+j+1); // <=== HERE
}
}
}
}
This passes the addresses of the pointers at str[j] str[j+1] to the swap function.
That should solve your swap issue. Whether the algorithm is correct, or for that matter the rest of your code, I leave to you to digest.

Attempting to split and store arrays similar to strtok

For an assignment in class, we have been instructed to write a program which takes a string and a delimiter and then takes "words" and stores them in a new array of strings. i.e., the input ("my name is", " ") would return an array with elements "my" "name" "is".
Roughly, what I've attempted is to:
Use a separate helper called number_of_delimeters() to determine the size of the array of strings
Iterate through the initial array to find the number of elements in a given string which would be placed in the array
Allocate storage within my array for each string
Store the elements within the allocated memory
Include directives:
#include <stdlib.h>
#include <stdio.h>
This is the separate helper:
int number_of_delimiters (char* s, int d)
{
int numdelim = 0;
for (int i = 0; s[i] != '\0'; i++)
{
if (s[i] == d)
{
numdelim++;
}
}
return numdelim;
}
`This is the function itself:
char** split_at (char* s, char d)
{
int numdelim = number_of_delimiters(s, d);
int a = 0;
int b = 0;
char** final = (char**)malloc((numdelim+1) * sizeof(char*));
for (int i = 0; i <= numdelim; i++)
{
int sizeofj = 0;
while (s[a] != d)
{
sizeofj++;
a++;
}
final[i] = (char*)malloc(sizeofj);
a++;
int j = 0;
while (j < sizeofj)
{
final[i][j] = s[b];
j++;
b++;
}
b++;
final[i][j+1] = '\0';
}
return final;
}
To print:
void print_string_array(char* a[], unsigned int alen)
{
printf("{");
for (int i = 0; i < alen; i++)
{
if (i == alen - 1)
{
printf("%s", a[i]);
}
else
{
printf("%s ", a[i]);
}
}
printf("}");
}
int main(int argc, char *argv[])
{
print_string_array(split_at("Hi, my name is none.", ' '), 5);
return 0;
}
This currently returns {Hi, my name is none.}
After doing some research, I realized that the purpose of this function is either similar or identical to strtok. However, looking at the source code for this proved to be little help because it included concepts we have not yet used in class.
I know the question is vague, and the code rough to read, but what can you point to as immediately problematic with this approach to the problem?
The program has several problems.
while (s[a] != d) is wrong, there is no delimiter after the last word in the string.
final[i][j+1] = '\0'; is wrong, j+1 is one position too much.
The returned array is unusable, unless you know beforehand how many elements are there.
Just for explanation:
strtok will modify the array you pass in! After
char test[] = "a b c ";
for(char* t = test; strtok(t, " "); t = NULL);
test content will be:
{ 'a', 0, 'b', 0, 'c', 0, 0 }
You get subsequently these pointers to your test array: test + 0, test + 2, test + 4, NULL.
strtok remembers the pointer you pass to it internally (most likely, you saw a static variable in your source code...) so you can (and must) pass NULL the next time you call it (as long as you want to operate on the same source string).
You, in contrast, apparently want to copy the data. Fine, one can do so. But here we get a problem:
char** final = //...
return final;
void print_string_array(char* a[], unsigned int alen)
You just return the array, but you are losing length information!
How do you want to pass the length to your print function then?
char** tokens = split_at(...);
print_string_array(tokens, sizeof(tokens));
will fail, because sizeof(tokens) will always return the size of a pointer on your local system (most likely 8, possibly 4 on older hardware)!
My personal recommendation: create a null terminated array of c strings:
char** final = (char**)malloc((numdelim + 2) * sizeof(char*));
// ^ (!)
// ...
final[numdelim + 1] = NULL;
Then your print function could look like this:
void print_string_array(char* a[]) // no len parameter any more!
{
printf("{");
if(*a)
{
printf("%s", *a); // printing first element without space
for (++a; *a; ++a) // *a: checking, if current pointer is not NULL
{
printf(" %s", *a); // next elements with spaces
}
}
printf("}");
}
No problems with length any more. Actually, this is exactly the same principle C strings use themselves (the terminating null character, remember?).
Additionally, here is a problem in your own code:
while (j < sizeofj)
{
final[i][j] = s[b];
j++; // j will always point behind your string!
b++;
}
b++;
// thus, you need:
final[i][j] = '\0'; // no +1 !
For completeness (this was discovered by n.m. already, see the other answer): If there is no trailing delimiter in your source string,
while (s[a] != d)
will read beyond your input string (which is undefined behaviour and could result in your program crashing). You need to check for the terminating null character, too:
while(s[a] && s[a] != d)
Finally: how do you want to handle subsequent delimiters? Currently, you will insert empty strings into your array? Print out your strings as follows (with two delimiting symbols - I used * and + like birth and death...):
printf("*%s+", *a);
and you will see. Is this intended?
Edit 2: The variant with pointer arithmetic (only):
char** split_at (char* s, char d)
{
int numdelim = 0;
char* t = s; // need a copy
while(*t)
{
numdelim += *t == d;
++t;
}
char** final = (char**)malloc((numdelim + 2) * sizeof(char*));
char** f = final; // pointer to current position within final
t = s; // re-assign t, using s as start pointer for new strings
while(*t) // see above
{
if(*t == d) // delimiter found!
{
// can subtract pointers --
// as long as they point to the same array!!!
char* n = (char*)malloc(t - s + 1); // +1: terminating null
*f++ = n; // store in position pointer and increment it
while(s != t) // copy the string from start to current t
*n++ = *s++;
*n = 0; // terminate the new string
}
++t; // next character...
}
*f = NULL; // and finally terminate the string array
return final;
}
While I've now been shown a more elegant solution, I've found and rectified the issues in my code:
char** split_at (char* s, char d)
{
int numdelim = 0;
int x;
for (x = 0; s[x] != '\0'; x++)
{
if (s[x] == d)
{
numdelim++;
}
}
int a = 0;
int b = 0;
char** final = (char**)malloc((numdelim+1) * sizeof(char*));
for (int i = 0; i <= numdelim; i++)
{
int sizeofj = 0;
while ((s[a] != d) && (a < x))
{
sizeofj++;
a++;
}
final[i] = (char*)malloc(sizeofj);
a++;
int j = 0;
while (j < sizeofj)
{
final[i][j] = s[b];
j++;
b++;
}
final[i][j] = '\0';
b++;
}
return final;
}
I consolidated what I previously had as a helper function, and modified some points where I incorrectly incremented .

Using pointers in 2D arrays

I'm attempting to store arrays of integers that I read from a file (with a separate function) in a 2D array but I keep having issues with Segmentation fault. I know it's an issue with my pointers but I can't figure out exactly what I'm doing wrong.
Here is my function (takes an integer and compares it with an integer read from a file before storing it in my 2D array).
int **getStopTimes(int stop_id) {
int **result = malloc(sizeof(*result));
char const* const fileName = "stop_times_test.txt";
FILE* txt = fopen(fileName, "r");
char line[256];
int count = 0;
while (fgets(line, sizeof(line), txt) != NULL) {
int *formattedLine = getStopTimeData(line); //getStopTimeData returns a pointer to an array of ints, memory is allocated in the function
if (formattedLine[1] == stop_id) {
result[count] = formattedLine;
count++;
}
}
fclose(txt);
return result;
}
And my main:
int main(int argc, char *argv[]) {
int **niceRow = getStopTimes(21249);
for (int i=0; i<2; i++) { //Only looping 3 iterations for test purposes
printf("%d,%d,%d,%d\n",niceRow[i][0], niceRow[i][1], niceRow[i][2], niceRow[i][3]);
}
free(niceRow);
return 0;
}
getStopTimeData function thats being called (Pulls certain information from an array of chars and stores/returns them in an int array):
int *getStopTimeData(char line[]) {
int commas = 0;
int len = strlen(line);
int *stopTime = malloc(4 * sizeof(*stopTime)); //Block of memory for each integer
char trip_id[256]; //Temp array to build trip_id string
char stop_id[256]; //Temp array to build stop_id string
int arrival_time; //Temp array to build arrival_time string
int departure_time; //Temp array to build departure_time string
int counter;
for(int i = 0; i <len; i++) {
if(line[i] == ',') {
commas++;
counter = 0;
continue;
}
switch(commas) { //Build strings here and store them
case 0 :
trip_id[counter++] = line[i];
if(line[i+1] == ',') trip_id[counter] = '\0';
break;
case 1: //Convert to hours past midnight from 24hr time notation so it can be stored as int
if(line[i] == ':' && line[i+3] == ':') {
arrival_time = (line[i-2]-'0')*600 + (line[i-1]-'0')*60 + (line[i+1]-'0')*10 + (line[i+2]-'0');
}
break;
case 2 :
if(line[i] == ':' && line[i+3] == ':') {
departure_time = (line[i-2]-'0')*600 + (line[i-1]-'0')*60 + (line[i+1]-'0')*10 + (line[i+2]-'0');
}
break;
case 3 :
stop_id[counter++] = line[i];
if(line[i+1] == ',') stop_id[counter] = '\0';
break;
}
}
//Assign and convert to ints
stopTime[0] = atoi(trip_id);
stopTime[1] = atoi(stop_id);
stopTime[2] = arrival_time;
stopTime[3] = departure_time;
return stopTime;
}
This line:
int **result = malloc(sizeof(*result));
allocates just memory for one single pointer. (*result is of type int *, so it's a pointer to data -- the sizeof operator will tell you the size of a pointer to data ... e.g. 4 on a 32bit architecture)
What you want to do is not entirely clear to me without seeing the code for getStopTimeData() ... but you definitely need more memory. If this function indeed returns a pointer to some ints, and it handles allocation correctly, you probably want something along the lines of this:
int result_elements = 32;
int **result = malloc(sizeof(int *) * result_elements);
int count = 0;
[...]
if (formattedLine[1] == stop_id) {
if (count == result_elements)
{
result_elements *= 2;
result = realloc(result, result_elements);
}
result[count] = formattedLine;
count++;
}
Add proper error checking, malloc and realloc could return (void *)0 (aka null) on out of memory condition.
Also, the 32 for the initial allocation size is just a wild guess ... adapt it to your needs (so it doesn't waste a lot of memory, but will be enough for most use cases)
The upper answer is good,
just to give you an advice try to avoid using 2D array but use a simple array where you can store all your data, this ensures you to have coalescent memory.
After that, you can access your 1D array with an easy trick to see it like a 2D array
Consider that your 2D array has a line_size
To access it like a matrix or a 2d array you need to find out the corresponding index of your 1d array for given x,y values
index = x + y * line size;
In the opposite way:
you know the index, you want to find x and y corresponding to this index.
y = index / line_size;
x = index mod(line_size);
Of course, this "trick" can be used if you already know your line size

Tortoise and the Hare Pointers

I'm building a program that simulates the tortoise and the hare race. The way I'm doing it is I create a SIZE 70 array of '_' to simulate the racetrack. Then I create 2 pointers, char *harePtr and char *tortoisePtr, that point to elements in that array (each one starting at [0]) The elements in the array that the pointers point to I'm also trying to change to 'T' and 'H' to simulate their locations on the track.
From there I've algorithms developed to determine, based on a random number generator, the action each would take.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 70
enum winner {TORTOISE, HARE};
int raceRunner (char wRaceTrack[], void (*moveHare)(char *harePtr, int i), void (*moveTortoise)(char *tortoisePtr, int i));
void moveHare (char *harePtr, int i);
void moveTortoise ( char *tortoisePtr, int i);
int main() {
char racetrack [SIZE];
size_t i;
for (i = 0; i < SIZE; i++)
racetrack[i] = '_';
int winner;
winner = raceRunner(racetrack, moveHare, moveTortoise);
if (winner == 1)
printf("The hare won!");
if (winner == 2)
printf("The tortoise won!");
}
int raceRunner (char wRaceTrack[], void (*moveHare)(char *harePtr, int i), void (*moveTortoise)(char *tortoisePtr, int i)){
srand(time(NULL));
int move = 1 + rand() %10;
char *harePtr = wRaceTrack;
char *tortoisePtr = wRaceTrack;
size_t i;
for (i = 0; i < SIZE; i++)
printf("%c,", wRaceTrack[i]);
printf("\n\n");
moveHare(harePtr, move);
moveTortoise(tortoisePtr, move);
i = 0;
for (i = 0; i < SIZE; i++)
printf("%c,", wRaceTrack[i]);
printf("\n\n");
if (harePtr = tortoisePtr)
printf("OUCH! Damn tortoise bit the hare!\n\n");
if (harePtr[69])
return 1;
else if (tortoisePtr[69])
return 2;
else
raceRunner(wRaceTrack, moveHare, moveTortoise);
}
void moveHare ( char *harePtr, int i) {
if (i == 1) {
*harePtr = '_';
harePtr - 12;
*harePtr = 'H';
}
if (2 <= i <= 3) {
return;
}
if (4 <= i <= 5){
*harePtr = '_';
harePtr + 9;
*harePtr = 'H';
}
if (6 <= i <= 8) {
*harePtr = '_';
harePtr + 1;
*harePtr = 'H';
}
if (9 <= i <= 10) {
*harePtr = '_';
harePtr - 2;
*harePtr = 'H';
}
}
void moveTortoise ( char *tortoisePtr, int i) {
if (1 <= i <= 5) {
*tortoisePtr = '_';
tortoisePtr + 3;
*tortoisePtr = 'T';
}
if (6 <= i <= 7){
*tortoisePtr = '_';
tortoisePtr - 6;
*tortoisePtr = 'T';
}
if (8 <= i <= 1) {
*tortoisePtr = '_';
tortoisePtr + 1;
*tortoisePtr = 'T';
}
}
What I'm trying to do is to then first set their CURRENT position back to '_', then increment each pointer to move up or down along the array accordingly, depending on what the random generator comes up with, and change that value to 'T' or 'H'. First pointer that points to the last element in the array, [69], wins the race.
When I run the program however, it consistently produces the same result each time, without the hare marker making an appearance anywhere on the array. I'm positive this is because I've my pointers set up improperly, as I'm still trying to wrap my head around the whole concept. Is it not possible to set up pointers to the same array? Or am I accessing the array in the wrong way through incorrect use of * and &? I'm honestly lost when it comes to using those operands to properly integrate pointers with arrays, so any and all help is appreciated. Thank you!
In your code, There are many issues.
First,
harePtr - 12;
...
harePtr + 9;
...
tortoisePtr + 3;
etc. statements are essentially useless. They do not affect harePtr or tortoisePtr, as you might have thought. The result of the opration is lost, unless you collect the same in some variable.
You can make use of += or -= in this regard, to modify the LHS operand value.
Second
regarding the chaining of relational operators, like
if (1 <= i <= 5)
see this answer to find out why it surprises you. is logically wrong.
Third
In your code
if (harePtr = tortoisePtr) –
does not compare the values, instead assigns it. You need to use == for comparison.
Fourth
srand() is used to seed the random number generator. You need to call srand() only once from the main(). You may want to refer to the related answer.
First of all, subtracting a number from a pointer will return a new value, not modify the existing one. Use the -= and += operators to actually change something.
Secondly, randomly changing a pointer and then using it without first checking whether it is still inside the valid range means the operating system will bite your program long before either animal manages to bite the other.

How to find an element in an array of structs in C?

I have to write a function that finds a product with given code from the given array. If product is found, a pointer to the corresponding array element is returned.
My main problem is that the given code should first be truncated to seven characters and only after that compared with array elements.
Would greatly appreciate your help.
struct product *find_product(struct product_array *pa, const char *code)
{
char *temp;
int i = 0;
while (*code) {
temp[i] = (*code);
code++;
i++;
if (i == 7)
break;
}
temp[i] = '\0';
for (int j = 0; j < pa->count; j++)
if (pa->arr[j].code == temp[i])
return &(pa->arr[j]);
}
Why don't you just use strncmp in a loop?
struct product *find_product(struct product_array *pa, const char *code)
{
for (size_t i = 0; i < pa->count; ++i)
{
if (strncmp(pa->arr[i].code, code, 7) == 0)
return &pa->arr[i];
}
return 0;
}
temp is a pointer which is uninitialized and you are dereferencing it which will lead to undefined behavior.
temp = malloc(size); // Allocate some memory size = 8 in your case
One more mistake I see is
if (pa->arr[j].code == temp[i]) // i is already indexing `\0`
should be
strcmp(pa->arr[j].code,temp); // returns 0 if both the strings are same
This code can completely be avoided if you can use strncmp()
As pointed out by others, you are using temp uninitialized and you are always comparing characters with '\0'.
You don't need a temp variable:
int strncmp ( const char * str1, const char * str2, size_t num );
Compare characters of two strings
Compares up to num characters of the
C string str1 to those of the C string str2.
/* Don't use magic numbers like 7 in the body of function */
#define PRODUCT_CODE_LEN 7
struct product *find_product(struct product_array *pa, const char *code)
{
for (int i = 0; i < pa->count; i++) {
if (strncmp(pa->arr[i].code, code, PRODUCT_CODE_LEN) == 0)
return &(pa->arr[i]);
}
return NULL; /* Not found */
}
When you write char* temp; you are just declaring an uninitialized pointer
In your case since you say that the code is truncated to 7 you could create a buffer
on the stack with place for the code
char temp[8];
Writing
temp[i] = (*code);
code++;
i++;
Can be simplified to:
temp[i++] = *code++;
In your loop
for (int j = 0; j < pa->count; j++)
if (pa->arr[j].code == temp[i])
return &(pa->arr[j]);
You are comparing the address of code and the character value of temp[i] which incidentally could be 8 and outside the array.
Instead what you want to do is compare what code points to and what temp contains:
for (int j = 0; j < pa->count; j++)
if (!strncmp(pa->arr[j].code, temp, 7)
return &(pa->arr[j]);
You should also return NULL; if nothing was found, seems you do not return anything.
Probably a good thing is also to make sure your temp[] always contains 7 characters.

Resources